Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Loading...
Loading
Contract Name:
EnterpriseModule
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.18;
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "./RelayerManager.sol";
import "./SecurityManager.sol";
import "./EnterpriseTransactionManager.sol";
import "./SignatureModule.sol";
import "hardhat/console.sol";
//TODO: add notice
/**
* @title EnterpriseModule
* @notice .
*/
contract EnterpriseModule is SignatureModule, BaseModule, RelayerManager, SecurityManager, EnterpriseTransactionManager {
bytes32 constant public NAME = "EnterpriseModule";
constructor (
IModuleRegistry _registry,
IGuardianStorage _guardianStorage,
ITransferStorage _userWhitelist,
IAuthoriser _authoriser,
uint256 _securityPeriod,
uint256 _securityWindow,
uint256 _recoveryPeriod,
uint256 _lockPeriod
)
BaseModule(_registry, _guardianStorage, _userWhitelist, _authoriser, NAME)
SecurityManager(_recoveryPeriod, _securityPeriod, _securityWindow, _lockPeriod)
EnterpriseTransactionManager(_securityPeriod)
RelayerManager("RelayerKnobs")
{
}
/**
* @inheritdoc IModule
*/
function init(address _wallet) external override onlyWallet(_wallet) {
enableDefaultStaticCalls(_wallet);
}
/**
* @inheritdoc IModule
*/
function addModule(address _wallet, address _module) external override onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
require(registry.isRegisteredModule(_module), "AM: module is not registered");
IWallet(_wallet).authoriseModule(_module, true);
}
/**
* @inheritdoc RelayerManager
*/
function getRequiredSignatures(address _wallet, bytes calldata _data) public view override returns (uint256, OwnerSignature) {
bytes4 methodId = Utils.functionPrefix(_data);
if (methodId ==EnterpriseTransactionManager.multiCall.selector ||
methodId ==EnterpriseTransactionManager.addToWhitelist.selector ||
methodId ==EnterpriseTransactionManager.removeFromWhitelist.selector ||
// methodId ==EnterpriseTransactionManager.enableERC1155TokenReceiver.selector ||
methodId ==EnterpriseTransactionManager.clearSession.selector )
{
if(msg.sender == _wallet) {
return (0, OwnerSignature.Anyone);
}
// owner
return (1, OwnerSignature.Required);
}
if (methodId ==EnterpriseTransactionManager.multiCallWithSession.selector) {
if(msg.sender == _wallet) {
return (0, OwnerSignature.Session);
}
return (1, OwnerSignature.Session);
}
if (methodId == SecurityManager.executeRecovery.selector) {
// majority of guardians
uint numberOfSignaturesRequired = _majorityOfGuardians(_wallet);
require(numberOfSignaturesRequired > 0, "AM: no guardians set on wallet");
return (numberOfSignaturesRequired, OwnerSignature.Disallowed);
}
if (methodId == SecurityManager.cancelRecovery.selector) {
// majority of (owner + guardians)
uint numberOfSignaturesRequired = Utils.ceil(recoveryConfigs[_wallet].guardianCount + 1, 2);
if(msg.sender == _wallet) {
return (numberOfSignaturesRequired - 1, OwnerSignature.Disallowed);
}
return (numberOfSignaturesRequired, OwnerSignature.Optional);
}
if (
methodId == SecurityManager.addGuardian.selector ||
methodId == SecurityManager.revokeGuardian.selector ||
methodId == SecurityManager.cancelGuardianAddition.selector ||
methodId == SecurityManager.cancelGuardianRevokation.selector ||
methodId == SecurityManager.transferOwnership.selector ||
methodId == EnterpriseModule.addModule.selector ||
methodId == SecurityManager.upgradeWallet.selector ||
methodId ==EnterpriseTransactionManager.multiCallWithGuardians.selector ||
methodId ==EnterpriseTransactionManager.multiCallWithGuardiansAndStartSession.selector)
{
// owner + majority of guardians
uint majorityGuardians = _majorityOfGuardians(_wallet);
// uint numberOfSignaturesRequired = majorityGuardians + 1;
return (majorityGuardians, OwnerSignature.Disallowed);
}
if (methodId == SecurityManager.finalizeRecovery.selector ||
methodId == SecurityManager.confirmGuardianAddition.selector ||
methodId == SecurityManager.confirmGuardianRevokation.selector)
{
// anyone
return (0, OwnerSignature.Anyone);
}
if (methodId == SecurityManager.lock.selector || methodId == SecurityManager.unlock.selector) {
// any guardian
return (1, OwnerSignature.Disallowed);
}
revert("SM: unknown method");
}
function _majorityOfGuardians(address _wallet) internal view returns (uint) {
return Utils.ceil(guardianStorage.guardianCount(_wallet), 2);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// 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 v4.4.1 (utils/Counters.sol)
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}// 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/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* _Available since v3.4._
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {EIP-5267}.
*
* _Available since v4.9._
*/
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
import "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}// 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/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// 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
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// 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: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */
/**
* returned data from validateUserOp.
* validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData`
* @param aggregator - address(0) - the account validated the signature by itself.
* address(1) - the account failed to validate the signature.
* otherwise - this is an address of a signature aggregator that must be used to validate the signature.
* @param validAfter - this UserOp is valid only after this timestamp.
* @param validaUntil - this UserOp is valid only up to this timestamp.
*/
struct ValidationData {
address aggregator;
uint48 validAfter;
uint48 validUntil;
}
//extract sigFailed, validAfter, validUntil.
// also convert zero validUntil to type(uint48).max
function _parseValidationData(uint validationData) pure returns (ValidationData memory data) {
address aggregator = address(uint160(validationData));
uint48 validUntil = uint48(validationData >> 160);
if (validUntil == 0) {
validUntil = type(uint48).max;
}
uint48 validAfter = uint48(validationData >> (48 + 160));
return ValidationData(aggregator, validAfter, validUntil);
}
// intersect account and paymaster ranges.
function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) {
ValidationData memory accountValidationData = _parseValidationData(validationData);
ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData);
address aggregator = accountValidationData.aggregator;
if (aggregator == address(0)) {
aggregator = pmValidationData.aggregator;
}
uint48 validAfter = accountValidationData.validAfter;
uint48 validUntil = accountValidationData.validUntil;
uint48 pmValidAfter = pmValidationData.validAfter;
uint48 pmValidUntil = pmValidationData.validUntil;
if (validAfter < pmValidAfter) validAfter = pmValidAfter;
if (validUntil > pmValidUntil) validUntil = pmValidUntil;
return ValidationData(aggregator, validAfter, validUntil);
}
/**
* helper to pack the return value for validateUserOp
* @param data - the ValidationData to pack
*/
function _packValidationData(ValidationData memory data) pure returns (uint256) {
return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48));
}
/**
* helper to pack the return value for validateUserOp, when not using an aggregator
* @param sigFailed - true for signature failure, false for success
* @param validUntil last timestamp this UserOperation is valid (or zero for infinite)
* @param validAfter first timestamp this UserOperation is valid
*/
function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) {
return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48));
}
/**
* keccak function over calldata.
* @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
*/
function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
assembly {
let mem := mload(0x40)
let len := data.length
calldatacopy(mem, data.offset, len)
ret := keccak256(mem, len)
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */
import {calldataKeccak} from "../core/Helpers.sol";
/**
* User Operation struct
* @param sender the sender account of this request.
* @param nonce unique value the sender uses to verify it is not a replay.
* @param initCode if set, the account contract will be created by this constructor/
* @param callData the method call to execute on this account.
* @param callGasLimit the gas limit passed to the callData method call.
* @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
* @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
* @param maxFeePerGas same as EIP-1559 gas parameter.
* @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
* @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender.
* @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID.
*/
struct UserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData;
bytes signature;
}
/**
* Utility functions helpful when working with UserOperation structs.
*/
library UserOperationLib {
function getSender(UserOperation calldata userOp) internal pure returns (address) {
address data;
//read sender from userOp, which is first userOp member (saves 800 gas...)
assembly {data := calldataload(userOp)}
return address(uint160(data));
}
//relayer/block builder might submit the TX with higher priorityFee, but the user should not
// pay above what he signed for.
function gasPrice(UserOperation calldata userOp) internal view returns (uint256) {
unchecked {
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
if (maxFeePerGas == maxPriorityFeePerGas) {
//legacy mode (for networks that don't support basefee opcode)
return maxFeePerGas;
}
return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
}
}
function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) {
address sender = getSender(userOp);
uint256 nonce = userOp.nonce;
bytes32 hashInitCode = calldataKeccak(userOp.initCode);
bytes32 hashCallData = calldataKeccak(userOp.callData);
uint256 callGasLimit = userOp.callGasLimit;
uint256 verificationGasLimit = userOp.verificationGasLimit;
uint256 preVerificationGas = userOp.preVerificationGas;
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);
return abi.encode(
sender, nonce,
hashInitCode, hashCallData,
callGasLimit, verificationGasLimit, preVerificationGas,
maxFeePerGas, maxPriorityFeePerGas,
hashPaymasterAndData
);
}
function hash(UserOperation calldata userOp) internal pure returns (bytes32) {
return keccak256(pack(userOp));
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}// Copyright (C) 2021 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
interface IAuthoriser {
function isAuthorised(address _wallet, address _spender, address _to, bytes calldata _data) external view returns (bool);
function areAuthorised(
address _wallet,
address[] calldata _spenders,
address[] calldata _to,
bytes[] calldata _data
)
external
view
returns (bool);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
import "../argent-trustlists/contracts/interfaces/IAuthoriser.sol"; //TODO: should we keep the authoriser for the first version?
import "../../wallet/IWallet.sol";
import "../infrastructure/IModuleRegistry.sol";
import "../infrastructure/storage/IGuardianStorage.sol";
import "../infrastructure/storage/ITransferStorage.sol";
import "./IModule.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "hardhat/console.sol";
/**
* @title BaseModule
* @notice Base Module contract that contains methods common to all Modules.
*/
abstract contract BaseModule is IModule {
// Empty calldata
bytes constant internal EMPTY_BYTES = "";
// Mock token address for ETH
address constant internal ETH_TOKEN = address(0);
// The module registry
IModuleRegistry internal immutable registry;
// The guardians storage
IGuardianStorage internal immutable guardianStorage;
// The trusted contacts storage
ITransferStorage internal immutable userWhitelist;
// The authoriser
IAuthoriser internal immutable authoriser;
event ModuleCreated(bytes32 name);
enum OwnerSignature {
Anyone, // Anyone
Required, // Owner required
Optional, // Owner and/or guardians
Disallowed, // Guardians only
Session // Session only
}
struct Session {
address key;
uint64 expires;
}
// Maps wallet to session
mapping (address => Session) internal sessions;
struct Lock {
// the lock's release timestamp
uint64 release;
// the signature of the method that set the last lock
bytes4 locker;
}
// Wallet specific lock storage
mapping (address => Lock) internal locks;
/**
* @notice Throws if the wallet is not locked.
*/
modifier onlyWhenLocked(address _wallet) {
require(_isLocked(_wallet), "BM: wallet must be locked");
_;
}
/**
* @notice Throws if the wallet is locked.
*/
modifier onlyWhenUnlocked(address _wallet) {
require(!_isLocked(_wallet), "BM: wallet locked");
_;
}
/**
* @notice Throws if the sender is not the module itself.
*/
modifier onlySelf() {
require(_isSelf(msg.sender), "BM: must be module");
_;
}
/**
* @notice Throws if the sender is not the module itself or the owner of the target wallet.
*/
modifier onlyWalletOwnerOrSelf(address _wallet) {
require(_isSelf(msg.sender) || _isOwner(_wallet, msg.sender), "BM: must be wallet owner/self");
_;
}
modifier onlyWalletOrSelf(address _wallet) {
require(_isSelf(msg.sender) || msg.sender == _wallet, "BM: must be wallet/self");
_;
}
/**
* @dev Throws if the sender is not the target wallet of the call.
*/
modifier onlyWallet(address _wallet) {
require(msg.sender == _wallet, "BM: caller must be wallet");
_;
}
constructor(
IModuleRegistry _registry,
IGuardianStorage _guardianStorage,
ITransferStorage _userWhitelist,
IAuthoriser _authoriser,
bytes32 _name
) {
registry = _registry;
guardianStorage = _guardianStorage;
userWhitelist = _userWhitelist;
authoriser = _authoriser;
emit ModuleCreated(_name);
}
/**
* @notice Moves tokens that have been sent to the module by mistake.
* @param _token The target token.
*/
function recoverToken(address _token) external {
uint total = IERC20(_token).balanceOf(address(this));
IERC20(_token).transfer(address(registry), total);
}
function _clearSession(address _wallet) internal {
delete sessions[_wallet];
}
/**
* @notice Helper method to check if an address is the owner of a target wallet.
* @param _wallet The target wallet.
* @param _addr The address.
*/
function _isOwner(address _wallet, address _addr) internal view returns (bool) {
return IWallet(_wallet).owner() == _addr;
}
/**
* @notice Helper method to check if a wallet is locked.
* @param _wallet The target wallet.
*/
function _isLocked(address _wallet) internal view returns (bool) {
return locks[_wallet].release > uint64(block.timestamp);
}
/**
* @notice Helper method to check if an address is the module itself.
* @param _addr The target address.
*/
function _isSelf(address _addr) internal view returns (bool) {
return _addr == address(this);
}
/**
* @notice Helper method to invoke a wallet.
* @param _wallet The target wallet.
* @param _to The target address for the transaction.
* @param _value The value of the transaction.
* @param _data The data of the transaction.
*/
function invokeWallet(address _wallet, address _to, uint256 _value, bytes memory _data) internal returns (bytes memory _res) {
bool success;
//TODO: change to execute? or whatever name there is in the wallet contract
console.log("invokeWallet");
(success, _res) = _wallet.call(abi.encodeWithSignature("invoke(address,uint256,bytes)", _to, _value, _data));
if (success && _res.length > 0) { //_res is empty if _wallet is an "old" BaseWallet that can't return output values
(_res) = abi.decode(_res, (bytes));
} else if (_res.length > 0) {
// solhint-disable-next-line no-inline-assembly
assembly {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
} else if (!success) {
revert("BM: wallet invoke reverted");
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
/**
* @title IModule
* @notice Interface for a Module.
*/
interface IModule {
/**
* @notice Adds a module to a wallet. Cannot execute when wallet is locked (or under recovery)
* @param _wallet The target wallet.
* @param _module The modules to authorise.
*/
function addModule(address _wallet, address _module) external;
/**
* @notice Inits a Module for a wallet by e.g. setting some wallet specific parameters in storage.
* @param _wallet The wallet.
*/
function init(address _wallet) external;
/**
* @notice Returns whether the module implements a callback for a given static call method.
* @param _methodId The method id.
*/
function supportsStaticCall(bytes4 _methodId) external view returns (bool _isSupported);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
/**
* @title Utils
* @notice Common utility methods used by modules.
*/
library Utils {
// ERC20, ERC721 & ERC1155 transfers & approvals
bytes4 private constant ERC20_TRANSFER = bytes4(keccak256("transfer(address,uint256)"));
bytes4 private constant ERC20_APPROVE = bytes4(keccak256("approve(address,uint256)"));
bytes4 private constant ERC721_SET_APPROVAL_FOR_ALL = bytes4(keccak256("setApprovalForAll(address,bool)"));
bytes4 private constant ERC721_TRANSFER_FROM = bytes4(keccak256("transferFrom(address,address,uint256)"));
bytes4 private constant ERC721_SAFE_TRANSFER_FROM = bytes4(keccak256("safeTransferFrom(address,address,uint256)"));
bytes4 private constant ERC721_SAFE_TRANSFER_FROM_BYTES = bytes4(keccak256("safeTransferFrom(address,address,uint256,bytes)"));
bytes4 private constant ERC1155_SAFE_TRANSFER_FROM = bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)"));
bytes4 private constant OWNER_SIG = 0x8da5cb5b;
/**
* @notice Helper method to recover the signer at a given position from a list of concatenated signatures.
* @param _signedHash The signed hash
* @param _signatures The concatenated signatures.
* @param _index The index of the signature to recover.
*/
function recoverSigner(bytes32 _signedHash, bytes memory _signatures, uint _index) internal pure returns (address) {
uint8 v;
bytes32 r;
bytes32 s;
// we jump 32 (0x20) as the first slot of bytes contains the length
// we jump 65 (0x41) per signature
// for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
// solhint-disable-next-line no-inline-assembly
assembly {
r := mload(add(_signatures, add(0x20,mul(0x41,_index))))
s := mload(add(_signatures, add(0x40,mul(0x41,_index))))
v := and(mload(add(_signatures, add(0x41,mul(0x41,_index)))), 0xff)
}
require(v == 27 || v == 28, "Utils: bad v value in signature");
address recoveredAddress = ecrecover(_signedHash, v, r, s);
require(recoveredAddress != address(0), "Utils: ecrecover returned 0");
return recoveredAddress;
}
/**
* @notice Helper method to recover the spender from a contract call.
* The method returns the contract unless the call is to a standard method of a ERC20/ERC721/ERC1155 token
* in which case the spender is recovered from the data.
* @param _to The target contract.
* @param _data The data payload.
*/
function recoverSpender(address _to, bytes memory _data) internal pure returns (address spender) {
if(_data.length >= 68) {
bytes4 methodId;
// solhint-disable-next-line no-inline-assembly
assembly {
methodId := mload(add(_data, 0x20))
}
if(
methodId == ERC20_TRANSFER ||
methodId == ERC20_APPROVE ||
methodId == ERC721_SET_APPROVAL_FOR_ALL)
{
// solhint-disable-next-line no-inline-assembly
assembly {
spender := mload(add(_data, 0x24))
}
return spender;
}
if(
methodId == ERC721_TRANSFER_FROM ||
methodId == ERC721_SAFE_TRANSFER_FROM ||
methodId == ERC721_SAFE_TRANSFER_FROM_BYTES ||
methodId == ERC1155_SAFE_TRANSFER_FROM)
{
// solhint-disable-next-line no-inline-assembly
assembly {
spender := mload(add(_data, 0x44))
}
return spender;
}
}
spender = _to;
}
/**
* @notice Helper method to parse data and extract the method signature.
*/
function functionPrefix(bytes memory _data) internal pure returns (bytes4 prefix) {
require(_data.length >= 4, "Utils: Invalid functionPrefix");
// solhint-disable-next-line no-inline-assembly
assembly {
prefix := mload(add(_data, 0x20))
}
}
/**
* @notice Checks if an address is a contract.
* @param _addr The address.
*/
function isContract(address _addr) internal view returns (bool) {
uint32 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(_addr)
}
return (size > 0);
}
/**
* @notice Checks if an address is a guardian or an account authorised to sign on behalf of a smart-contract guardian
* given a list of guardians.
* @param _guardians the list of guardians
* @param _guardian the address to test
* @return true and the list of guardians minus the found guardian upon success, false and the original list of guardians if not found.
*/
function isGuardianOrGuardianSigner(address[] memory _guardians, address _guardian) internal view returns (bool, address[] memory) {
if (_guardians.length == 0 || _guardian == address(0)) {
return (false, _guardians);
}
bool isFound = false;
address[] memory updatedGuardians = new address[](_guardians.length - 1);
uint256 index = 0;
for (uint256 i = 0; i < _guardians.length; i++) {
if (!isFound) {
// check if _guardian is an account guardian
if (_guardian == _guardians[i]) {
isFound = true;
continue;
}
// check if _guardian is the owner of a smart contract guardian
if (isContract(_guardians[i]) && isGuardianOwner(_guardians[i], _guardian)) {
isFound = true;
continue;
}
}
if (index < updatedGuardians.length) {
updatedGuardians[index] = _guardians[i];
index++;
}
}
return isFound ? (true, updatedGuardians) : (false, _guardians);
}
/**
* @notice Checks if an address is the owner of a guardian contract.
* The method does not revert if the call to the owner() method consumes more then 25000 gas.
* @param _guardian The guardian contract
* @param _owner The owner to verify.
*/
function isGuardianOwner(address _guardian, address _owner) internal view returns (bool) {
address owner = address(0);
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr,OWNER_SIG)
let result := staticcall(25000, _guardian, ptr, 0x20, ptr, 0x20)
if eq(result, 1) {
owner := mload(ptr)
}
}
return owner == _owner;
}
/**
* @notice Returns ceil(a / b).
*/
function ceil(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a / b;
if (a % b == 0) {
return c;
} else {
return c + 1;
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "hardhat/console.sol";
/**
* @title EnterpriseTransactionManager
* @notice Module to execute transactions in sequence to e.g. transfer tokens (ETH, ERC20, ERC721, ERC1155) or call third-party contracts.
*/
abstract contract EnterpriseTransactionManager is BaseModule {
// Static calls
bytes4 private constant ERC1271_IS_VALID_SIGNATURE = bytes4(keccak256("isValidSignature(bytes32,bytes)"));
bytes4 private constant ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
bytes4 private constant ERC1155_RECEIVED = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));
bytes4 private constant ERC1155_BATCH_RECEIVED = bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"));
bytes4 private constant ERC165_INTERFACE = bytes4(keccak256("supportsInterface(bytes4)"));
struct Call {
address to;
uint256 value;
bytes data;
}
// The time delay for adding a trusted contact
uint256 internal immutable whitelistPeriod;
// *************** Events *************************** //
event AddedToWhitelist(address indexed wallet, address indexed target, uint64 whitelistAfter);
event RemovedFromWhitelist(address indexed wallet, address indexed target);
event SessionCreated(address indexed wallet, address sessionKey, uint64 expires);
event SessionCleared(address indexed wallet, address sessionKey);
// *************** Constructor ************************ //
constructor(uint256 _whitelistPeriod) {
whitelistPeriod = _whitelistPeriod;
}
// *************** External functions ************************ //
/**
* @notice Makes the target wallet execute a sequence of transactions authorised by the wallet owner.
* The method reverts if any of the inner transactions reverts.
* The method reverts if any of the inner transaction is not to a trusted contact or an authorised dapp.
* @param _wallet The target wallet.
* @param _transactions The sequence of transactions.
*/
function multiCall(
address _wallet,
Call[] calldata _transactions
)
external
onlySelf()
onlyWhenUnlocked(_wallet)
returns (bytes[] memory)
{
bytes[] memory results = new bytes[](_transactions.length);
for(uint i = 0; i < _transactions.length; i++) {
//FIX: check authoriser
// address spender = Utils.recoverSpender(_transactions[i].to, _transactions[i].data);
require(
_transactions[i].to != address(this),
"TM: call not authorised");
results[i] = invokeWallet(_wallet, _transactions[i].to, _transactions[i].value, _transactions[i].data);
}
return results;
}
/**
* @notice Makes the target wallet execute a sequence of transactions authorised by a session key.
* The method reverts if any of the inner transactions reverts.
* @param _wallet The target wallet.
* @param _transactions The sequence of transactions.
*/
function multiCallWithSession(
address _wallet,
Call[] calldata _transactions
)
external
onlySelf()
onlyWhenUnlocked(_wallet)
returns (bytes[] memory)
{
return multiCallWithApproval(_wallet, _transactions);
}
/**
* @notice Makes the target wallet execute a sequence of transactions approved by a majority of guardians.
* The method reverts if any of the inner transactions reverts.
* @param _wallet The target wallet.
* @param _transactions The sequence of transactions.
*/
function multiCallWithGuardians(
address _wallet,
Call[] calldata _transactions
)
external
onlySelf()
onlyWhenUnlocked(_wallet)
returns (bytes[] memory)
{
console.log("multiCall");
console.log(_transactions.length);
return multiCallWithApproval(_wallet, _transactions);
}
/**
* @notice Makes the target wallet execute a sequence of transactions approved by a majority of guardians.
* The method reverts if any of the inner transactions reverts.
* Upon success a new session is started.
* @param _wallet The target wallet.
* @param _transactions The sequence of transactions.
*/
function multiCallWithGuardiansAndStartSession(
address _wallet,
Call[] calldata _transactions,
address _sessionUser,
uint64 _duration
)
external
onlySelf()
onlyWhenUnlocked(_wallet)
returns (bytes[] memory)
{
startSession(_wallet, _sessionUser, _duration);
return multiCallWithApproval(_wallet, _transactions);
}
/**
* @notice Clears the active session of a wallet if any.
* @param _wallet The target wallet.
*/
function clearSession(address _wallet) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
emit SessionCleared(_wallet, sessions[_wallet].key);
_clearSession(_wallet);
}
/**
* @notice Adds an address to the list of trusted contacts.
* @param _wallet The target wallet.
* @param _target The address to add.
*/
function addToWhitelist(address _wallet, address _target) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
require(_target != _wallet, "TM: Cannot whitelist wallet");
require(!registry.isRegisteredModule(_target), "TM: Cannot whitelist module");
require(!isWhitelisted(_wallet, _target), "TM: target already whitelisted");
uint256 whitelistAfter = block.timestamp + whitelistPeriod;
setWhitelist(_wallet, _target, whitelistAfter);
emit AddedToWhitelist(_wallet, _target, uint64(whitelistAfter));
}
/**
* @notice Removes an address from the list of trusted contacts.
* @param _wallet The target wallet.
* @param _target The address to remove.
*/
function removeFromWhitelist(address _wallet, address _target) external onlyWalletOwnerOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
setWhitelist(_wallet, _target, 0);
emit RemovedFromWhitelist(_wallet, _target);
}
/**
* @notice Checks if an address is a trusted contact for a wallet.
* @param _wallet The target wallet.
* @param _target The address.
* @return _isWhitelisted true if the address is a trusted contact.
*/
function isWhitelisted(address _wallet, address _target) public view returns (bool _isWhitelisted) {
uint whitelistAfter = userWhitelist.getWhitelist(_wallet, _target);
return whitelistAfter > 0 && whitelistAfter < block.timestamp;
}
/**
* @inheritdoc IModule
*/
function supportsStaticCall(bytes4 _methodId) external pure override returns (bool _isSupported) {
return _methodId == ERC1271_IS_VALID_SIGNATURE ||
_methodId == ERC721_RECEIVED ||
_methodId == ERC165_INTERFACE ||
_methodId == ERC1155_RECEIVED ||
_methodId == ERC1155_BATCH_RECEIVED;
}
/** ******************* Callbacks ************************** */
/**
* @notice Returns true if this contract implements the interface defined by
* `interfaceId` (see https://eips.ethereum.org/EIPS/eip-165).
*/
// function supportsInterface(bytes4 _interfaceID) external pure returns (bool) {
// return _interfaceID == ERC165_INTERFACE || _interfaceID == (ERC1155_RECEIVED ^ ERC1155_BATCH_RECEIVED);
// }
/**
* @notice Implementation of EIP 1271.
* Should return whether the signature provided is valid for the provided data.
* @param _msgHash Hash of a message signed on the behalf of address(this)
* @param _signature Signature byte array associated with _msgHash
*/
function isValidSignature(bytes32 _msgHash, bytes memory _signature) external view returns (bytes4) {
require(_signature.length == 65, "TM: invalid signature length");
address signer = Utils.recoverSigner(_msgHash, _signature, 0);
require(_isOwner(msg.sender, signer), "TM: Invalid signer");
return ERC1271_IS_VALID_SIGNATURE;
}
fallback() external {
bytes4 methodId = Utils.functionPrefix(msg.data);
if(methodId == ERC721_RECEIVED || methodId == ERC1155_RECEIVED || methodId == ERC1155_BATCH_RECEIVED) {
// solhint-disable-next-line no-inline-assembly
assembly {
calldatacopy(0, 0, 0x04)
return (0, 0x20)
}
}
}
// *************** Internal Functions ********************* //
function enableDefaultStaticCalls(address _wallet) internal {
// setup this module as static call executor
IWallet(_wallet).enableStaticCall(address(this), ERC1271_IS_VALID_SIGNATURE);
}
function multiCallWithApproval(address _wallet, Call[] calldata _transactions) internal returns (bytes[] memory) {
bytes[] memory results = new bytes[](_transactions.length);
console.log(_transactions.length);
for(uint i = 0; i < _transactions.length; i++) {
console.log(_transactions[i].to);
console.logBytes(_transactions[i].data);
console.log(_transactions[i].value);
results[i] = invokeWallet(_wallet, _transactions[i].to, _transactions[i].value, _transactions[i].data);
}
return results;
}
function startSession(address _wallet, address _sessionUser, uint64 _duration) internal {
require(_sessionUser != address(0), "TM: Invalid session user");
require(_duration > 0, "TM: Invalid session duration");
uint64 expiry = SafeCast.toUint64(block.timestamp + _duration);
sessions[_wallet] = Session(_sessionUser, expiry);
emit SessionCreated(_wallet, _sessionUser, expiry);
}
function setWhitelist(address _wallet, address _target, uint256 _whitelistAfter) internal {
userWhitelist.setWhitelist(_wallet, _target, _whitelistAfter);
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;
/**
* @title IModuleRegistry
* @notice Interface for the registry of authorised modules.
*/
interface IModuleRegistry {
function registerModule(address _module, bytes32 _name) external;
function deregisterModule(address _module) external;
function registerUpgrader(address _upgrader, bytes32 _name) external;
function deregisterUpgrader(address _upgrader) external;
function recoverToken(address _token) external;
function moduleInfo(address _module) external view returns (bytes32);
function upgraderInfo(address _upgrader) external view returns (bytes32);
function isRegisteredModule(address _module) external view returns (bool);
function isRegisteredModule(address[] calldata _modules) external view returns (bool);
function isRegisteredUpgrader(address _upgrader) external view returns (bool);
}// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;
interface IGuardianStorage {
/**
* @notice Lets an authorised module add a guardian to a wallet.
* @param _wallet The target wallet.
* @param _guardian The guardian to add.
*/
function addGuardian(address _wallet, address _guardian) external;
/**
* @notice Lets an authorised module revoke a guardian from a wallet.
* @param _wallet The target wallet.
* @param _guardian The guardian to revoke.
*/
function revokeGuardian(address _wallet, address _guardian) external;
/**
* @notice Checks if an account is a guardian for a wallet.
* @param _wallet The target wallet.
* @param _guardian The account.
* @return true if the account is a guardian for a wallet.
*/
function isGuardian(address _wallet, address _guardian) external view returns (bool);
function isLocked(address _wallet) external view returns (bool);
function getLock(address _wallet) external view returns (uint256);
function getLocker(address _wallet) external view returns (address);
function setLock(address _wallet, uint256 _releaseAfter) external;
function getGuardians(address _wallet) external view returns (address[] memory);
function guardianCount(address _wallet) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;
/**
* @title ITransferStorage
* @notice TransferStorage interface
*/
interface ITransferStorage {
function setWhitelist(address _wallet, address _target, uint256 _value) external;
function getWhitelist(address _wallet, address _target) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
import "../interfaces/UserOperation.sol";
pragma solidity ^0.8.18;
interface ISignatureModule {
function isValidSignature(
UserOperation calldata _userOp,
bytes32 _userOpHash
) external view returns (uint256);
function isSignatureModule() external pure returns (bool);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "./infrastructure/storage/IGuardianStorage.sol";
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
/**
* @title RelayerManager
* @notice Abstract Module to execute transactions signed by ETH-less accounts and sent by a relayer.
*/
abstract contract RelayerManager is BaseModule, EIP712 {
// solhint-disable-next-line var-name-mixedcase
bytes32 private constant _TRANSACTION_TYPEHASH =
keccak256(
"Transaction(address wallet,bytes data,uint256 nonce,uint256 deadline)"
);
mapping(address => mapping(bytes32 => bool)) private _usedSignHashes;
event TransactionExecuted(
address indexed wallet,
bool indexed success,
bytes returnData,
bytes32 signedHash
);
event Refund(
address indexed wallet,
address indexed refundAddress,
address refundToken,
uint256 refundAmount
);
// *************** Constructor ************************ //
/**
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
*
*/
constructor(string memory name) EIP712(name, "1") {}
/* ***************** External methods ************************* */
/**
* @notice Gets the number of valid signatures that must be provided to execute a
* specific relayed transaction.
* @param _wallet The target wallet.
* @param _data The data of the relayed transaction.
* @return The number of required signatures and the wallet owner signature requirement.
*/
function getRequiredSignatures(
address _wallet,
bytes calldata _data
) public view virtual returns (uint256, OwnerSignature);
/**
* @notice Executes a relayed transaction.
* @param _wallet The target wallet.
* @param _data The data for the relayed transaction
* @param _nonce The nonce used to prevent replay attacks.
* @param _signatures The signatures as a concatenated byte array.
*/
function execute(
address _wallet,
bytes calldata _data,
uint256 _nonce,
uint256 _deadline,
bytes calldata _signatures
) external returns (bool) {
require(verifyData(_wallet, _data), "RM: Target of _data != _wallet");
require(!_isLocked(_wallet), "RM: Locked wallet refund");
uint256 requiredSignatures;
OwnerSignature ownerSignatureRequirement;
bool success;
bytes memory returnData;
(requiredSignatures, ownerSignatureRequirement) = getRequiredSignatures(
_wallet,
_data
);
require(
requiredSignatures > 0 ||
ownerSignatureRequirement == OwnerSignature.Anyone,
"RM: Wrong signature requirement"
);
require(
requiredSignatures * 65 == _signatures.length,
"RM: Wrong number of signatures"
);
bytes32 structHash = keccak256(
abi.encode(
_TRANSACTION_TYPEHASH,
_wallet,
keccak256(_data),
_nonce,
_deadline
)
);
bytes32 hash = _hashTypedDataV4(structHash);
if (ownerSignatureRequirement == OwnerSignature.Session) {
require(validateSession(_wallet), "RM: Invalid session");
} else {
require(
validateSignatures(
_wallet,
hash,
_signatures,
ownerSignatureRequirement
),
"RM: Invalid signatures"
);
}
(success, returnData) = address(this).call(_data);
emit TransactionExecuted(
_wallet,
success,
returnData,
hash
);
return success;
}
/**
* @notice Checks if a transaction identified by its sign hash has already been executed.
* @param _wallet The target wallet.
* @param _signHash The sign hash of the transaction.
*/
function isExecutedTx(
address _wallet,
bytes32 _signHash
) public view returns (bool executed) {
return _usedSignHashes[_wallet][_signHash];
}
/**
* @notice Gets the last stored session for a wallet.
* @param _wallet The target wallet.
*/
function getSession(
address _wallet
) external view returns (address key, uint64 expires) {
return (sessions[_wallet].key, sessions[_wallet].expires);
}
/**
* @notice Validates the signatures provided with a relayed transaction.
* @param _wallet The target wallet.
* @param _signHash The sign hash of the transaction.
* @param _signatures The signatures as a concatenated bytes array.
* @param _option An OwnerSignature enum indicating whether the owner is required, optional or disallowed.
* @return A boolean indicating whether the signatures are valid.
*/
function validateSignatures(
address _wallet,
bytes32 _signHash,
bytes calldata _signatures,
OwnerSignature _option
) internal view returns (bool) {
if (_signatures.length == 0) {
return true;
}
address lastSigner = address(0);
address[] memory guardians;
if (_option != OwnerSignature.Required || _signatures.length > 65) {
guardians = guardianStorage.getGuardians(_wallet); // guardians are only read if they may be needed
}
require(
!isExecutedTx(_wallet, _signHash),
"RM: validateSignatures: tx already executed"
);
for (uint256 i = 0; i < _signatures.length / 65; i++) {
bytes memory signature = new bytes(65);
assembly {
// Calculate the offset for the signature based on the index
let offset := add(mul(i, 65), _signatures.offset)
// Copy 65 bytes from the calculated offset in calldata to the memory location of the signature array
calldatacopy(add(signature, 32), offset, 65)
}
if (i == 0) {
bool ownerFound;
ownerFound = SignatureChecker.isValidSignatureNow(
IWallet(_wallet).owner(),
_signHash,
signature
);
if (_option == OwnerSignature.Required) {
// First signer must be owner
if (ownerFound) {
continue;
}
return false;
} else if (_option == OwnerSignature.Optional) {
// First signer can be owner
if (ownerFound) {
continue;
}
}
}
bool guardianFound;
for (uint256 j = 0; j < guardians.length; j++) {
if (
SignatureChecker.isValidSignatureNow(
guardians[j],
_signHash,
signature
)
) {
if (guardians[j] <= lastSigner) {
return false; // Signers must be different
}
lastSigner = guardians[j];
guardianFound = true;
break;
}
}
if (!guardianFound) {
return false;
}
}
return true;
}
/**
* @notice Validates the signature provided when a session key was used.
* @param _wallet The target wallet.
* @return A boolean indicating whether the signature is valid.
*/
function validateSession(address _wallet) internal view returns (bool) {
Session memory session = sessions[_wallet];
return (msg.sender == _wallet && session.expires >= block.timestamp);
}
/**
* @notice Checks that the wallet address provided as the first parameter of _data matches _wallet
* @return false if the addresses are different.
*/
function verifyData(
address _wallet,
bytes calldata _data
) internal pure returns (bool) {
require(_data.length >= 36, "RM: Invalid dataWallet");
address dataWallet = abi.decode(_data[4:], (address));
return dataWallet == _wallet;
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.3;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "./common/Utils.sol";
import "./common/BaseModule.sol";
import "../wallet/IWallet.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
/**
* @title SecurityManager
* @notice Abstract module implementing the key security features of the wallet: guardians, lock and recovery.
*/
abstract contract SecurityManager is BaseModule {
struct RecoveryConfig {
address recovery;
uint64 executeAfter;
uint32 guardianCount;
}
struct GuardianManagerConfig {
// The time at which a guardian addition or revokation will be confirmable by the owner
mapping (bytes32 => uint256) pending;
}
// Wallet specific storage for recovery
mapping (address => RecoveryConfig) internal recoveryConfigs;
// Wallet specific storage for pending guardian addition/revokation
mapping (address => GuardianManagerConfig) internal guardianConfigs;
// Recovery period
uint256 internal immutable recoveryPeriod;
// Lock period
uint256 internal immutable lockPeriod;
// The security period to add/remove guardians
uint256 internal immutable securityPeriod;
// The security window
uint256 internal immutable securityWindow;
// *************** Events *************************** //
event RecoveryExecuted(address indexed wallet, address indexed _recovery, uint64 executeAfter);
event RecoveryFinalized(address indexed wallet, address indexed _recovery);
event RecoveryCanceled(address indexed wallet, address indexed _recovery);
event OwnershipTransfered(address indexed wallet, address indexed _newOwner);
event WalletUpgraded(address indexed wallet, address indexed _newImplementation);
event Locked(address indexed wallet, uint64 releaseAfter);
event Unlocked(address indexed wallet);
event GuardianAdditionRequested(address indexed wallet, address indexed guardian, uint256 executeAfter);
event GuardianRevokationRequested(address indexed wallet, address indexed guardian, uint256 executeAfter);
event GuardianAdditionCancelled(address indexed wallet, address indexed guardian);
event GuardianRevokationCancelled(address indexed wallet, address indexed guardian);
event GuardianAdded(address indexed wallet, address indexed guardian);
event GuardianRevoked(address indexed wallet, address indexed guardian);
// *************** Modifiers ************************ //
/**
* @notice Throws if there is no ongoing recovery procedure.
*/
modifier onlyWhenRecovery(address _wallet) {
require(recoveryConfigs[_wallet].executeAfter > 0, "SM: no ongoing recovery");
_;
}
/**
* @notice Throws if there is an ongoing recovery procedure.
*/
modifier notWhenRecovery(address _wallet) {
require(recoveryConfigs[_wallet].executeAfter == 0, "SM: ongoing recovery");
_;
}
/**
* @notice Throws if the caller is not a guardian for the wallet or the module itself.
*/
modifier onlyGuardianOrSelf(address _wallet) {
require(_isSelf(msg.sender) || isGuardian(_wallet, msg.sender), "SM: must be guardian/self");
_;
}
// *************** Constructor ************************ //
constructor(
uint256 _recoveryPeriod,
uint256 _securityPeriod,
uint256 _securityWindow,
uint256 _lockPeriod
) {
// For the wallet to be secure we must have recoveryPeriod >= securityPeriod + securityWindow
// where securityPeriod and securityWindow are the security parameters of adding/removing guardians.
require(_lockPeriod >= _recoveryPeriod, "SM: insecure lock period");
require(_recoveryPeriod >= _securityPeriod + _securityWindow, "SM: insecure security periods");
recoveryPeriod = _recoveryPeriod;
lockPeriod = _lockPeriod;
securityWindow = _securityWindow;
securityPeriod = _securityPeriod;
}
// *************** External functions ************************ //
// *************** Recovery functions ************************ //
/**
* @notice Lets the guardians start the execution of the recovery procedure.
* Once triggered the recovery is pending for the security period before it can be finalized.
* Must be confirmed by N guardians, where N = ceil(Nb Guardians / 2).
* @param _wallet The target wallet.
* @param _recovery The address to which ownership should be transferred.
*/
function executeRecovery(address _wallet, address _recovery) external onlySelf() notWhenRecovery(_wallet) {
validateNewOwner(_wallet, _recovery);
uint64 executeAfter = uint64(block.timestamp + recoveryPeriod);
recoveryConfigs[_wallet] = RecoveryConfig(_recovery, executeAfter, uint32(guardianStorage.guardianCount(_wallet)));
_setLock(_wallet, block.timestamp + lockPeriod, SecurityManager.executeRecovery.selector);
emit RecoveryExecuted(_wallet, _recovery, executeAfter);
}
/**
* @notice Finalizes an ongoing recovery procedure if the security period is over.
* The method is public and callable by anyone to enable orchestration.
* @param _wallet The target wallet.
*/
function finalizeRecovery(address _wallet) external onlyWhenRecovery(_wallet) {
RecoveryConfig storage config = recoveryConfigs[_wallet];
require(uint64(block.timestamp) > config.executeAfter, "SM: ongoing recovery period");
address recoveryOwner = config.recovery;
delete recoveryConfigs[_wallet];
_clearSession(_wallet);
IWallet(_wallet).setOwner(recoveryOwner);
_setLock(_wallet, 0, bytes4(0));
emit RecoveryFinalized(_wallet, recoveryOwner);
}
/**
* @notice Lets the owner cancel an ongoing recovery procedure.
* Must be confirmed by N guardians, where N = ceil(Nb Guardian at executeRecovery + 1) / 2) - 1.
* @param _wallet The target wallet.
*/
function cancelRecovery(address _wallet) external onlySelf() onlyWhenRecovery(_wallet) {
address recoveryOwner = recoveryConfigs[_wallet].recovery;
delete recoveryConfigs[_wallet];
_setLock(_wallet, 0, bytes4(0));
emit RecoveryCanceled(_wallet, recoveryOwner);
}
/**
* @notice Lets the owner transfer the wallet ownership. This is executed immediately.
* @param _wallet The target wallet.
* @param _newOwner The address to which ownership should be transferred.
*/
function transferOwnership(address _wallet, address _newOwner) external onlySelf() onlyWhenUnlocked(_wallet) {
validateNewOwner(_wallet, _newOwner);
IWallet(_wallet).setOwner(_newOwner);
emit OwnershipTransfered(_wallet, _newOwner);
}
/**
* @notice Lets the owner upgrade the wallet. This is executed immediately.
* @param _wallet The target wallet.
* @param _newImplementation The address of the new implementation.
*/
function upgradeWallet(address _wallet, address _newImplementation) external onlySelf() onlyWhenUnlocked(_wallet) {
//TODO: validate new implementation
UUPSUpgradeable(_wallet).upgradeTo(_newImplementation);
emit WalletUpgraded(_wallet, _newImplementation);
}
/**
* @notice Gets the details of the ongoing recovery procedure if any.
* @param _wallet The target wallet.
*/
function getRecovery(address _wallet) external view returns(address _address, uint64 _executeAfter, uint32 _guardianCount) {
RecoveryConfig storage config = recoveryConfigs[_wallet];
return (config.recovery, config.executeAfter, config.guardianCount);
}
// *************** Lock functions ************************ //
/**
* @notice Lets a guardian lock a wallet.
* @param _wallet The target wallet.
*/
function lock(address _wallet) external onlyGuardianOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
_setLock(_wallet, block.timestamp + lockPeriod, SecurityManager.lock.selector);
emit Locked(_wallet, uint64(block.timestamp + lockPeriod));
}
/**
* @notice Lets a guardian unlock a locked wallet.
* @param _wallet The target wallet.
*/
function unlock(address _wallet) external onlyGuardianOrSelf(_wallet) onlyWhenLocked(_wallet) {
require(locks[_wallet].locker == SecurityManager.lock.selector, "SM: cannot unlock");
_setLock(_wallet, 0, bytes4(0));
emit Unlocked(_wallet);
}
/**
* @notice Returns the release time of a wallet lock or 0 if the wallet is unlocked.
* @param _wallet The target wallet.
* @return _releaseAfter The epoch time at which the lock will release (in seconds).
*/
function getLock(address _wallet) external view returns(uint64 _releaseAfter) {
return _isLocked(_wallet) ? locks[_wallet].release : 0;
}
/**
* @notice Checks if a wallet is locked.
* @param _wallet The target wallet.
* @return _isLocked `true` if the wallet is locked otherwise `false`.
*/
function isLocked(address _wallet) external view returns (bool) {
return _isLocked(_wallet);
}
// *************** Guardian functions ************************ //
/**
* @notice Lets the owner add a guardian to its wallet.
* The first guardian is added immediately. All following additions must be confirmed
* by calling the confirmGuardianAddition() method.
* @param _wallet The target wallet.
* @param _guardian The guardian to add.
*/
function addGuardian(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
console.log("addGuardian");
require(!_isOwner(_wallet, _guardian), "SM: guardian cannot be owner");
require(!isGuardian(_wallet, _guardian), "SM: duplicate guardian");
// Guardians must either be an EOA or a contract with an owner()
// method that returns an address with a 25000 gas stipend.
// Note that this test is not meant to be strict and can be bypassed by custom malicious contracts.
(bool success,) = _guardian.call{gas: 25000}(abi.encodeWithSignature("owner()"));
require(success, "SM: must be EOA/Argent wallet");
bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition"));
GuardianManagerConfig storage config = guardianConfigs[_wallet];
require(
config.pending[id] == 0 || block.timestamp > config.pending[id] + securityWindow,
"SM: duplicate pending addition");
config.pending[id] = block.timestamp + securityPeriod;
emit GuardianAdditionRequested(_wallet, _guardian, block.timestamp + securityPeriod);
}
/**
* @notice Confirms the pending addition of a guardian to a wallet.
* The method must be called during the confirmation window and can be called by anyone to enable orchestration.
* @param _wallet The target wallet.
* @param _guardian The guardian.
*/
function confirmGuardianAddition(address _wallet, address _guardian) external onlyWhenUnlocked(_wallet) {
bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition"));
GuardianManagerConfig storage config = guardianConfigs[_wallet];
require(config.pending[id] > 0, "SM: unknown pending addition");
require(config.pending[id] < block.timestamp, "SM: pending addition not over");
require(block.timestamp < config.pending[id] + securityWindow, "SM: pending addition expired");
guardianStorage.addGuardian(_wallet, _guardian);
emit GuardianAdded(_wallet, _guardian);
delete config.pending[id];
}
/**
* @notice Lets the owner cancel a pending guardian addition.
* @param _wallet The target wallet.
* @param _guardian The guardian.
*/
function cancelGuardianAddition(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "addition"));
GuardianManagerConfig storage config = guardianConfigs[_wallet];
require(config.pending[id] > 0, "SM: unknown pending addition");
delete config.pending[id];
emit GuardianAdditionCancelled(_wallet, _guardian);
}
/**
* @notice Lets the owner revoke a guardian from its wallet.
* @dev Revokation must be confirmed by calling the confirmGuardianRevokation() method.
* @param _wallet The target wallet.
* @param _guardian The guardian to revoke.
*/
function revokeGuardian(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) {
require(isGuardian(_wallet, _guardian), "SM: must be existing guardian");
bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation"));
GuardianManagerConfig storage config = guardianConfigs[_wallet];
require(
config.pending[id] == 0 || block.timestamp > config.pending[id] + securityWindow,
"SM: duplicate pending revoke"); // TODO need to allow if confirmation window passed
config.pending[id] = block.timestamp + securityPeriod;
emit GuardianRevokationRequested(_wallet, _guardian, block.timestamp + securityPeriod);
}
/**
* @notice Confirms the pending revokation of a guardian to a wallet.
* The method must be called during the confirmation window and can be called by anyone to enable orchestration.
* @param _wallet The target wallet.
* @param _guardian The guardian.
*/
function confirmGuardianRevokation(address _wallet, address _guardian) external {
bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation"));
GuardianManagerConfig storage config = guardianConfigs[_wallet];
require(config.pending[id] > 0, "SM: unknown pending revoke");
require(config.pending[id] < block.timestamp, "SM: pending revoke not over");
require(block.timestamp < config.pending[id] + securityWindow, "SM: pending revoke expired");
guardianStorage.revokeGuardian(_wallet, _guardian);
emit GuardianRevoked(_wallet, _guardian);
delete config.pending[id];
}
/**
* @notice Lets the owner cancel a pending guardian revokation.
* @param _wallet The target wallet.
* @param _guardian The guardian.
*/
function cancelGuardianRevokation(address _wallet, address _guardian) external onlyWalletOrSelf(_wallet) onlyWhenUnlocked(_wallet) {
bytes32 id = keccak256(abi.encodePacked(_wallet, _guardian, "revokation"));
GuardianManagerConfig storage config = guardianConfigs[_wallet];
require(config.pending[id] > 0, "SM: unknown pending revoke");
delete config.pending[id];
emit GuardianRevokationCancelled(_wallet, _guardian);
}
/**
* @notice Checks if an address is a guardian for a wallet.
* @param _wallet The target wallet.
* @param _guardian The address to check.
* @return _isGuardian `true` if the address is a guardian for the wallet otherwise `false`.
*/
function isGuardian(address _wallet, address _guardian) public view returns (bool _isGuardian) {
return guardianStorage.isGuardian(_wallet, _guardian);
}
/**
* @notice Counts the number of active guardians for a wallet.
* @param _wallet The target wallet.
* @return _count The number of active guardians for a wallet.
*/
function guardianCount(address _wallet) external view returns (uint256 _count) {
return guardianStorage.guardianCount(_wallet);
}
/**
* @notice Get the active guardians for a wallet.
* @param _wallet The target wallet.
* @return _guardians the active guardians for a wallet.
*/
function getGuardians(address _wallet) external view returns (address[] memory _guardians) {
return guardianStorage.getGuardians(_wallet);
}
// *************** Internal Functions ********************* //
function validateNewOwner(address _wallet, address _newOwner) internal view {
require(_newOwner != address(0), "SM: new owner cannot be null");
require(!isGuardian(_wallet, _newOwner), "SM: new owner cannot be guardian");
}
function _setLock(address _wallet, uint256 _releaseAfter, bytes4 _locker) internal {
locks[_wallet] = Lock(SafeCast.toUint64(_releaseAfter), _locker);
}
}// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../interfaces/UserOperation.sol";
import "../wallet/IWallet.sol";
import "./ISignatureModule.sol";
import "hardhat/console.sol";
abstract contract SignatureModule is ISignatureModule{
//is ISignatureModule {
using ECDSA for bytes32;
//return value in case of signature failure, with no time-range.
// equivalent to _packValidationData(true,0,0);
uint256 internal constant SIG_VALIDATION_FAILED = 1;
constructor() {}
function isValidSignature(
UserOperation calldata _userOp,
bytes32 _userOpHash
) public view override returns (uint256 validationData) {
bytes32 hash = _userOpHash.toEthSignedMessageHash();
address _owner = IWallet(msg.sender).owner();
if (_owner != hash.recover(_userOp.signature))
return SIG_VALIDATION_FAILED;
return 0;
}
function isSignatureModule() external pure override returns (bool) {
return true;
}
}// Copyright (C) 2018 Argent Labs Ltd. <https://argent.xyz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.5.4 <0.9.0;
/**
* @title IWallet
* @notice Interface for the BaseWallet
*/
interface IWallet {
/**
* @notice Returns the wallet owner.
* @return The wallet owner address.
*/
function owner() external view returns (address);
/**
* @notice Returns the number of authorised modules.
* @return The number of authorised modules.
*/
function modules() external view returns (uint);
/**
* @notice Sets a new owner for the wallet.
* @param _newOwner The new owner.
*/
function setOwner(address _newOwner) external;
/**
* @notice Checks if a module is authorised on the wallet.
* @param _module The module address to check.
* @return `true` if the module is authorised, otherwise `false`.
*/
function authorised(address _module) external view returns (bool);
/**
* @notice Returns the module responsible for a static call redirection.
* @param _sig The signature of the static call.
* @return the module doing the redirection
*/
function enabled(bytes4 _sig) external view returns (address);
/**
* @notice Enables/Disables a module.
* @param _module The target module.
* @param _value Set to `true` to authorise the module.
*/
function authoriseModule(address _module, bool _value) external;
/**
* @notice Enables a static method by specifying the target module to which the call must be delegated.
* @param _module The target module.
* @param _method The static method signature.
*/
function enableStaticCall(address _module, bytes4 _method) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
library console {
address constant CONSOLE_ADDRESS =
0x000000000000000000636F6e736F6c652e6c6f67;
function _sendLogPayloadImplementation(bytes memory payload) internal view {
address consoleAddress = CONSOLE_ADDRESS;
/// @solidity memory-safe-assembly
assembly {
pop(
staticcall(
gas(),
consoleAddress,
add(payload, 32),
mload(payload),
0,
0
)
)
}
}
function _castToPure(
function(bytes memory) internal view fnIn
) internal pure returns (function(bytes memory) pure fnOut) {
assembly {
fnOut := fnIn
}
}
function _sendLogPayload(bytes memory payload) internal pure {
_castToPure(_sendLogPayloadImplementation)(payload);
}
function log() internal pure {
_sendLogPayload(abi.encodeWithSignature("log()"));
}
function logInt(int256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
}
function logUint(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function logString(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function logBool(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function logAddress(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function logBytes(bytes memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
}
function logBytes1(bytes1 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
}
function logBytes2(bytes2 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
}
function logBytes3(bytes3 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
}
function logBytes4(bytes4 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
}
function logBytes5(bytes5 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
}
function logBytes6(bytes6 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
}
function logBytes7(bytes7 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
}
function logBytes8(bytes8 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
}
function logBytes9(bytes9 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
}
function logBytes10(bytes10 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
}
function logBytes11(bytes11 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
}
function logBytes12(bytes12 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
}
function logBytes13(bytes13 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
}
function logBytes14(bytes14 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
}
function logBytes15(bytes15 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
}
function logBytes16(bytes16 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
}
function logBytes17(bytes17 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
}
function logBytes18(bytes18 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
}
function logBytes19(bytes19 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
}
function logBytes20(bytes20 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
}
function logBytes21(bytes21 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
}
function logBytes22(bytes22 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
}
function logBytes23(bytes23 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
}
function logBytes24(bytes24 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
}
function logBytes25(bytes25 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
}
function logBytes26(bytes26 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
}
function logBytes27(bytes27 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
}
function logBytes28(bytes28 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
}
function logBytes29(bytes29 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
}
function logBytes30(bytes30 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
}
function logBytes31(bytes31 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
}
function logBytes32(bytes32 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
}
function log(uint256 p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
}
function log(string memory p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
}
function log(bool p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
}
function log(address p0) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
}
function log(uint256 p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
}
function log(uint256 p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
}
function log(uint256 p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
}
function log(uint256 p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
}
function log(string memory p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
}
function log(string memory p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
}
function log(string memory p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
}
function log(string memory p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
}
function log(bool p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
}
function log(bool p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
}
function log(bool p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
}
function log(bool p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
}
function log(address p0, uint256 p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
}
function log(address p0, string memory p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
}
function log(address p0, bool p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
}
function log(address p0, address p1) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
}
function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
}
function log(uint256 p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
}
function log(uint256 p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
}
function log(uint256 p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
}
function log(uint256 p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
}
function log(uint256 p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
}
function log(uint256 p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
}
function log(uint256 p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
}
function log(uint256 p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
}
function log(uint256 p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
}
function log(string memory p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
}
function log(string memory p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
}
function log(string memory p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
}
function log(string memory p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
}
function log(string memory p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
}
function log(string memory p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
}
function log(string memory p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
}
function log(string memory p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
}
function log(string memory p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
}
function log(string memory p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
}
function log(string memory p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
}
function log(string memory p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
}
function log(string memory p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
}
function log(bool p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
}
function log(bool p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
}
function log(bool p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
}
function log(bool p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
}
function log(bool p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
}
function log(bool p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
}
function log(bool p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
}
function log(bool p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
}
function log(bool p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
}
function log(bool p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
}
function log(bool p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
}
function log(bool p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
}
function log(bool p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
}
function log(bool p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
}
function log(bool p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
}
function log(bool p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
}
function log(address p0, uint256 p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
}
function log(address p0, uint256 p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
}
function log(address p0, uint256 p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
}
function log(address p0, uint256 p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
}
function log(address p0, string memory p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
}
function log(address p0, string memory p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
}
function log(address p0, string memory p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
}
function log(address p0, string memory p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
}
function log(address p0, bool p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
}
function log(address p0, bool p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
}
function log(address p0, bool p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
}
function log(address p0, bool p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
}
function log(address p0, address p1, uint256 p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
}
function log(address p0, address p1, string memory p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
}
function log(address p0, address p1, bool p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
}
function log(address p0, address p1, address p2) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
}
function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
}
function log(uint256 p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
}
function log(string memory p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
}
function log(bool p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
}
function log(address p0, uint256 p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
}
function log(address p0, string memory p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
}
function log(address p0, bool p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, uint256 p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, string memory p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, bool p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, uint256 p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, string memory p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, bool p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
}
function log(address p0, address p1, address p2, address p3) internal pure {
_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"contract IModuleRegistry","name":"_registry","type":"address"},{"internalType":"contract IGuardianStorage","name":"_guardianStorage","type":"address"},{"internalType":"contract ITransferStorage","name":"_userWhitelist","type":"address"},{"internalType":"contract IAuthoriser","name":"_authoriser","type":"address"},{"internalType":"uint256","name":"_securityPeriod","type":"uint256"},{"internalType":"uint256","name":"_securityWindow","type":"uint256"},{"internalType":"uint256","name":"_recoveryPeriod","type":"uint256"},{"internalType":"uint256","name":"_lockPeriod","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint64","name":"whitelistAfter","type":"uint64"}],"name":"AddedToWhitelist","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianAdditionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"executeAfter","type":"uint256"}],"name":"GuardianAdditionRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRevokationCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"executeAfter","type":"uint256"}],"name":"GuardianRevokationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint64","name":"releaseAfter","type":"uint64"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"ModuleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransfered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"}],"name":"RecoveryCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"},{"indexed":false,"internalType":"uint64","name":"executeAfter","type":"uint64"}],"name":"RecoveryExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_recovery","type":"address"}],"name":"RecoveryFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"refundAddress","type":"address"},{"indexed":false,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"}],"name":"RemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"sessionKey","type":"address"}],"name":"SessionCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"address","name":"sessionKey","type":"address"},{"indexed":false,"internalType":"uint64","name":"expires","type":"uint64"}],"name":"SessionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"signedHash","type":"bytes32"}],"name":"TransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Unlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newImplementation","type":"address"}],"name":"WalletUpgraded","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"addGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_module","type":"address"}],"name":"addModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"cancelGuardianAddition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"cancelGuardianRevokation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"cancelRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"clearSession","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"confirmGuardianAddition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"confirmGuardianRevokation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_recovery","type":"address"}],"name":"executeRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"finalizeRecovery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getGuardians","outputs":[{"internalType":"address[]","name":"_guardians","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getLock","outputs":[{"internalType":"uint64","name":"_releaseAfter","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getRecovery","outputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"uint64","name":"_executeAfter","type":"uint64"},{"internalType":"uint32","name":"_guardianCount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getRequiredSignatures","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum BaseModule.OwnerSignature","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"getSession","outputs":[{"internalType":"address","name":"key","type":"address"},{"internalType":"uint64","name":"expires","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"guardianCount","outputs":[{"internalType":"uint256","name":"_count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bytes32","name":"_signHash","type":"bytes32"}],"name":"isExecutedTx","outputs":[{"internalType":"bool","name":"executed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"isGuardian","outputs":[{"internalType":"bool","name":"_isGuardian","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSignatureModule","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_msgHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"_userOp","type":"tuple"},{"internalType":"bytes32","name":"_userOpHash","type":"bytes32"}],"name":"isValidSignature","outputs":[{"internalType":"uint256","name":"validationData","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"_isWhitelisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCallWithGuardians","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"},{"internalType":"address","name":"_sessionUser","type":"address"},{"internalType":"uint64","name":"_duration","type":"uint64"}],"name":"multiCallWithGuardiansAndStartSession","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct EnterpriseTransactionManager.Call[]","name":"_transactions","type":"tuple[]"}],"name":"multiCallWithSession","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_target","type":"address"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_guardian","type":"address"}],"name":"revokeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_methodId","type":"bytes4"}],"name":"supportsStaticCall","outputs":[{"internalType":"bool","name":"_isSupported","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"address","name":"_newImplementation","type":"address"}],"name":"upgradeWallet","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6102806040523480156200001257600080fd5b5060405162005fc838038062005fc883398101604081905262000035916200039c565b83828585846040518060400160405280600c81526020016b52656c617965724b6e6f627360a01b81525080604051806040016040528060018152602001603160f81b8152508f8f8f8f6f456e74657270726973654d6f64756c6560801b846001600160a01b03166080816001600160a01b031681525050836001600160a01b031660a0816001600160a01b031681525050826001600160a01b031660c0816001600160a01b031681525050816001600160a01b031660e0816001600160a01b0316815250507f3019c8fc80239e3dff8f781212ae2004839c2cb61d6c70acd279ac65392145df816040516200012c91815260200190565b60405180910390a1505050505062000154600283620002ed60201b620035e41790919060201c565b6101a05262000171816003620002ed602090811b620035e417901c565b6101c052815160208084019190912061016052815190820120610180524661012052620002026101605161018051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b61010052505030610140525083811015620002645760405162461bcd60e51b815260206004820152601860248201527f534d3a20696e736563757265206c6f636b20706572696f64000000000000000060448201526064015b60405180910390fd5b6200027082846200042b565b841015620002c15760405162461bcd60e51b815260206004820152601d60248201527f534d3a20696e73656375726520736563757269747920706572696f647300000060448201526064016200025b565b6101e0939093526102009290925261024091909152610220526102605250620006339650505050505050565b60006020835110156200030d5762000305836200033d565b905062000337565b8262000324836200038060201b620036151760201c565b90620003319082620004f2565b5060ff90505b92915050565b600080829050601f815111156200036b578260405163305a27a960e01b81526004016200025b9190620005be565b805162000378826200060e565b179392505050565b90565b6001600160a01b03811681146200039957600080fd5b50565b600080600080600080600080610100898b031215620003ba57600080fd5b8851620003c78162000383565b60208a0151909850620003da8162000383565b60408a0151909750620003ed8162000383565b60608a0151909650620004008162000383565b60808a015160a08b015160c08c015160e0909c01519a9d999c50979a91999098919650945092505050565b808201808211156200033757634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200047857607f821691505b6020821081036200049957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004ed57600081815260208120601f850160051c81016020861015620004c85750805b601f850160051c820191505b81811015620004e957828155600101620004d4565b5050505b505050565b81516001600160401b038111156200050e576200050e6200044d565b62000526816200051f845462000463565b846200049f565b602080601f8311600181146200055e5760008415620005455750858301515b600019600386901b1c1916600185901b178555620004e9565b600085815260208120601f198616915b828110156200058f578886015182559484019460019091019084016200056e565b5085821015620005ae5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620005ed57858101830151858201604001528201620005cf565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620004995760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e0516102005161022051610240516102605161585c6200076c60003960006119590152600081816109de0152818161159e01528181611e1f0152612f5a015260008181610a5701528181610abf01528181612fd3015261303b015260008181612b010152818161349401526134f6015260006129ab0152600061232d01526000612302015260006147820152600061475a015260006146b5015260006146df0152600061470901526000505060008181612bb10152613d58015260008181611638015281816116ff01528181611eb901528181612a15015281816132860152818161339701528181613c7b0152613fce01526000818161184301528181611a4a0152612510015261585c6000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c806384b0196e1161013b578063b6b35272116100b8578063d4ee97341161007c578063d4ee9734146106db578063f143ddba146106ee578063f18858ab14610701578063f435f5a714610721578063f8d3277d1461073457610248565b8063b6b352721461067c578063ba8210881461068f578063c6845210146106a2578063c90db447146106b5578063d4bfea48146106c857610248565b80639be65a60116100ff5780639be65a6014610616578063a3f4df7e14610629578063a5efb23514610643578063a6eb069014610656578063b0ba4da01461066957610248565b806384b0196e146104fa578063873bd184146105155780638c8e13b91461051c5780639769c3fe146105835780639add38d51461060357610248565b80634b3ef054116101c95780636b9db4e61161018d5780636b9db4e6146104835780636d435421146104ae5780636ff6ec7c146104c157806370135f52146104d45780637d1c2e78146104e757610248565b80634b3ef054146103f05780635040fb761461040357806357518243146104245780635a1db8c41461043757806360c0fdc01461044a57610248565b80632960739b116102105780632960739b146103835780632f6c493c14610396578063315a7af3146103a95780633b73d67f146103bc5780634a4fbeec146103dd57610248565b80631626ba7e146102e957806319ab453c1461031a5780631d97d8cc1461032d5780632437b75c1461034057806325b5093414610360575b600061028a6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b03198116630a85bd0160e11b14806102bb57506001600160e01b0319811663f23a6e6160e01b145b806102d657506001600160e01b0319811663bc197c8160e01b145b156102e75760046000803760206000f35b005b6102fc6102f7366004614c76565b6107a8565b6040516001600160e01b031990911681526020015b60405180910390f35b6102e7610328366004614d14565b610881565b6102e761033b366004614d31565b6108e7565b61035361034e366004614dae565b610afd565b6040516103119190614e84565b61037361036e366004614ee6565b610b66565b6040519015158152602001610311565b6102e7610391366004614d31565b610bed565b6102e76103a4366004614d14565b610d34565b6102e76103b7366004614d14565b610ea1565b6103cf6103ca366004614f51565b611065565b604051610311929190614fbb565b6103736103eb366004614d14565b611483565b6102e76103fe366004614d31565b61148e565b610416610411366004614d14565b6116dd565b604051908152602001610311565b6102e7610432366004614d31565b61176c565b6102e7610445366004614d31565b6119d4565b610373610458366004614fed565b6001600160a01b03919091166000908152600460209081526040808320938352929052205460ff1690565b610496610491366004614d14565b611b69565b6040516001600160401b039091168152602001610311565b6102e76104bc366004614d31565b611ba4565b6103536104cf366004615019565b611c8c565b6102e76104e2366004614d31565b611ce8565b6103736104f5366004615060565b611f5f565b6105026122f4565b60405161031197969594939291906150f5565b6001610373565b61055c61052a366004614d14565b6001600160a01b0390811660009081526020819052604090205490811691600160a01b9091046001600160401b031690565b604080516001600160a01b0390931683526001600160401b03909116602083015201610311565b6105d0610591366004614d14565b6001600160a01b0390811660009081526005602052604090205490811691600160a01b82046001600160401b031691600160e01b900463ffffffff1690565b604080516001600160a01b0390941684526001600160401b03909216602084015263ffffffff1690820152606001610311565b61041661061136600461518b565b61237d565b6102e7610624366004614d14565b61248e565b6104166f456e74657270726973654d6f64756c6560801b81565b610353610651366004615019565b612595565b6102e7610664366004614d31565b6127c5565b6102e7610677366004614d31565b61290c565b61037361068a366004614d31565b612b85565b6102e761069d366004614d14565b612c35565b6102e76106b0366004614d31565b612ce6565b6102e76106c3366004614d14565b61307a565b6102e76106d6366004614d31565b61317e565b6103736106e9366004614d31565b61325c565b6103536106fc366004615019565b6132fa565b61071461070f366004614d14565b613375565b60405161031191906151c7565b6102e761072f366004614d14565b613408565b6102e7610742366004614d31565b61353b565b60006004825110156107a05760405162461bcd60e51b815260206004820152601d60248201527f5574696c733a20496e76616c69642066756e6374696f6e50726566697800000060448201526064015b60405180910390fd5b506020015190565b600081516041146107fb5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20696e76616c6964207369676e6174757265206c656e677468000000006044820152606401610797565b600061080984846000613618565b9050610815338261374d565b6108565760405162461bcd60e51b81526020600482015260126024820152712a269d1024b73b30b634b21039b4b3b732b960711b6044820152606401610797565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b80336001600160a01b038216146108da5760405162461bcd60e51b815260206004820152601960248201527f424d3a2063616c6c6572206d7573742062652077616c6c6574000000000000006044820152606401610797565b6108e3826137cc565b5050565b81303314806108fe5750336001600160a01b038216145b61091a5760405162461bcd60e51b815260040161079790615214565b610924838361325c565b6109705760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d757374206265206578697374696e6720677561726469616e0000006044820152606401610797565b6000838360405160200161098592919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b0387166000908152600684528281208282529384905291909120549092501580610a065750600082815260208290526040902054610a03907f000000000000000000000000000000000000000000000000000000000000000090615296565b42115b610a525760405162461bcd60e51b815260206004820152601c60248201527f534d3a206475706c69636174652070656e64696e67207265766f6b65000000006044820152606401610797565b610a7c7f000000000000000000000000000000000000000000000000000000000000000042615296565b6000838152602083905260409020556001600160a01b038085169086167f9746f6868f544595794833da53250bd19e72334733336cfd5dd6fbc5f6a6ac42610ae47f000000000000000000000000000000000000000000000000000000000000000042615296565b6040519081526020015b60405180910390a35050505050565b6060303314610b1e5760405162461bcd60e51b8152600401610797906152a9565b85610b2881613835565b15610b455760405162461bcd60e51b8152600401610797906152d5565b610b5087858561385e565b610b5b8787876139cb565b979650505050505050565b60006001600160e01b03198216630b135d3f60e11b1480610b9757506001600160e01b03198216630a85bd0160e11b145b80610bb257506001600160e01b031982166301ffc9a760e01b145b80610bcd57506001600160e01b0319821663f23a6e6160e01b145b8061087b57506001600160e01b0319821663bc197c8160e01b1492915050565b8130331480610c045750336001600160a01b038216145b610c205760405162461bcd60e51b815260040161079790615214565b82610c2a81613835565b15610c475760405162461bcd60e51b8152600401610797906152d5565b60008484604051602001610c5c92919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b038816600090815260068452828120828252938490529190912054909250610ce55760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917fc0b205956d5e27c296695de329b5a014584a4f51824b1725a0eefc1174d6dbd59190a3505050505050565b8030331480610d485750610d48813361325c565b610d905760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b81610d9a81613835565b610de65760405162461bcd60e51b815260206004820152601960248201527f424d3a2077616c6c6574206d757374206265206c6f636b6564000000000000006044820152606401610797565b6001600160a01b038316600090815260016020526040902054600160401b900460e01b6001600160e01b03191663f435f5a760e01b14610e5c5760405162461bcd60e51b8152602060048201526011602482015270534d3a2063616e6e6f7420756e6c6f636b60781b6044820152606401610797565b610e6883600080613bb3565b6040516001600160a01b038416907f7e6adfec7e3f286831a0200a754127c171a2da564078722cb97704741bbdb0ea90600090a2505050565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b0316610f125760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b038216600090815260056020526040902080546001600160401b03600160a01b90910481164290911611610f8f5760405162461bcd60e51b815260206004820152601b60248201527f534d3a206f6e676f696e67207265636f7665727920706572696f6400000000006044820152606401610797565b80546001600160a01b0384811660009081526005602052604081205516610fb584613c2e565b6040516313af403560e01b81526001600160a01b0382811660048301528516906313af403590602401600060405180830381600087803b158015610ff857600080fd5b505af115801561100c573d6000803e3d6000fd5b5050505061101f8460008060e01b613bb3565b806001600160a01b0316846001600160a01b03167fd8667de85dae2d56d76e700d16de53d21ac2ce4d5549cb0bf51c55fdc37f0bc160405160405180910390a350505050565b60008060006110a985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b0319811663a5efb23560e01b14806110da57506001600160e01b03198116635751824360e01b145b806110f557506001600160e01b0319811663f8d3277d60e01b145b8061111057506001600160e01b03198116631750421160e31b145b1561113f576001600160a01b038616330361113257600080925092505061147b565b600180925092505061147b565b63240244e160e21b6001600160e01b0319821601611183576001600160a01b03861633036111755760006004925092505061147b565b60016004925092505061147b565b63027a2d9360e51b6001600160e01b03198216016112055760006111a687613c55565b9050600081116111f85760405162461bcd60e51b815260206004820152601e60248201527f414d3a206e6f20677561726469616e7320736574206f6e2077616c6c657400006044820152606401610797565b92506003915061147b9050565b6336f24bb960e01b6001600160e01b0319821601611296576001600160a01b03861660009081526005602052604081205461125f9061125290600160e01b900463ffffffff166001615300565b63ffffffff166002613ce9565b90506001600160a01b03871633036112895761127c60018261531d565b600393509350505061147b565b92506002915061147b9050565b6001600160e01b03198116630c68452160e41b14806112c557506001600160e01b03198116630765f63360e21b145b806112e057506001600160e01b03198116630a6eb06960e41b145b806112fb57506001600160e01b03198116632960739b60e01b145b8061131657506001600160e01b03198116636d43542160e01b145b8061133157506001600160e01b031981166316876e3160e21b145b8061134c57506001600160e01b03198116631a97fd4960e31b145b8061136757506001600160e01b031981166378a1eedd60e11b145b8061138257506001600160e01b0319811663090dedd760e21b145b156113a057600061139287613c55565b93506003925061147b915050565b6001600160e01b0319811663315a7af360e01b14806113cf57506001600160e01b03198116633809afa960e11b145b806113ea57506001600160e01b031981166312cfbc1560e21b145b156113fc57600080925092505061147b565b6001600160e01b0319811663f435f5a760e01b148061142b57506001600160e01b03198116630bdb124f60e21b145b1561143e5760016003925092505061147b565b60405162461bcd60e51b815260206004820152601260248201527114d34e881d5b9adb9bdddb881b595d1a1bd960721b6044820152606401610797565b935093915050565b600061087b82613835565b600082826040516020016114a392919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b03861660009081526006845282812082825293849052919091205490925061152c5760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b60008281526020829052604090205442116115895760405162461bcd60e51b815260206004820152601b60248201527f534d3a2070656e64696e67207265766f6b65206e6f74206f76657200000000006044820152606401610797565b6000828152602082905260409020546115c3907f000000000000000000000000000000000000000000000000000000000000000090615296565b42106116115760405162461bcd60e51b815260206004820152601a60248201527f534d3a2070656e64696e67207265766f6b6520657870697265640000000000006044820152606401610797565b604051630765f63360e21b81526001600160a01b03858116600483015284811660248301527f00000000000000000000000000000000000000000000000000000000000000001690631d97d8cc90604401600060405180830381600087803b15801561167c57600080fd5b505af1158015611690573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f548f10dcba266544123ad8cf8284f25c4baa659cba25dbdf16a06ea11235de9b90600090a3600091825260205260408120555050565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635040fb7690602401602060405180830381865afa158015611748573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087b9190615330565b81303314806117805750611780813361374d565b61179c5760405162461bcd60e51b815260040161079790615349565b826117a681613835565b156117c35760405162461bcd60e51b8152600401610797906152d5565b836001600160a01b0316836001600160a01b0316036118245760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c6973742077616c6c657400000000006044820152606401610797565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630bcd4ebb90602401602060405180830381865afa15801561188a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ae9190615380565b156118fb5760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c697374206d6f64756c6500000000006044820152606401610797565b6119058484612b85565b156119525760405162461bcd60e51b815260206004820152601e60248201527f544d3a2074617267657420616c72656164792077686974656c697374656400006044820152606401610797565b600061197e7f000000000000000000000000000000000000000000000000000000000000000042615296565b905061198b858583613d2a565b6040516001600160401b03821681526001600160a01b0380861691908716907f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd90602001610aee565b81303314806119e857506119e8813361374d565b611a045760405162461bcd60e51b815260040161079790615349565b82611a0e81613835565b15611a2b5760405162461bcd60e51b8152600401610797906152d5565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f00000000000000000000000000000000000000000000000000000000000000001690630bcd4ebb90602401602060405180830381865afa158015611a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab59190615380565b611b015760405162461bcd60e51b815260206004820152601c60248201527f414d3a206d6f64756c65206973206e6f742072656769737465726564000000006044820152606401610797565b604051631f17732d60e01b81526001600160a01b03848116600483015260016024830152851690631f17732d90604401600060405180830381600087803b158015611b4b57600080fd5b505af1158015611b5f573d6000803e3d6000fd5b5050505050505050565b6000611b7482613835565b611b7f57600061087b565b506001600160a01b03166000908152600160205260409020546001600160401b031690565b303314611bc35760405162461bcd60e51b8152600401610797906152a9565b81611bcd81613835565b15611bea5760405162461bcd60e51b8152600401610797906152d5565b611bf48383613db9565b6040516313af403560e01b81526001600160a01b0383811660048301528416906313af403590602401600060405180830381600087803b158015611c3757600080fd5b505af1158015611c4b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6790600090a3505050565b6060303314611cad5760405162461bcd60e51b8152600401610797906152a9565b83611cb781613835565b15611cd45760405162461bcd60e51b8152600401610797906152d5565b611cdf8585856139cb565b95945050505050565b81611cf281613835565b15611d0f5760405162461bcd60e51b8152600401610797906152d5565b60008383604051602001611d249291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b038716600090815260068452828120828252938490529190912054909250611dad5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b6000828152602082905260409020544211611e0a5760405162461bcd60e51b815260206004820152601d60248201527f534d3a2070656e64696e67206164646974696f6e206e6f74206f7665720000006044820152606401610797565b600082815260208290526040902054611e44907f000000000000000000000000000000000000000000000000000000000000000090615296565b4210611e925760405162461bcd60e51b815260206004820152601c60248201527f534d3a2070656e64696e67206164646974696f6e2065787069726564000000006044820152606401610797565b604051630c68452160e41b81526001600160a01b03868116600483015285811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063c684521090604401600060405180830381600087803b158015611efd57600080fd5b505af1158015611f11573d6000803e3d6000fd5b50506040516001600160a01b038088169350881691507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a90600090a360009182526020526040812055505050565b6000611f6c888888613e66565b611fb85760405162461bcd60e51b815260206004820152601e60248201527f524d3a20546172676574206f66205f6461746120213d205f77616c6c657400006044820152606401610797565b611fc188613835565b1561200e5760405162461bcd60e51b815260206004820152601860248201527f524d3a204c6f636b65642077616c6c657420726566756e6400000000000000006044820152606401610797565b600080600060606120208c8c8c611065565b9094509250831515806120445750600083600481111561204257612042614fa5565b145b6120905760405162461bcd60e51b815260206004820152601f60248201527f524d3a2057726f6e67207369676e617475726520726571756972656d656e74006044820152606401610797565b8561209c8560416153d5565b146120e95760405162461bcd60e51b815260206004820152601e60248201527f524d3a2057726f6e67206e756d626572206f66207369676e61747572657300006044820152606401610797565b60007fbf1af91af6bb21cb6f3df695a3f72929c8cc95124bb13aad4c9d2ff670a214318d8d8d60405161211d9291906153ec565b60405190819003812061215f9392918e908e906020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604051602081830303815290604052805190602001209050600061218282613ee7565b9050600485600481111561219857612198614fa5565b036121ed576121a68e613f14565b6121e85760405162461bcd60e51b815260206004820152601360248201527229269d1024b73b30b634b21039b2b9b9b4b7b760691b6044820152606401610797565b61223f565b6121fa8e828b8b89613f74565b61223f5760405162461bcd60e51b8152602060048201526016602482015275524d3a20496e76616c6964207369676e61747572657360501b6044820152606401610797565b6040513090612251908f908f906153ec565b6000604051808303816000865af19150503d806000811461228e576040519150601f19603f3d011682016040523d82523d6000602084013e612293565b606091505b5080945081955050508315158e6001600160a01b03167f7da4525a280527268ba2e963ee6c1b18f43c9507bcb1d2560f652ab17c76e90a85846040516122da9291906153fc565b60405180910390a350919c9b505050505050505050505050565b6000606080828080836123287f000000000000000000000000000000000000000000000000000000000000000060026142c8565b6123537f000000000000000000000000000000000000000000000000000000000000000060036142c8565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c829052603c81206000336001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612410919061541e565b905061246061242361014087018761543b565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869392505061436c9050565b6001600160a01b0316816001600160a01b0316146124835760019250505061087b565b506000949350505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156124d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f99190615330565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390529192509083169063a9059cbb906044016020604051808303816000875af115801561256c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125909190615380565b505050565b60603033146125b65760405162461bcd60e51b8152600401610797906152a9565b836125c081613835565b156125dd5760405162461bcd60e51b8152600401610797906152d5565b6000836001600160401b038111156125f7576125f7614c09565b60405190808252806020026020018201604052801561262a57816020015b60608152602001906001900390816126155790505b50905060005b848110156127bb573086868381811061264b5761264b615481565b905060200281019061265d9190615497565b61266b906020810190614d14565b6001600160a01b0316036126c15760405162461bcd60e51b815260206004820152601760248201527f544d3a2063616c6c206e6f7420617574686f72697365640000000000000000006044820152606401610797565b61278b878787848181106126d7576126d7615481565b90506020028101906126e99190615497565b6126f7906020810190614d14565b88888581811061270957612709615481565b905060200281019061271b9190615497565b6020013589898681811061273157612731615481565b90506020028101906127439190615497565b61275190604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061439092505050565b82828151811061279d5761279d615481565b602002602001018190525080806127b3906154b7565b915050612630565b5095945050505050565b81303314806127dc5750336001600160a01b038216145b6127f85760405162461bcd60e51b815260040161079790615214565b8261280281613835565b1561281f5760405162461bcd60e51b8152600401610797906152d5565b600084846040516020016128349291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0388166000908152600684528281208282529384905291909120549092506128bd5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917faa13b27c23e9e3f3d5f3861a53b7a2931e019170a6a19ed64942e26a1dd5987a9190a3505050505050565b30331461292b5760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0382166000908152600560205260409020548290600160a01b90046001600160401b03161561299a5760405162461bcd60e51b8152602060048201526014602482015273534d3a206f6e676f696e67207265636f7665727960601b6044820152606401610797565b6129a48383613db9565b60006129d07f000000000000000000000000000000000000000000000000000000000000000042615296565b604080516060810182526001600160a01b0380871682526001600160401b038416602083015282516328207dbb60e11b815288821660048201529394509092918301917f000000000000000000000000000000000000000000000000000000000000000090911690635040fb7690602401602060405180830381865afa158015612a5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a829190615330565b63ffffffff9081169091526001600160a01b0380871660009081526005602090815260409182902085518154928701519690930151909416600160e01b026001600160e01b036001600160401b03909616600160a01b026001600160e01b031990921692909316919091171792909216919091179055612b3384612b267f000000000000000000000000000000000000000000000000000000000000000042615296565b630585d26d60e51b613bb3565b6040516001600160401b03821681526001600160a01b0380851691908616907f5f59bfd9baba55ae30bb440923cbbe30987d50e12a4e9134ffac3fd9afc3526d9060200160405180910390a350505050565b6040516309fa507560e11b81526001600160a01b038381166004830152828116602483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906313f4a0ea90604401602060405180830381865afa158015612bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1c9190615330565b9050600081118015612c2d57504281105b949350505050565b8030331480612c495750612c49813361374d565b612c655760405162461bcd60e51b815260040161079790615349565b81612c6f81613835565b15612c8c5760405162461bcd60e51b8152600401610797906152d5565b6001600160a01b038381166000818152602081815260409182902054915191909316815290917feb290a597820eccc6b8b31f942bd97c633d5138f4d849751f770f3cb3900e57a910160405180910390a261259083613c2e565b8130331480612cfd5750336001600160a01b038216145b612d195760405162461bcd60e51b815260040161079790615214565b82612d2381613835565b15612d405760405162461bcd60e51b8152600401610797906152d5565b612d6c6040518060400160405280600b81526020016a30b23223bab0b93234b0b760a91b8152506144e8565b612d76848461374d565b15612dc35760405162461bcd60e51b815260206004820152601c60248201527f534d3a20677561726469616e2063616e6e6f74206265206f776e6572000000006044820152606401610797565b612dcd848461325c565b15612e135760405162461bcd60e51b815260206004820152601660248201527529a69d10323ab83634b1b0ba329033bab0b93234b0b760511b6044820152606401610797565b60408051600481526024810182526020810180516001600160e01b0316638da5cb5b60e01b17905290516000916001600160a01b038616916161a891612e58916154d0565b60006040518083038160008787f1925050503d8060008114612e96576040519150601f19603f3d011682016040523d82523d6000602084013e612e9b565b606091505b5050905080612eec5760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d75737420626520454f412f417267656e742077616c6c65740000006044820152606401610797565b60008585604051602001612f019291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0389166000908152600684528281208282529384905291909120549092501580612f825750600082815260208290526040902054612f7f907f000000000000000000000000000000000000000000000000000000000000000090615296565b42115b612fce5760405162461bcd60e51b815260206004820152601e60248201527f534d3a206475706c69636174652070656e64696e67206164646974696f6e00006044820152606401610797565b612ff87f000000000000000000000000000000000000000000000000000000000000000042615296565b6000838152602083905260409020556001600160a01b038087169088167fe4166e4bc55a182bd13d933553241bb3441b91d15fbc74c5c752f96965563bde6130607f000000000000000000000000000000000000000000000000000000000000000042615296565b60405190815260200160405180910390a350505050505050565b3033146130995760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b031661310a5760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b0380831660009081526005602052604081208054908290559091169061313990849080613bb3565b806001600160a01b0316836001600160a01b03167fc45926607303da71dbeffd2ed5c6b00f581982586b697655d19ae4c4d558f25960405160405180910390a3505050565b30331461319d5760405162461bcd60e51b8152600401610797906152a9565b816131a781613835565b156131c45760405162461bcd60e51b8152600401610797906152d5565b604051631b2ce7f360e11b81526001600160a01b038381166004830152841690633659cfe690602401600060405180830381600087803b15801561320757600080fd5b505af115801561321b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f5c92b3979a73cef77d1416cc6817a9094d4fd8d62e4d93189c8e2b06c5c5919790600090a3505050565b60405163353ba5cd60e21b81526001600160a01b03838116600483015282811660248301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063d4ee973490604401602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f39190615380565b9392505050565b606030331461331b5760405162461bcd60e51b8152600401610797906152a9565b8361332581613835565b156133425760405162461bcd60e51b8152600401610797906152d5565b61336c604051806040016040528060098152602001681b5d5b1d1a50d85b1b60ba1b8152506144e8565b611cd48361452e565b60405163f18858ab60e01b81526001600160a01b0382811660048301526060917f00000000000000000000000000000000000000000000000000000000000000009091169063f18858ab90602401600060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261087b91908101906154e2565b803033148061341c575061341c813361325c565b6134645760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b8161346e81613835565b1561348b5760405162461bcd60e51b8152600401610797906152d5565b6134c6836134b97f000000000000000000000000000000000000000000000000000000000000000042615296565b63f435f5a760e01b613bb3565b6001600160a01b0383167f6395bace6e0acbe4f22761b149d3cc2e88c7dde6bf4d8481825eef404cf989a161351b7f000000000000000000000000000000000000000000000000000000000000000042615296565b6040516001600160401b03909116815260200160405180910390a2505050565b813033148061354f575061354f813361374d565b61356b5760405162461bcd60e51b815260040161079790615349565b8261357581613835565b156135925760405162461bcd60e51b8152600401610797906152d5565b61359e84846000613d2a565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6000602083511015613600576135f983614573565b905061087b565b8161360b848261561b565b5060ff905061087b565b90565b6041808202830160208101516040820151919092015160009260ff9190911691601b83148061364a57508260ff16601c145b6136965760405162461bcd60e51b815260206004820152601f60248201527f5574696c733a2062616420762076616c756520696e207369676e6174757265006044820152606401610797565b604080516000808252602082018084528a905260ff861692820192909252606081018490526080810183905260019060a0016020604051602081039080840390855afa1580156136ea573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b5b5760405162461bcd60e51b815260206004820152601b60248201527f5574696c733a2065637265636f7665722072657475726e6564203000000000006044820152606401610797565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bb919061541e565b6001600160a01b0316149392505050565b6040516309ed185960e11b8152306004820152630b135d3f60e11b60248201526001600160a01b038216906313da30b290604401600060405180830381600087803b15801561381a57600080fd5b505af115801561382e573d6000803e3d6000fd5b5050505050565b6001600160a01b03166000908152600160205260409020546001600160401b0342811691161190565b6001600160a01b0382166138b45760405162461bcd60e51b815260206004820152601860248201527f544d3a20496e76616c69642073657373696f6e207573657200000000000000006044820152606401610797565b6000816001600160401b03161161390d5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20496e76616c69642073657373696f6e206475726174696f6e000000006044820152606401610797565b600061392a6139256001600160401b03841642615296565b6145b1565b6040805180820182526001600160a01b038681168083526001600160401b0385811660208086018281528c86166000818152808452899020975188549251909516600160a01b026001600160e01b031990921694909616939093179290921790945584519182528101929092529293507f2ecea11087d1dc1431b517cbb5a559a9e33e58a1afeaac288f782c1c8bed8b8a910160405180910390a250505050565b60606000826001600160401b038111156139e7576139e7614c09565b604051908082528060200260200182016040528015613a1a57816020015b6060815260200190600190039081613a055790505b509050613a268361452e565b60005b83811015613baa57613a6b858583818110613a4657613a46615481565b9050602002810190613a589190615497565b613a66906020810190614d14565b61461d565b613ada858583818110613a8057613a80615481565b9050602002810190613a929190615497565b613aa090604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061466592505050565b613b0a858583818110613aef57613aef615481565b9050602002810190613b019190615497565b6020013561452e565b613b7a86868684818110613b2057613b20615481565b9050602002810190613b329190615497565b613b40906020810190614d14565b878785818110613b5257613b52615481565b9050602002810190613b649190615497565b6020013588888681811061273157612731615481565b828281518110613b8c57613b8c615481565b60200260200101819052508080613ba2906154b7565b915050613a29565b50949350505050565b6040518060400160405280613bc7846145b1565b6001600160401b0390811682526001600160e01b03199093166020918201526001600160a01b039094166000908152600185526040902081518154929095015160e01c600160401b026001600160601b031990921694909216939093179290921790915550565b6001600160a01b0316600090815260208190526040902080546001600160e01b0319169055565b6040516328207dbb60e11b81526001600160a01b03828116600483015260009161087b917f00000000000000000000000000000000000000000000000000000000000000001690635040fb7690602401602060405180830381865afa158015613cc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce69190615330565b60025b600080613cf683856156f0565b9050613d028385615704565b600003613d1057905061087b565b613d1b816001615296565b91505061087b565b5092915050565b604051631017f7cd60e31b81526001600160a01b0384811660048301528381166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906380bfbe6890606401600060405180830381600087803b158015613d9c57600080fd5b505af1158015613db0573d6000803e3d6000fd5b50505050505050565b6001600160a01b038116613e0f5760405162461bcd60e51b815260206004820152601c60248201527f534d3a206e6577206f776e65722063616e6e6f74206265206e756c6c000000006044820152606401610797565b613e19828261325c565b156108e35760405162461bcd60e51b815260206004820181905260248201527f534d3a206e6577206f776e65722063616e6e6f7420626520677561726469616e6044820152606401610797565b60006024821015613eb25760405162461bcd60e51b815260206004820152601660248201527514934e88125b9d985b1a590819185d1855d85b1b195d60521b6044820152606401610797565b6000613ec18360048187615718565b810190613ece9190614d14565b6001600160a01b03908116908616149150509392505050565b600061087b613ef46146a8565b8360405161190160f01b8152600281019290925260228201526042902090565b6001600160a01b038181166000818152602081815260408083208151808301909252549485168152600160a01b9094046001600160401b0316908401529190331480156132f357504281602001516001600160401b031610159392505050565b6000828103613f8557506001611cdf565b600060606001846004811115613f9d57613f9d614fa5565b141580613faa5750604185115b156140405760405163f18858ab60e01b81526001600160a01b0389811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063f18858ab90602401600060405180830381865afa158015614015573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261403d91908101906154e2565b90505b6001600160a01b03881660009081526004602090815260408083208a845290915290205460ff16156140c85760405162461bcd60e51b815260206004820152602b60248201527f524d3a2076616c69646174655369676e6174757265733a20747820616c72656160448201526a191e48195e1958dd5d195960aa1b6064820152608401610797565b60005b6140d66041876156f0565b8110156142b95760408051604180825260808201909252600091602082018180368337019050509050876041830201604181602084013750816000036141e25760006141848b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417d919061541e565b8b846147d8565b9050600187600481111561419a5761419a614fa5565b036141ba5780156141ac5750506142a7565b600095505050505050611cdf565b60028760048111156141ce576141ce614fa5565b036141e05780156141e05750506142a7565b505b6000805b84518110156142905761421385828151811061420457614204615481565b60200260200101518c856147d8565b1561427e57856001600160a01b031685828151811061423457614234615481565b60200260200101516001600160a01b0316116142595760009650505050505050611cdf565b84818151811061426b5761426b615481565b6020026020010151955060019150614290565b80614288816154b7565b9150506141e6565b50806142a457600095505050505050611cdf565b50505b806142b1816154b7565b9150506140cb565b50600198975050505050505050565b606060ff83146142db576135f983614839565b8180546142e790615593565b80601f016020809104026020016040519081016040528092919081815260200182805461431390615593565b80156143605780601f1061433557610100808354040283529160200191614360565b820191906000526020600020905b81548152906001019060200180831161434357829003601f168201915b5050505050905061087b565b600080600061437b8585614878565b91509150614388816148bd565b509392505050565b606060006143c16040518060400160405280600c81526020016b1a5b9d9bdad955d85b1b195d60a21b8152506144e8565b856001600160a01b03168585856040516024016143e093929190615742565b60408051601f198184030181529181526020820180516001600160e01b03166347b7819960e11b1790525161441591906154d0565b6000604051808303816000865af19150503d8060008114614452576040519150601f19603f3d011682016040523d82523d6000602084013e614457565b606091505b509250905080801561446a575060008251115b1561448a57818060200190518101906144839190615769565b9150613baa565b81511561449b573d6000803e3d6000fd5b80613baa5760405162461bcd60e51b815260206004820152601a60248201527f424d3a2077616c6c657420696e766f6b652072657665727465640000000000006044820152606401610797565b61452b816040516024016144fc91906157d6565b60408051601f198184030181529190526020810180516001600160e01b031663104c13eb60e21b179052614a07565b50565b61452b8160405160240161454491815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663f82c50f160e01b179052614a07565b600080829050601f8151111561459e578260405163305a27a960e01b815260040161079791906157d6565b80516145a9826157e9565b179392505050565b60006001600160401b038211156146195760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610797565b5090565b6040516001600160a01b038216602482015261452b9060440160408051601f198184030181529190526020810180516001600160e01b031663161765e160e11b179052614a07565b61452b8160405160240161467991906157d6565b60408051601f198184030181529190526020810180516001600160e01b03166305f3bfab60e11b179052614a07565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561470157507f000000000000000000000000000000000000000000000000000000000000000046145b1561472b57507f000000000000000000000000000000000000000000000000000000000000000090565b6147d3604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b60008060006147e78585614878565b9092509050600081600481111561480057614800614fa5565b14801561481e5750856001600160a01b0316826001600160a01b0316145b8061482f575061482f868686614a10565b9695505050505050565b6060600061484683614afc565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60008082516041036148ae5760208301516040840151606085015160001a6148a287828585614b24565b945094505050506148b6565b506000905060025b9250929050565b60008160048111156148d1576148d1614fa5565b036148d95750565b60018160048111156148ed576148ed614fa5565b0361493a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610797565b600281600481111561494e5761494e614fa5565b0361499b5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610797565b60038160048111156149af576149af614fa5565b0361452b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610797565b61452b81614be8565b6000806000856001600160a01b0316631626ba7e60e01b8686604051602401614a3a92919061580d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614a7891906154d0565b600060405180830381855afa9150503d8060008114614ab3576040519150601f19603f3d011682016040523d82523d6000602084013e614ab8565b606091505b5091509150818015614acc57506020815110155b801561482f57508051630b135d3f60e11b90614af19083016020908101908401615330565b149695505050505050565b600060ff8216601f81111561087b57604051632cd44ac360e21b815260040160405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b5b5750600090506003614bdf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614baf573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614bd857600060019250925050614bdf565b9150600090505b94509492505050565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614c4757614c47614c09565b604052919050565b60006001600160401b03821115614c6857614c68614c09565b50601f01601f191660200190565b60008060408385031215614c8957600080fd5b8235915060208301356001600160401b03811115614ca657600080fd5b8301601f81018513614cb757600080fd5b8035614cca614cc582614c4f565b614c1f565b818152866020838501011115614cdf57600080fd5b816020840160208301376000602083830101528093505050509250929050565b6001600160a01b038116811461452b57600080fd5b600060208284031215614d2657600080fd5b81356132f381614cff565b60008060408385031215614d4457600080fd5b8235614d4f81614cff565b91506020830135614d5f81614cff565b809150509250929050565b60008083601f840112614d7c57600080fd5b5081356001600160401b03811115614d9357600080fd5b6020830191508360208260051b85010111156148b657600080fd5b600080600080600060808688031215614dc657600080fd5b8535614dd181614cff565b945060208601356001600160401b0380821115614ded57600080fd5b614df989838a01614d6a565b909650945060408801359150614e0e82614cff565b9092506060870135908082168214614e2557600080fd5b50809150509295509295909350565b60005b83811015614e4f578181015183820152602001614e37565b50506000910152565b60008151808452614e70816020860160208601614e34565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614ed957603f19888603018452614ec7858351614e58565b94509285019290850190600101614eab565b5092979650505050505050565b600060208284031215614ef857600080fd5b81356001600160e01b0319811681146132f357600080fd5b60008083601f840112614f2257600080fd5b5081356001600160401b03811115614f3957600080fd5b6020830191508360208285010111156148b657600080fd5b600080600060408486031215614f6657600080fd5b8335614f7181614cff565b925060208401356001600160401b03811115614f8c57600080fd5b614f9886828701614f10565b9497909650939450505050565b634e487b7160e01b600052602160045260246000fd5b8281526040810160058310614fe057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000806040838503121561500057600080fd5b823561500b81614cff565b946020939093013593505050565b60008060006040848603121561502e57600080fd5b833561503981614cff565b925060208401356001600160401b0381111561505457600080fd5b614f9886828701614d6a565b600080600080600080600060a0888a03121561507b57600080fd5b873561508681614cff565b965060208801356001600160401b03808211156150a257600080fd5b6150ae8b838c01614f10565b909850965060408a0135955060608a0135945060808a01359150808211156150d557600080fd5b506150e28a828b01614f10565b989b979a50959850939692959293505050565b60ff60f81b881681526000602060e08184015261511560e084018a614e58565b8381036040850152615127818a614e58565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156151795783518352928401929184019160010161515d565b50909c9b505050505050505050505050565b6000806040838503121561519e57600080fd5b82356001600160401b038111156151b457600080fd5b8301610160818603121561500b57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156152085783516001600160a01b0316835292840192918401916001016151e3565b50909695505050505050565b60208082526017908201527f424d3a206d7573742062652077616c6c65742f73656c66000000000000000000604082015260600190565b6001600160601b0319606093841b811682529190921b166014820152693932bb37b5b0ba34b7b760b11b602882015260320190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561087b5761087b615280565b602080825260129082015271424d3a206d757374206265206d6f64756c6560701b604082015260600190565b60208082526011908201527010934e881dd85b1b195d081b1bd8dad959607a1b604082015260600190565b63ffffffff818116838216019080821115613d2357613d23615280565b8181038181111561087b5761087b615280565b60006020828403121561534257600080fd5b5051919050565b6020808252601d908201527f424d3a206d7573742062652077616c6c6574206f776e65722f73656c66000000604082015260600190565b60006020828403121561539257600080fd5b815180151581146132f357600080fd5b6001600160601b0319606093841b811682529190921b1660148201526730b23234ba34b7b760c11b602882015260300190565b808202811582820484141761087b5761087b615280565b8183823760009101908152919050565b60408152600061540f6040830185614e58565b90508260208301529392505050565b60006020828403121561543057600080fd5b81516132f381614cff565b6000808335601e1984360301811261545257600080fd5b8301803591506001600160401b0382111561546c57600080fd5b6020019150368190038213156148b657600080fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126154ad57600080fd5b9190910192915050565b6000600182016154c9576154c9615280565b5060010190565b600082516154ad818460208701614e34565b600060208083850312156154f557600080fd5b82516001600160401b038082111561550c57600080fd5b818501915085601f83011261552057600080fd5b81518181111561553257615532614c09565b8060051b9150615543848301614c1f565b818152918301840191848101908884111561555d57600080fd5b938501935b83851015615587578451925061557783614cff565b8282529385019390850190615562565b98975050505050505050565b600181811c908216806155a757607f821691505b6020821081036155c757634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561259057600081815260208120601f850160051c810160208610156155f45750805b601f850160051c820191505b8181101561561357828155600101615600565b505050505050565b81516001600160401b0381111561563457615634614c09565b615648816156428454615593565b846155cd565b602080601f83116001811461567d57600084156156655750858301515b600019600386901b1c1916600185901b178555615613565b600085815260208120601f198616915b828110156156ac5788860151825594840194600190910190840161568d565b50858210156156ca5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601260045260246000fd5b6000826156ff576156ff6156da565b500490565b600082615713576157136156da565b500690565b6000808585111561572857600080fd5b8386111561573557600080fd5b5050820193919092039150565b60018060a01b0384168152826020820152606060408201526000611cdf6060830184614e58565b60006020828403121561577b57600080fd5b81516001600160401b0381111561579157600080fd5b8201601f810184136157a257600080fd5b80516157b0614cc582614c4f565b8181528560208385010111156157c557600080fd5b611cdf826020830160208601614e34565b6020815260006132f36020830184614e58565b805160208083015191908110156155c75760001960209190910360031b1b16919050565b828152604060208201526000612c2d6040830184614e5856fea26469706673582212205eaf7721bad67e446fbb0611cd25254152f0ec99df9e7f28146f9d90d9bcc19264736f6c63430008120033000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce60000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e613000000000000000000000000798d2d716a13c62324bd98a47f209548ef6d359c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102485760003560e01c806384b0196e1161013b578063b6b35272116100b8578063d4ee97341161007c578063d4ee9734146106db578063f143ddba146106ee578063f18858ab14610701578063f435f5a714610721578063f8d3277d1461073457610248565b8063b6b352721461067c578063ba8210881461068f578063c6845210146106a2578063c90db447146106b5578063d4bfea48146106c857610248565b80639be65a60116100ff5780639be65a6014610616578063a3f4df7e14610629578063a5efb23514610643578063a6eb069014610656578063b0ba4da01461066957610248565b806384b0196e146104fa578063873bd184146105155780638c8e13b91461051c5780639769c3fe146105835780639add38d51461060357610248565b80634b3ef054116101c95780636b9db4e61161018d5780636b9db4e6146104835780636d435421146104ae5780636ff6ec7c146104c157806370135f52146104d45780637d1c2e78146104e757610248565b80634b3ef054146103f05780635040fb761461040357806357518243146104245780635a1db8c41461043757806360c0fdc01461044a57610248565b80632960739b116102105780632960739b146103835780632f6c493c14610396578063315a7af3146103a95780633b73d67f146103bc5780634a4fbeec146103dd57610248565b80631626ba7e146102e957806319ab453c1461031a5780631d97d8cc1461032d5780632437b75c1461034057806325b5093414610360575b600061028a6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b03198116630a85bd0160e11b14806102bb57506001600160e01b0319811663f23a6e6160e01b145b806102d657506001600160e01b0319811663bc197c8160e01b145b156102e75760046000803760206000f35b005b6102fc6102f7366004614c76565b6107a8565b6040516001600160e01b031990911681526020015b60405180910390f35b6102e7610328366004614d14565b610881565b6102e761033b366004614d31565b6108e7565b61035361034e366004614dae565b610afd565b6040516103119190614e84565b61037361036e366004614ee6565b610b66565b6040519015158152602001610311565b6102e7610391366004614d31565b610bed565b6102e76103a4366004614d14565b610d34565b6102e76103b7366004614d14565b610ea1565b6103cf6103ca366004614f51565b611065565b604051610311929190614fbb565b6103736103eb366004614d14565b611483565b6102e76103fe366004614d31565b61148e565b610416610411366004614d14565b6116dd565b604051908152602001610311565b6102e7610432366004614d31565b61176c565b6102e7610445366004614d31565b6119d4565b610373610458366004614fed565b6001600160a01b03919091166000908152600460209081526040808320938352929052205460ff1690565b610496610491366004614d14565b611b69565b6040516001600160401b039091168152602001610311565b6102e76104bc366004614d31565b611ba4565b6103536104cf366004615019565b611c8c565b6102e76104e2366004614d31565b611ce8565b6103736104f5366004615060565b611f5f565b6105026122f4565b60405161031197969594939291906150f5565b6001610373565b61055c61052a366004614d14565b6001600160a01b0390811660009081526020819052604090205490811691600160a01b9091046001600160401b031690565b604080516001600160a01b0390931683526001600160401b03909116602083015201610311565b6105d0610591366004614d14565b6001600160a01b0390811660009081526005602052604090205490811691600160a01b82046001600160401b031691600160e01b900463ffffffff1690565b604080516001600160a01b0390941684526001600160401b03909216602084015263ffffffff1690820152606001610311565b61041661061136600461518b565b61237d565b6102e7610624366004614d14565b61248e565b6104166f456e74657270726973654d6f64756c6560801b81565b610353610651366004615019565b612595565b6102e7610664366004614d31565b6127c5565b6102e7610677366004614d31565b61290c565b61037361068a366004614d31565b612b85565b6102e761069d366004614d14565b612c35565b6102e76106b0366004614d31565b612ce6565b6102e76106c3366004614d14565b61307a565b6102e76106d6366004614d31565b61317e565b6103736106e9366004614d31565b61325c565b6103536106fc366004615019565b6132fa565b61071461070f366004614d14565b613375565b60405161031191906151c7565b6102e761072f366004614d14565b613408565b6102e7610742366004614d31565b61353b565b60006004825110156107a05760405162461bcd60e51b815260206004820152601d60248201527f5574696c733a20496e76616c69642066756e6374696f6e50726566697800000060448201526064015b60405180910390fd5b506020015190565b600081516041146107fb5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20696e76616c6964207369676e6174757265206c656e677468000000006044820152606401610797565b600061080984846000613618565b9050610815338261374d565b6108565760405162461bcd60e51b81526020600482015260126024820152712a269d1024b73b30b634b21039b4b3b732b960711b6044820152606401610797565b7f1626ba7e356f5979dd355a3d2bfb43e80420a480c3b854edce286a82d74968699150505b92915050565b80336001600160a01b038216146108da5760405162461bcd60e51b815260206004820152601960248201527f424d3a2063616c6c6572206d7573742062652077616c6c6574000000000000006044820152606401610797565b6108e3826137cc565b5050565b81303314806108fe5750336001600160a01b038216145b61091a5760405162461bcd60e51b815260040161079790615214565b610924838361325c565b6109705760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d757374206265206578697374696e6720677561726469616e0000006044820152606401610797565b6000838360405160200161098592919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b0387166000908152600684528281208282529384905291909120549092501580610a065750600082815260208290526040902054610a03907f000000000000000000000000000000000000000000000000000000000000001490615296565b42115b610a525760405162461bcd60e51b815260206004820152601c60248201527f534d3a206475706c69636174652070656e64696e67207265766f6b65000000006044820152606401610797565b610a7c7f000000000000000000000000000000000000000000000000000000000000001442615296565b6000838152602083905260409020556001600160a01b038085169086167f9746f6868f544595794833da53250bd19e72334733336cfd5dd6fbc5f6a6ac42610ae47f000000000000000000000000000000000000000000000000000000000000001442615296565b6040519081526020015b60405180910390a35050505050565b6060303314610b1e5760405162461bcd60e51b8152600401610797906152a9565b85610b2881613835565b15610b455760405162461bcd60e51b8152600401610797906152d5565b610b5087858561385e565b610b5b8787876139cb565b979650505050505050565b60006001600160e01b03198216630b135d3f60e11b1480610b9757506001600160e01b03198216630a85bd0160e11b145b80610bb257506001600160e01b031982166301ffc9a760e01b145b80610bcd57506001600160e01b0319821663f23a6e6160e01b145b8061087b57506001600160e01b0319821663bc197c8160e01b1492915050565b8130331480610c045750336001600160a01b038216145b610c205760405162461bcd60e51b815260040161079790615214565b82610c2a81613835565b15610c475760405162461bcd60e51b8152600401610797906152d5565b60008484604051602001610c5c92919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b038816600090815260068452828120828252938490529190912054909250610ce55760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917fc0b205956d5e27c296695de329b5a014584a4f51824b1725a0eefc1174d6dbd59190a3505050505050565b8030331480610d485750610d48813361325c565b610d905760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b81610d9a81613835565b610de65760405162461bcd60e51b815260206004820152601960248201527f424d3a2077616c6c6574206d757374206265206c6f636b6564000000000000006044820152606401610797565b6001600160a01b038316600090815260016020526040902054600160401b900460e01b6001600160e01b03191663f435f5a760e01b14610e5c5760405162461bcd60e51b8152602060048201526011602482015270534d3a2063616e6e6f7420756e6c6f636b60781b6044820152606401610797565b610e6883600080613bb3565b6040516001600160a01b038416907f7e6adfec7e3f286831a0200a754127c171a2da564078722cb97704741bbdb0ea90600090a2505050565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b0316610f125760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b038216600090815260056020526040902080546001600160401b03600160a01b90910481164290911611610f8f5760405162461bcd60e51b815260206004820152601b60248201527f534d3a206f6e676f696e67207265636f7665727920706572696f6400000000006044820152606401610797565b80546001600160a01b0384811660009081526005602052604081205516610fb584613c2e565b6040516313af403560e01b81526001600160a01b0382811660048301528516906313af403590602401600060405180830381600087803b158015610ff857600080fd5b505af115801561100c573d6000803e3d6000fd5b5050505061101f8460008060e01b613bb3565b806001600160a01b0316846001600160a01b03167fd8667de85dae2d56d76e700d16de53d21ac2ce4d5549cb0bf51c55fdc37f0bc160405160405180910390a350505050565b60008060006110a985858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061074792505050565b90506001600160e01b0319811663a5efb23560e01b14806110da57506001600160e01b03198116635751824360e01b145b806110f557506001600160e01b0319811663f8d3277d60e01b145b8061111057506001600160e01b03198116631750421160e31b145b1561113f576001600160a01b038616330361113257600080925092505061147b565b600180925092505061147b565b63240244e160e21b6001600160e01b0319821601611183576001600160a01b03861633036111755760006004925092505061147b565b60016004925092505061147b565b63027a2d9360e51b6001600160e01b03198216016112055760006111a687613c55565b9050600081116111f85760405162461bcd60e51b815260206004820152601e60248201527f414d3a206e6f20677561726469616e7320736574206f6e2077616c6c657400006044820152606401610797565b92506003915061147b9050565b6336f24bb960e01b6001600160e01b0319821601611296576001600160a01b03861660009081526005602052604081205461125f9061125290600160e01b900463ffffffff166001615300565b63ffffffff166002613ce9565b90506001600160a01b03871633036112895761127c60018261531d565b600393509350505061147b565b92506002915061147b9050565b6001600160e01b03198116630c68452160e41b14806112c557506001600160e01b03198116630765f63360e21b145b806112e057506001600160e01b03198116630a6eb06960e41b145b806112fb57506001600160e01b03198116632960739b60e01b145b8061131657506001600160e01b03198116636d43542160e01b145b8061133157506001600160e01b031981166316876e3160e21b145b8061134c57506001600160e01b03198116631a97fd4960e31b145b8061136757506001600160e01b031981166378a1eedd60e11b145b8061138257506001600160e01b0319811663090dedd760e21b145b156113a057600061139287613c55565b93506003925061147b915050565b6001600160e01b0319811663315a7af360e01b14806113cf57506001600160e01b03198116633809afa960e11b145b806113ea57506001600160e01b031981166312cfbc1560e21b145b156113fc57600080925092505061147b565b6001600160e01b0319811663f435f5a760e01b148061142b57506001600160e01b03198116630bdb124f60e21b145b1561143e5760016003925092505061147b565b60405162461bcd60e51b815260206004820152601260248201527114d34e881d5b9adb9bdddb881b595d1a1bd960721b6044820152606401610797565b935093915050565b600061087b82613835565b600082826040516020016114a392919061524b565b60408051601f1981840301815291815281516020928301206001600160a01b03861660009081526006845282812082825293849052919091205490925061152c5760405162461bcd60e51b815260206004820152601a60248201527f534d3a20756e6b6e6f776e2070656e64696e67207265766f6b650000000000006044820152606401610797565b60008281526020829052604090205442116115895760405162461bcd60e51b815260206004820152601b60248201527f534d3a2070656e64696e67207265766f6b65206e6f74206f76657200000000006044820152606401610797565b6000828152602082905260409020546115c3907f000000000000000000000000000000000000000000000000000000000000001490615296565b42106116115760405162461bcd60e51b815260206004820152601a60248201527f534d3a2070656e64696e67207265766f6b6520657870697265640000000000006044820152606401610797565b604051630765f63360e21b81526001600160a01b03858116600483015284811660248301527f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f1690631d97d8cc90604401600060405180830381600087803b15801561167c57600080fd5b505af1158015611690573d6000803e3d6000fd5b50506040516001600160a01b038087169350871691507f548f10dcba266544123ad8cf8284f25c4baa659cba25dbdf16a06ea11235de9b90600090a3600091825260205260408120555050565b6040516328207dbb60e11b81526001600160a01b0382811660048301526000917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f90911690635040fb7690602401602060405180830381865afa158015611748573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087b9190615330565b81303314806117805750611780813361374d565b61179c5760405162461bcd60e51b815260040161079790615349565b826117a681613835565b156117c35760405162461bcd60e51b8152600401610797906152d5565b836001600160a01b0316836001600160a01b0316036118245760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c6973742077616c6c657400000000006044820152606401610797565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce601690630bcd4ebb90602401602060405180830381865afa15801561188a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118ae9190615380565b156118fb5760405162461bcd60e51b815260206004820152601b60248201527f544d3a2043616e6e6f742077686974656c697374206d6f64756c6500000000006044820152606401610797565b6119058484612b85565b156119525760405162461bcd60e51b815260206004820152601e60248201527f544d3a2074617267657420616c72656164792077686974656c697374656400006044820152606401610797565b600061197e7f000000000000000000000000000000000000000000000000000000000000001442615296565b905061198b858583613d2a565b6040516001600160401b03821681526001600160a01b0380861691908716907f1f57f9641d3e8733ed672fef5ac85464bd7215ef2f21e83428e8408248b13dcd90602001610aee565b81303314806119e857506119e8813361374d565b611a045760405162461bcd60e51b815260040161079790615349565b82611a0e81613835565b15611a2b5760405162461bcd60e51b8152600401610797906152d5565b604051630bcd4ebb60e01b81526001600160a01b0384811660048301527f000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce601690630bcd4ebb90602401602060405180830381865afa158015611a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab59190615380565b611b015760405162461bcd60e51b815260206004820152601c60248201527f414d3a206d6f64756c65206973206e6f742072656769737465726564000000006044820152606401610797565b604051631f17732d60e01b81526001600160a01b03848116600483015260016024830152851690631f17732d90604401600060405180830381600087803b158015611b4b57600080fd5b505af1158015611b5f573d6000803e3d6000fd5b5050505050505050565b6000611b7482613835565b611b7f57600061087b565b506001600160a01b03166000908152600160205260409020546001600160401b031690565b303314611bc35760405162461bcd60e51b8152600401610797906152a9565b81611bcd81613835565b15611bea5760405162461bcd60e51b8152600401610797906152d5565b611bf48383613db9565b6040516313af403560e01b81526001600160a01b0383811660048301528416906313af403590602401600060405180830381600087803b158015611c3757600080fd5b505af1158015611c4b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6790600090a3505050565b6060303314611cad5760405162461bcd60e51b8152600401610797906152a9565b83611cb781613835565b15611cd45760405162461bcd60e51b8152600401610797906152d5565b611cdf8585856139cb565b95945050505050565b81611cf281613835565b15611d0f5760405162461bcd60e51b8152600401610797906152d5565b60008383604051602001611d249291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b038716600090815260068452828120828252938490529190912054909250611dad5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b6000828152602082905260409020544211611e0a5760405162461bcd60e51b815260206004820152601d60248201527f534d3a2070656e64696e67206164646974696f6e206e6f74206f7665720000006044820152606401610797565b600082815260208290526040902054611e44907f000000000000000000000000000000000000000000000000000000000000001490615296565b4210611e925760405162461bcd60e51b815260206004820152601c60248201527f534d3a2070656e64696e67206164646974696f6e2065787069726564000000006044820152606401610797565b604051630c68452160e41b81526001600160a01b03868116600483015285811660248301527f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f169063c684521090604401600060405180830381600087803b158015611efd57600080fd5b505af1158015611f11573d6000803e3d6000fd5b50506040516001600160a01b038088169350881691507fbc3292102fa77e083913064b282926717cdfaede4d35f553d66366c0a3da755a90600090a360009182526020526040812055505050565b6000611f6c888888613e66565b611fb85760405162461bcd60e51b815260206004820152601e60248201527f524d3a20546172676574206f66205f6461746120213d205f77616c6c657400006044820152606401610797565b611fc188613835565b1561200e5760405162461bcd60e51b815260206004820152601860248201527f524d3a204c6f636b65642077616c6c657420726566756e6400000000000000006044820152606401610797565b600080600060606120208c8c8c611065565b9094509250831515806120445750600083600481111561204257612042614fa5565b145b6120905760405162461bcd60e51b815260206004820152601f60248201527f524d3a2057726f6e67207369676e617475726520726571756972656d656e74006044820152606401610797565b8561209c8560416153d5565b146120e95760405162461bcd60e51b815260206004820152601e60248201527f524d3a2057726f6e67206e756d626572206f66207369676e61747572657300006044820152606401610797565b60007fbf1af91af6bb21cb6f3df695a3f72929c8cc95124bb13aad4c9d2ff670a214318d8d8d60405161211d9291906153ec565b60405190819003812061215f9392918e908e906020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604051602081830303815290604052805190602001209050600061218282613ee7565b9050600485600481111561219857612198614fa5565b036121ed576121a68e613f14565b6121e85760405162461bcd60e51b815260206004820152601360248201527229269d1024b73b30b634b21039b2b9b9b4b7b760691b6044820152606401610797565b61223f565b6121fa8e828b8b89613f74565b61223f5760405162461bcd60e51b8152602060048201526016602482015275524d3a20496e76616c6964207369676e61747572657360501b6044820152606401610797565b6040513090612251908f908f906153ec565b6000604051808303816000865af19150503d806000811461228e576040519150601f19603f3d011682016040523d82523d6000602084013e612293565b606091505b5080945081955050508315158e6001600160a01b03167f7da4525a280527268ba2e963ee6c1b18f43c9507bcb1d2560f652ab17c76e90a85846040516122da9291906153fc565b60405180910390a350919c9b505050505050505050505050565b6000606080828080836123287f52656c617965724b6e6f6273000000000000000000000000000000000000000c60026142c8565b6123537f310000000000000000000000000000000000000000000000000000000000000160036142c8565b60408051600080825260208201909252600f60f81b9b939a50919850469750309650945092509050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c829052603c81206000336001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612410919061541e565b905061246061242361014087018761543b565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869392505061436c9050565b6001600160a01b0316816001600160a01b0316146124835760019250505061087b565b506000949350505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156124d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f99190615330565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce6081166004830152602482018390529192509083169063a9059cbb906044016020604051808303816000875af115801561256c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125909190615380565b505050565b60603033146125b65760405162461bcd60e51b8152600401610797906152a9565b836125c081613835565b156125dd5760405162461bcd60e51b8152600401610797906152d5565b6000836001600160401b038111156125f7576125f7614c09565b60405190808252806020026020018201604052801561262a57816020015b60608152602001906001900390816126155790505b50905060005b848110156127bb573086868381811061264b5761264b615481565b905060200281019061265d9190615497565b61266b906020810190614d14565b6001600160a01b0316036126c15760405162461bcd60e51b815260206004820152601760248201527f544d3a2063616c6c206e6f7420617574686f72697365640000000000000000006044820152606401610797565b61278b878787848181106126d7576126d7615481565b90506020028101906126e99190615497565b6126f7906020810190614d14565b88888581811061270957612709615481565b905060200281019061271b9190615497565b6020013589898681811061273157612731615481565b90506020028101906127439190615497565b61275190604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061439092505050565b82828151811061279d5761279d615481565b602002602001018190525080806127b3906154b7565b915050612630565b5095945050505050565b81303314806127dc5750336001600160a01b038216145b6127f85760405162461bcd60e51b815260040161079790615214565b8261280281613835565b1561281f5760405162461bcd60e51b8152600401610797906152d5565b600084846040516020016128349291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0388166000908152600684528281208282529384905291909120549092506128bd5760405162461bcd60e51b815260206004820152601c60248201527f534d3a20756e6b6e6f776e2070656e64696e67206164646974696f6e000000006044820152606401610797565b600082815260208290526040808220829055516001600160a01b0380881692908916917faa13b27c23e9e3f3d5f3861a53b7a2931e019170a6a19ed64942e26a1dd5987a9190a3505050505050565b30331461292b5760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0382166000908152600560205260409020548290600160a01b90046001600160401b03161561299a5760405162461bcd60e51b8152602060048201526014602482015273534d3a206f6e676f696e67207265636f7665727960601b6044820152606401610797565b6129a48383613db9565b60006129d07f000000000000000000000000000000000000000000000000000000000000002842615296565b604080516060810182526001600160a01b0380871682526001600160401b038416602083015282516328207dbb60e11b815288821660048201529394509092918301917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f90911690635040fb7690602401602060405180830381865afa158015612a5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a829190615330565b63ffffffff9081169091526001600160a01b0380871660009081526005602090815260409182902085518154928701519690930151909416600160e01b026001600160e01b036001600160401b03909616600160a01b026001600160e01b031990921692909316919091171792909216919091179055612b3384612b267f000000000000000000000000000000000000000000000000000000000000002842615296565b630585d26d60e51b613bb3565b6040516001600160401b03821681526001600160a01b0380851691908616907f5f59bfd9baba55ae30bb440923cbbe30987d50e12a4e9134ffac3fd9afc3526d9060200160405180910390a350505050565b6040516309fa507560e11b81526001600160a01b038381166004830152828116602483015260009182917f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e61316906313f4a0ea90604401602060405180830381865afa158015612bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1c9190615330565b9050600081118015612c2d57504281105b949350505050565b8030331480612c495750612c49813361374d565b612c655760405162461bcd60e51b815260040161079790615349565b81612c6f81613835565b15612c8c5760405162461bcd60e51b8152600401610797906152d5565b6001600160a01b038381166000818152602081815260409182902054915191909316815290917feb290a597820eccc6b8b31f942bd97c633d5138f4d849751f770f3cb3900e57a910160405180910390a261259083613c2e565b8130331480612cfd5750336001600160a01b038216145b612d195760405162461bcd60e51b815260040161079790615214565b82612d2381613835565b15612d405760405162461bcd60e51b8152600401610797906152d5565b612d6c6040518060400160405280600b81526020016a30b23223bab0b93234b0b760a91b8152506144e8565b612d76848461374d565b15612dc35760405162461bcd60e51b815260206004820152601c60248201527f534d3a20677561726469616e2063616e6e6f74206265206f776e6572000000006044820152606401610797565b612dcd848461325c565b15612e135760405162461bcd60e51b815260206004820152601660248201527529a69d10323ab83634b1b0ba329033bab0b93234b0b760511b6044820152606401610797565b60408051600481526024810182526020810180516001600160e01b0316638da5cb5b60e01b17905290516000916001600160a01b038616916161a891612e58916154d0565b60006040518083038160008787f1925050503d8060008114612e96576040519150601f19603f3d011682016040523d82523d6000602084013e612e9b565b606091505b5050905080612eec5760405162461bcd60e51b815260206004820152601d60248201527f534d3a206d75737420626520454f412f417267656e742077616c6c65740000006044820152606401610797565b60008585604051602001612f019291906153a2565b60408051601f1981840301815291815281516020928301206001600160a01b0389166000908152600684528281208282529384905291909120549092501580612f825750600082815260208290526040902054612f7f907f000000000000000000000000000000000000000000000000000000000000001490615296565b42115b612fce5760405162461bcd60e51b815260206004820152601e60248201527f534d3a206475706c69636174652070656e64696e67206164646974696f6e00006044820152606401610797565b612ff87f000000000000000000000000000000000000000000000000000000000000001442615296565b6000838152602083905260409020556001600160a01b038087169088167fe4166e4bc55a182bd13d933553241bb3441b91d15fbc74c5c752f96965563bde6130607f000000000000000000000000000000000000000000000000000000000000001442615296565b60405190815260200160405180910390a350505050505050565b3033146130995760405162461bcd60e51b8152600401610797906152a9565b6001600160a01b0381166000908152600560205260409020548190600160a01b90046001600160401b031661310a5760405162461bcd60e51b8152602060048201526017602482015276534d3a206e6f206f6e676f696e67207265636f7665727960481b6044820152606401610797565b6001600160a01b0380831660009081526005602052604081208054908290559091169061313990849080613bb3565b806001600160a01b0316836001600160a01b03167fc45926607303da71dbeffd2ed5c6b00f581982586b697655d19ae4c4d558f25960405160405180910390a3505050565b30331461319d5760405162461bcd60e51b8152600401610797906152a9565b816131a781613835565b156131c45760405162461bcd60e51b8152600401610797906152d5565b604051631b2ce7f360e11b81526001600160a01b038381166004830152841690633659cfe690602401600060405180830381600087803b15801561320757600080fd5b505af115801561321b573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f5c92b3979a73cef77d1416cc6817a9094d4fd8d62e4d93189c8e2b06c5c5919790600090a3505050565b60405163353ba5cd60e21b81526001600160a01b03838116600483015282811660248301526000917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f9091169063d4ee973490604401602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f39190615380565b9392505050565b606030331461331b5760405162461bcd60e51b8152600401610797906152a9565b8361332581613835565b156133425760405162461bcd60e51b8152600401610797906152d5565b61336c604051806040016040528060098152602001681b5d5b1d1a50d85b1b60ba1b8152506144e8565b611cd48361452e565b60405163f18858ab60e01b81526001600160a01b0382811660048301526060917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f9091169063f18858ab90602401600060405180830381865afa1580156133e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261087b91908101906154e2565b803033148061341c575061341c813361325c565b6134645760405162461bcd60e51b815260206004820152601960248201527829a69d1036bab9ba1031329033bab0b93234b0b717b9b2b63360391b6044820152606401610797565b8161346e81613835565b1561348b5760405162461bcd60e51b8152600401610797906152d5565b6134c6836134b97f000000000000000000000000000000000000000000000000000000000000002842615296565b63f435f5a760e01b613bb3565b6001600160a01b0383167f6395bace6e0acbe4f22761b149d3cc2e88c7dde6bf4d8481825eef404cf989a161351b7f000000000000000000000000000000000000000000000000000000000000002842615296565b6040516001600160401b03909116815260200160405180910390a2505050565b813033148061354f575061354f813361374d565b61356b5760405162461bcd60e51b815260040161079790615349565b8261357581613835565b156135925760405162461bcd60e51b8152600401610797906152d5565b61359e84846000613d2a565b826001600160a01b0316846001600160a01b03167fd288ab5da2e1f37cf384a1565a3f905ad289b092fbdd31950dbbfef148c04f8860405160405180910390a350505050565b6000602083511015613600576135f983614573565b905061087b565b8161360b848261561b565b5060ff905061087b565b90565b6041808202830160208101516040820151919092015160009260ff9190911691601b83148061364a57508260ff16601c145b6136965760405162461bcd60e51b815260206004820152601f60248201527f5574696c733a2062616420762076616c756520696e207369676e6174757265006044820152606401610797565b604080516000808252602082018084528a905260ff861692820192909252606081018490526080810183905260019060a0016020604051602081039080840390855afa1580156136ea573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b5b5760405162461bcd60e51b815260206004820152601b60248201527f5574696c733a2065637265636f7665722072657475726e6564203000000000006044820152606401610797565b6000816001600160a01b0316836001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bb919061541e565b6001600160a01b0316149392505050565b6040516309ed185960e11b8152306004820152630b135d3f60e11b60248201526001600160a01b038216906313da30b290604401600060405180830381600087803b15801561381a57600080fd5b505af115801561382e573d6000803e3d6000fd5b5050505050565b6001600160a01b03166000908152600160205260409020546001600160401b0342811691161190565b6001600160a01b0382166138b45760405162461bcd60e51b815260206004820152601860248201527f544d3a20496e76616c69642073657373696f6e207573657200000000000000006044820152606401610797565b6000816001600160401b03161161390d5760405162461bcd60e51b815260206004820152601c60248201527f544d3a20496e76616c69642073657373696f6e206475726174696f6e000000006044820152606401610797565b600061392a6139256001600160401b03841642615296565b6145b1565b6040805180820182526001600160a01b038681168083526001600160401b0385811660208086018281528c86166000818152808452899020975188549251909516600160a01b026001600160e01b031990921694909616939093179290921790945584519182528101929092529293507f2ecea11087d1dc1431b517cbb5a559a9e33e58a1afeaac288f782c1c8bed8b8a910160405180910390a250505050565b60606000826001600160401b038111156139e7576139e7614c09565b604051908082528060200260200182016040528015613a1a57816020015b6060815260200190600190039081613a055790505b509050613a268361452e565b60005b83811015613baa57613a6b858583818110613a4657613a46615481565b9050602002810190613a589190615497565b613a66906020810190614d14565b61461d565b613ada858583818110613a8057613a80615481565b9050602002810190613a929190615497565b613aa090604081019061543b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061466592505050565b613b0a858583818110613aef57613aef615481565b9050602002810190613b019190615497565b6020013561452e565b613b7a86868684818110613b2057613b20615481565b9050602002810190613b329190615497565b613b40906020810190614d14565b878785818110613b5257613b52615481565b9050602002810190613b649190615497565b6020013588888681811061273157612731615481565b828281518110613b8c57613b8c615481565b60200260200101819052508080613ba2906154b7565b915050613a29565b50949350505050565b6040518060400160405280613bc7846145b1565b6001600160401b0390811682526001600160e01b03199093166020918201526001600160a01b039094166000908152600185526040902081518154929095015160e01c600160401b026001600160601b031990921694909216939093179290921790915550565b6001600160a01b0316600090815260208190526040902080546001600160e01b0319169055565b6040516328207dbb60e11b81526001600160a01b03828116600483015260009161087b917f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f1690635040fb7690602401602060405180830381865afa158015613cc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce69190615330565b60025b600080613cf683856156f0565b9050613d028385615704565b600003613d1057905061087b565b613d1b816001615296565b91505061087b565b5092915050565b604051631017f7cd60e31b81526001600160a01b0384811660048301528381166024830152604482018390527f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e61316906380bfbe6890606401600060405180830381600087803b158015613d9c57600080fd5b505af1158015613db0573d6000803e3d6000fd5b50505050505050565b6001600160a01b038116613e0f5760405162461bcd60e51b815260206004820152601c60248201527f534d3a206e6577206f776e65722063616e6e6f74206265206e756c6c000000006044820152606401610797565b613e19828261325c565b156108e35760405162461bcd60e51b815260206004820181905260248201527f534d3a206e6577206f776e65722063616e6e6f7420626520677561726469616e6044820152606401610797565b60006024821015613eb25760405162461bcd60e51b815260206004820152601660248201527514934e88125b9d985b1a590819185d1855d85b1b195d60521b6044820152606401610797565b6000613ec18360048187615718565b810190613ece9190614d14565b6001600160a01b03908116908616149150509392505050565b600061087b613ef46146a8565b8360405161190160f01b8152600281019290925260228201526042902090565b6001600160a01b038181166000818152602081815260408083208151808301909252549485168152600160a01b9094046001600160401b0316908401529190331480156132f357504281602001516001600160401b031610159392505050565b6000828103613f8557506001611cdf565b600060606001846004811115613f9d57613f9d614fa5565b141580613faa5750604185115b156140405760405163f18858ab60e01b81526001600160a01b0389811660048301527f000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f169063f18858ab90602401600060405180830381865afa158015614015573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261403d91908101906154e2565b90505b6001600160a01b03881660009081526004602090815260408083208a845290915290205460ff16156140c85760405162461bcd60e51b815260206004820152602b60248201527f524d3a2076616c69646174655369676e6174757265733a20747820616c72656160448201526a191e48195e1958dd5d195960aa1b6064820152608401610797565b60005b6140d66041876156f0565b8110156142b95760408051604180825260808201909252600091602082018180368337019050509050876041830201604181602084013750816000036141e25760006141848b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417d919061541e565b8b846147d8565b9050600187600481111561419a5761419a614fa5565b036141ba5780156141ac5750506142a7565b600095505050505050611cdf565b60028760048111156141ce576141ce614fa5565b036141e05780156141e05750506142a7565b505b6000805b84518110156142905761421385828151811061420457614204615481565b60200260200101518c856147d8565b1561427e57856001600160a01b031685828151811061423457614234615481565b60200260200101516001600160a01b0316116142595760009650505050505050611cdf565b84818151811061426b5761426b615481565b6020026020010151955060019150614290565b80614288816154b7565b9150506141e6565b50806142a457600095505050505050611cdf565b50505b806142b1816154b7565b9150506140cb565b50600198975050505050505050565b606060ff83146142db576135f983614839565b8180546142e790615593565b80601f016020809104026020016040519081016040528092919081815260200182805461431390615593565b80156143605780601f1061433557610100808354040283529160200191614360565b820191906000526020600020905b81548152906001019060200180831161434357829003601f168201915b5050505050905061087b565b600080600061437b8585614878565b91509150614388816148bd565b509392505050565b606060006143c16040518060400160405280600c81526020016b1a5b9d9bdad955d85b1b195d60a21b8152506144e8565b856001600160a01b03168585856040516024016143e093929190615742565b60408051601f198184030181529181526020820180516001600160e01b03166347b7819960e11b1790525161441591906154d0565b6000604051808303816000865af19150503d8060008114614452576040519150601f19603f3d011682016040523d82523d6000602084013e614457565b606091505b509250905080801561446a575060008251115b1561448a57818060200190518101906144839190615769565b9150613baa565b81511561449b573d6000803e3d6000fd5b80613baa5760405162461bcd60e51b815260206004820152601a60248201527f424d3a2077616c6c657420696e766f6b652072657665727465640000000000006044820152606401610797565b61452b816040516024016144fc91906157d6565b60408051601f198184030181529190526020810180516001600160e01b031663104c13eb60e21b179052614a07565b50565b61452b8160405160240161454491815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663f82c50f160e01b179052614a07565b600080829050601f8151111561459e578260405163305a27a960e01b815260040161079791906157d6565b80516145a9826157e9565b179392505050565b60006001600160401b038211156146195760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610797565b5090565b6040516001600160a01b038216602482015261452b9060440160408051601f198184030181529190526020810180516001600160e01b031663161765e160e11b179052614a07565b61452b8160405160240161467991906157d6565b60408051601f198184030181529190526020810180516001600160e01b03166305f3bfab60e11b179052614a07565b6000306001600160a01b037f00000000000000000000000062bebf3fb38df89c13be114d3761528df7f75c2f1614801561470157507f0000000000000000000000000000000000000000000000000000000000aa36a746145b1561472b57507fcc6cc0e803a10acb2036622ffe00698f2d6010390e3cc955702735cc0b24df1c90565b6147d3604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f55c4f5592be9e78c3c80aa7e492430b3b9282cc84dcc3f39731f366bb92cd1d5918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b60008060006147e78585614878565b9092509050600081600481111561480057614800614fa5565b14801561481e5750856001600160a01b0316826001600160a01b0316145b8061482f575061482f868686614a10565b9695505050505050565b6060600061484683614afc565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60008082516041036148ae5760208301516040840151606085015160001a6148a287828585614b24565b945094505050506148b6565b506000905060025b9250929050565b60008160048111156148d1576148d1614fa5565b036148d95750565b60018160048111156148ed576148ed614fa5565b0361493a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610797565b600281600481111561494e5761494e614fa5565b0361499b5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610797565b60038160048111156149af576149af614fa5565b0361452b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610797565b61452b81614be8565b6000806000856001600160a01b0316631626ba7e60e01b8686604051602401614a3a92919061580d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614a7891906154d0565b600060405180830381855afa9150503d8060008114614ab3576040519150601f19603f3d011682016040523d82523d6000602084013e614ab8565b606091505b5091509150818015614acc57506020815110155b801561482f57508051630b135d3f60e11b90614af19083016020908101908401615330565b149695505050505050565b600060ff8216601f81111561087b57604051632cd44ac360e21b815260040160405180910390fd5b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b5b5750600090506003614bdf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614baf573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614bd857600060019250925050614bdf565b9150600090505b94509492505050565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614c4757614c47614c09565b604052919050565b60006001600160401b03821115614c6857614c68614c09565b50601f01601f191660200190565b60008060408385031215614c8957600080fd5b8235915060208301356001600160401b03811115614ca657600080fd5b8301601f81018513614cb757600080fd5b8035614cca614cc582614c4f565b614c1f565b818152866020838501011115614cdf57600080fd5b816020840160208301376000602083830101528093505050509250929050565b6001600160a01b038116811461452b57600080fd5b600060208284031215614d2657600080fd5b81356132f381614cff565b60008060408385031215614d4457600080fd5b8235614d4f81614cff565b91506020830135614d5f81614cff565b809150509250929050565b60008083601f840112614d7c57600080fd5b5081356001600160401b03811115614d9357600080fd5b6020830191508360208260051b85010111156148b657600080fd5b600080600080600060808688031215614dc657600080fd5b8535614dd181614cff565b945060208601356001600160401b0380821115614ded57600080fd5b614df989838a01614d6a565b909650945060408801359150614e0e82614cff565b9092506060870135908082168214614e2557600080fd5b50809150509295509295909350565b60005b83811015614e4f578181015183820152602001614e37565b50506000910152565b60008151808452614e70816020860160208601614e34565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614ed957603f19888603018452614ec7858351614e58565b94509285019290850190600101614eab565b5092979650505050505050565b600060208284031215614ef857600080fd5b81356001600160e01b0319811681146132f357600080fd5b60008083601f840112614f2257600080fd5b5081356001600160401b03811115614f3957600080fd5b6020830191508360208285010111156148b657600080fd5b600080600060408486031215614f6657600080fd5b8335614f7181614cff565b925060208401356001600160401b03811115614f8c57600080fd5b614f9886828701614f10565b9497909650939450505050565b634e487b7160e01b600052602160045260246000fd5b8281526040810160058310614fe057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000806040838503121561500057600080fd5b823561500b81614cff565b946020939093013593505050565b60008060006040848603121561502e57600080fd5b833561503981614cff565b925060208401356001600160401b0381111561505457600080fd5b614f9886828701614d6a565b600080600080600080600060a0888a03121561507b57600080fd5b873561508681614cff565b965060208801356001600160401b03808211156150a257600080fd5b6150ae8b838c01614f10565b909850965060408a0135955060608a0135945060808a01359150808211156150d557600080fd5b506150e28a828b01614f10565b989b979a50959850939692959293505050565b60ff60f81b881681526000602060e08184015261511560e084018a614e58565b8381036040850152615127818a614e58565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156151795783518352928401929184019160010161515d565b50909c9b505050505050505050505050565b6000806040838503121561519e57600080fd5b82356001600160401b038111156151b457600080fd5b8301610160818603121561500b57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156152085783516001600160a01b0316835292840192918401916001016151e3565b50909695505050505050565b60208082526017908201527f424d3a206d7573742062652077616c6c65742f73656c66000000000000000000604082015260600190565b6001600160601b0319606093841b811682529190921b166014820152693932bb37b5b0ba34b7b760b11b602882015260320190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561087b5761087b615280565b602080825260129082015271424d3a206d757374206265206d6f64756c6560701b604082015260600190565b60208082526011908201527010934e881dd85b1b195d081b1bd8dad959607a1b604082015260600190565b63ffffffff818116838216019080821115613d2357613d23615280565b8181038181111561087b5761087b615280565b60006020828403121561534257600080fd5b5051919050565b6020808252601d908201527f424d3a206d7573742062652077616c6c6574206f776e65722f73656c66000000604082015260600190565b60006020828403121561539257600080fd5b815180151581146132f357600080fd5b6001600160601b0319606093841b811682529190921b1660148201526730b23234ba34b7b760c11b602882015260300190565b808202811582820484141761087b5761087b615280565b8183823760009101908152919050565b60408152600061540f6040830185614e58565b90508260208301529392505050565b60006020828403121561543057600080fd5b81516132f381614cff565b6000808335601e1984360301811261545257600080fd5b8301803591506001600160401b0382111561546c57600080fd5b6020019150368190038213156148b657600080fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126154ad57600080fd5b9190910192915050565b6000600182016154c9576154c9615280565b5060010190565b600082516154ad818460208701614e34565b600060208083850312156154f557600080fd5b82516001600160401b038082111561550c57600080fd5b818501915085601f83011261552057600080fd5b81518181111561553257615532614c09565b8060051b9150615543848301614c1f565b818152918301840191848101908884111561555d57600080fd5b938501935b83851015615587578451925061557783614cff565b8282529385019390850190615562565b98975050505050505050565b600181811c908216806155a757607f821691505b6020821081036155c757634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561259057600081815260208120601f850160051c810160208610156155f45750805b601f850160051c820191505b8181101561561357828155600101615600565b505050505050565b81516001600160401b0381111561563457615634614c09565b615648816156428454615593565b846155cd565b602080601f83116001811461567d57600084156156655750858301515b600019600386901b1c1916600185901b178555615613565b600085815260208120601f198616915b828110156156ac5788860151825594840194600190910190840161568d565b50858210156156ca5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601260045260246000fd5b6000826156ff576156ff6156da565b500490565b600082615713576157136156da565b500690565b6000808585111561572857600080fd5b8386111561573557600080fd5b5050820193919092039150565b60018060a01b0384168152826020820152606060408201526000611cdf6060830184614e58565b60006020828403121561577b57600080fd5b81516001600160401b0381111561579157600080fd5b8201601f810184136157a257600080fd5b80516157b0614cc582614c4f565b8181528560208385010111156157c557600080fd5b611cdf826020830160208601614e34565b6020815260006132f36020830184614e58565b805160208083015191908110156155c75760001960209190910360031b1b16919050565b828152604060208201526000612c2d6040830184614e5856fea26469706673582212205eaf7721bad67e446fbb0611cd25254152f0ec99df9e7f28146f9d90d9bcc19264736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce60000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e613000000000000000000000000798d2d716a13c62324bd98a47f209548ef6d359c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028
-----Decoded View---------------
Arg [0] : _registry (address): 0xd2122ea1D515b756C7BA11474E3eB4135699cE60
Arg [1] : _guardianStorage (address): 0x872005fdC178b16C7Eb7318172d42494d407886F
Arg [2] : _userWhitelist (address): 0x44A9990B0C59474e097653F8dF2eE00620E6E613
Arg [3] : _authoriser (address): 0x798D2d716A13c62324BD98a47f209548EF6D359c
Arg [4] : _securityPeriod (uint256): 20
Arg [5] : _securityWindow (uint256): 20
Arg [6] : _recoveryPeriod (uint256): 40
Arg [7] : _lockPeriod (uint256): 40
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000d2122ea1d515b756c7ba11474e3eb4135699ce60
Arg [1] : 000000000000000000000000872005fdc178b16c7eb7318172d42494d407886f
Arg [2] : 00000000000000000000000044a9990b0c59474e097653f8df2ee00620e6e613
Arg [3] : 000000000000000000000000798d2d716a13c62324bd98a47f209548ef6d359c
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000028
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000028
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.