Latest 25 from a total of 289 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Execute Next Tx | 42377770 | 124 days ago | IN | 0 XDAI | 0.00014936 | ||||
| Exec Transaction... | 42377735 | 124 days ago | IN | 0 XDAI | 0.0002249 | ||||
| Execute Next Tx | 42361098 | 125 days ago | IN | 0 XDAI | 0.00014939 | ||||
| Exec Transaction... | 42361060 | 125 days ago | IN | 0 XDAI | 0.00022494 | ||||
| Execute Next Tx | 42359822 | 125 days ago | IN | 0 XDAI | 0.0001494 | ||||
| Exec Transaction... | 42359785 | 125 days ago | IN | 0 XDAI | 0.00022495 | ||||
| Execute Next Tx | 42357372 | 126 days ago | IN | 0 XDAI | 0.00014938 | ||||
| Execute Next Tx | 42357370 | 126 days ago | IN | 0 XDAI | 0.00014729 | ||||
| Exec Transaction... | 42357335 | 126 days ago | IN | 0 XDAI | 0.00022495 | ||||
| Execute Next Tx | 42355109 | 126 days ago | IN | 0 XDAI | 0.00014938 | ||||
| Exec Transaction... | 42355072 | 126 days ago | IN | 0 XDAI | 0.00022493 | ||||
| Execute Next Tx | 42342676 | 126 days ago | IN | 0 XDAI | 0.00014938 | ||||
| Exec Transaction... | 42342639 | 126 days ago | IN | 0 XDAI | 0.00022497 | ||||
| Execute Next Tx | 42091001 | 141 days ago | IN | 0 XDAI | 0.00014938 | ||||
| Exec Transaction... | 42090964 | 141 days ago | IN | 0 XDAI | 0.00022491 | ||||
| Execute Next Tx | 41374195 | 184 days ago | IN | 0 XDAI | 0.00014911 | ||||
| Exec Transaction... | 41374160 | 184 days ago | IN | 0 XDAI | 0.00022451 | ||||
| Execute Next Tx | 41374132 | 184 days ago | IN | 0 XDAI | 0.00185013 | ||||
| Exec Transaction... | 41374055 | 184 days ago | IN | 0 XDAI | 0.00052972 | ||||
| Execute Next Tx | 41324731 | 187 days ago | IN | 0 XDAI | 0.00100893 | ||||
| Exec Transaction... | 41324693 | 187 days ago | IN | 0 XDAI | 0.00028761 | ||||
| Execute Next Tx | 41322961 | 187 days ago | IN | 0 XDAI | 0.00050397 | ||||
| Exec Transaction... | 41322926 | 187 days ago | IN | 0 XDAI | 0.00026298 | ||||
| Execute Next Tx | 41316626 | 188 days ago | IN | 0 XDAI | 0.00012346 | ||||
| Exec Transaction... | 41316588 | 188 days ago | IN | 0 XDAI | 0.00022451 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 40529027 | 235 days ago | Contract Creation | 0 XDAI |
Cross-Chain Transactions
Loading...
Loading
Minimal Proxy Contract for 0x4a97e65188a950dd4b0f21f9b5434daee0bbf9f5
Contract Name:
Delay
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0;
import {Enum, Modifier} from "@gnosis.pm/zodiac/contracts/core/Modifier.sol";
contract Delay is Modifier {
event DelaySetup(
address indexed initiator,
address indexed owner,
address indexed avatar,
address target
);
event TxCooldownSet(uint256 cooldown);
event TxExpirationSet(uint256 expiration);
event TxNonceSet(uint256 nonce);
event TransactionAdded(
uint256 indexed queueNonce,
bytes32 indexed txHash,
address to,
uint256 value,
bytes data,
Enum.Operation operation
);
uint256 public txCooldown;
uint256 public txExpiration;
uint256 public txNonce;
uint256 public queueNonce;
// Mapping of queue nonce to transaction hash.
mapping(uint256 => bytes32) public txHash;
// Mapping of queue nonce to creation timestamp.
mapping(uint256 => uint256) public txCreatedAt;
/// @param _owner Address of the owner
/// @param _avatar Address of the avatar (e.g. a Gnosis Safe)
/// @param _target Address of the contract that will call exec function
/// @param _cooldown Cooldown in seconds that should be required after a transaction is proposed
/// @param _expiration Duration that a proposed transaction is valid for after the cooldown, in seconds (or 0 if valid forever)
/// @notice There need to be at least 60 seconds between end of cooldown and expiration
constructor(
address _owner,
address _avatar,
address _target,
uint256 _cooldown,
uint256 _expiration
) {
bytes memory initParams = abi.encode(
_owner,
_avatar,
_target,
_cooldown,
_expiration
);
setUp(initParams);
}
function setUp(bytes memory initParams) public override initializer {
(
address _owner,
address _avatar,
address _target,
uint256 _cooldown,
uint256 _expiration
) = abi.decode(
initParams,
(address, address, address, uint256, uint256)
);
require(_avatar != address(0), "Avatar can not be zero address");
require(_target != address(0), "Target can not be zero address");
require(
_expiration == 0 || _expiration >= 60,
"Expiration must be 0 or at least 60 seconds"
);
_transferOwnership(_owner);
avatar = _avatar;
target = _target;
txExpiration = _expiration;
txCooldown = _cooldown;
setupModules();
emit DelaySetup(msg.sender, _owner, _avatar, _target);
emit AvatarSet(address(0), _avatar);
emit TargetSet(address(0), _target);
}
/// @dev Sets the cooldown before a transaction can be executed.
/// @param _txCooldown Cooldown in seconds that should be required before the transaction can be executed
/// @notice This can only be called by the owner
function setTxCooldown(uint256 _txCooldown) public onlyOwner {
txCooldown = _txCooldown;
emit TxCooldownSet(_txCooldown);
}
/// @dev Sets the duration for which a transaction is valid.
/// @param _txExpiration Duration that a transaction is valid in seconds (or 0 if valid forever) after the cooldown
/// @notice There need to be at least 60 seconds between end of cooldown and expiration
/// @notice This can only be called by the owner
function setTxExpiration(uint256 _txExpiration) public onlyOwner {
require(
_txExpiration == 0 || _txExpiration >= 60,
"Expiration must be 0 or at least 60 seconds"
);
txExpiration = _txExpiration;
emit TxExpirationSet(_txExpiration);
}
/// @dev Sets transaction nonce. Used to invalidate or skip transactions in queue.
/// @param _txNonce New transaction nonce
/// @notice This can only be called by the owner
function setTxNonce(uint256 _txNonce) public onlyOwner {
require(
_txNonce > txNonce,
"New nonce must be higher than current txNonce"
);
require(_txNonce <= queueNonce, "Cannot be higher than queueNonce");
txNonce = _txNonce;
emit TxNonceSet(_txNonce);
}
/// @dev Adds a transaction to the queue (same as avatar interface so that this can be placed between other modules and the avatar).
/// @param to Destination address of module transaction
/// @param value Ether value of module transaction
/// @param data Data payload of module transaction
/// @param operation Operation type of module transaction
/// @return success Whether or not the call was successfully queued for execution
/// @notice Can only be called by enabled modules
function execTransactionFromModule(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
) public override moduleOnly returns (bool success) {
bytes32 hash = getTransactionHash(to, value, data, operation);
txHash[queueNonce] = hash;
txCreatedAt[queueNonce] = block.timestamp;
emit TransactionAdded(queueNonce, hash, to, value, data, operation);
queueNonce++;
success = true;
}
/// @dev Adds a transaction to the queue (same as avatar interface so that this can be placed between other modules and the avatar).
/// @param to Destination address of module transaction
/// @param value Ether value of module transaction
/// @param data Data payload of module transaction
/// @param operation Operation type of module transaction
/// @return success Whether or not the call was successfully queued for execution
/// @return returnData ABI encoded queue nonce (uint256), transaction hash (bytes32), and block.timestamp (uint256)
/// @notice Can only be called by enabled modules
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
)
public
override
moduleOnly
returns (bool success, bytes memory returnData)
{
bytes32 hash = getTransactionHash(to, value, data, operation);
txHash[queueNonce] = hash;
txCreatedAt[queueNonce] = block.timestamp;
emit TransactionAdded(queueNonce, hash, to, value, data, operation);
success = true;
returnData = abi.encode(queueNonce, hash, block.timestamp);
queueNonce++;
}
/// @dev Executes the next transaction only if the cooldown has passed and the transaction has not expired
/// @param to Destination address of module transaction
/// @param value Ether value of module transaction
/// @param data Data payload of module transaction
/// @param operation Operation type of module transaction
/// @notice The txIndex used by this function is always 0
function executeNextTx(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
) public {
require(txNonce < queueNonce, "Transaction queue is empty");
uint256 txCreationTimestamp = txCreatedAt[txNonce];
require(
block.timestamp - txCreationTimestamp >= txCooldown,
"Transaction is still in cooldown"
);
if (txExpiration != 0) {
require(
txCreationTimestamp + txCooldown + txExpiration >=
block.timestamp,
"Transaction expired"
);
}
require(
txHash[txNonce] == getTransactionHash(to, value, data, operation),
"Transaction hashes do not match"
);
txNonce++;
require(exec(to, value, data, operation), "Module transaction failed");
}
function skipExpired() public {
while (
txExpiration != 0 &&
txCreatedAt[txNonce] + txCooldown + txExpiration <
block.timestamp &&
txNonce < queueNonce
) {
txNonce++;
}
}
function getTransactionHash(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(to, value, data, operation));
}
function getTxHash(uint256 _nonce) public view returns (bytes32) {
return (txHash[_nonce]);
}
function getTxCreatedAt(uint256 _nonce) public view returns (uint256) {
return (txCreatedAt[_nonce]);
}
}// SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; /// @title Enum - Collection of enums /// @author Richard Meissner - <[email protected]> contract Enum { enum Operation {Call, DelegateCall} }
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {Enum} from "@gnosis.pm/safe-contracts/contracts/common/Enum.sol";
import {ExecutionTracker} from "../signature/ExecutionTracker.sol";
import {IAvatar} from "../interfaces/IAvatar.sol";
import {Module} from "./Module.sol";
import {SignatureChecker} from "../signature/SignatureChecker.sol";
/// @title Modifier Interface - A contract that sits between a Module and an Avatar and enforce some additional logic.
abstract contract Modifier is
Module,
ExecutionTracker,
SignatureChecker,
IAvatar
{
address internal constant SENTINEL_MODULES = address(0x1);
/// Mapping of modules.
mapping(address => address) internal modules;
/// `sender` is not an authorized module.
/// @param sender The address of the sender.
error NotAuthorized(address sender);
/// `module` is invalid.
error InvalidModule(address module);
/// `pageSize` is invalid.
error InvalidPageSize();
/// `module` is already disabled.
error AlreadyDisabledModule(address module);
/// `module` is already enabled.
error AlreadyEnabledModule(address module);
/// @dev `setModules()` was already called.
error SetupModulesAlreadyCalled();
/*
--------------------------------------------------
You must override both of the following virtual functions,
execTransactionFromModule() and execTransactionFromModuleReturnData().
It is recommended that implementations of both functions make use the
onlyModule modifier.
*/
/// @dev Passes a transaction to the modifier.
/// @notice Can only be called by enabled modules.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModule(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
) public virtual returns (bool success);
/// @dev Passes a transaction to the modifier, expects return data.
/// @notice Can only be called by enabled modules.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction.
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation
) public virtual returns (bool success, bytes memory returnData);
/*
--------------------------------------------------
*/
modifier moduleOnly() {
if (modules[msg.sender] == address(0)) {
(bytes32 hash, address signer) = moduleTxSignedBy();
// is the signer a module?
if (modules[signer] == address(0)) {
revert NotAuthorized(msg.sender);
}
// is the provided signature fresh?
if (consumed[signer][hash]) {
revert HashAlreadyConsumed(hash);
}
consumed[signer][hash] = true;
emit HashExecuted(hash);
}
_;
}
function sentOrSignedByModule() internal view returns (address) {
if (modules[msg.sender] != address(0)) {
return msg.sender;
}
(, address signer) = moduleTxSignedBy();
if (modules[signer] != address(0)) {
return signer;
}
return address(0);
}
/// @dev Disables a module on the modifier.
/// @notice This can only be called by the owner.
/// @param prevModule Module that pointed to the module to be removed in the linked list.
/// @param module Module to be removed.
function disableModule(
address prevModule,
address module
) public override onlyOwner {
if (module == address(0) || module == SENTINEL_MODULES)
revert InvalidModule(module);
if (modules[prevModule] != module) revert AlreadyDisabledModule(module);
modules[prevModule] = modules[module];
modules[module] = address(0);
emit DisabledModule(module);
}
/// @dev Enables a module that can add transactions to the queue
/// @param module Address of the module to be enabled
/// @notice This can only be called by the owner
function enableModule(address module) public override onlyOwner {
if (module == address(0) || module == SENTINEL_MODULES)
revert InvalidModule(module);
if (modules[module] != address(0)) revert AlreadyEnabledModule(module);
modules[module] = modules[SENTINEL_MODULES];
modules[SENTINEL_MODULES] = module;
emit EnabledModule(module);
}
/// @dev Returns if an module is enabled
/// @return True if the module is enabled
function isModuleEnabled(
address _module
) public view override returns (bool) {
return SENTINEL_MODULES != _module && modules[_module] != address(0);
}
/// @dev Returns array of modules.
/// If all entries fit into a single page, the next pointer will be 0x1.
/// If another page is present, next will be the last element of the returned array.
/// @param start Start of the page. Has to be a module or start pointer (0x1 address)
/// @param pageSize Maximum number of modules that should be returned. Has to be > 0
/// @return array Array of modules.
/// @return next Start of the next page.
function getModulesPaginated(
address start,
uint256 pageSize
) external view override returns (address[] memory array, address next) {
if (start != SENTINEL_MODULES && !isModuleEnabled(start)) {
revert InvalidModule(start);
}
if (pageSize == 0) {
revert InvalidPageSize();
}
// Init array with max page size
array = new address[](pageSize);
// Populate return array
uint256 moduleCount = 0;
next = modules[start];
while (
next != address(0) && next != SENTINEL_MODULES && moduleCount < pageSize
) {
array[moduleCount] = next;
next = modules[next];
moduleCount++;
}
// Because of the argument validation we can assume that
// the `currentModule` will always be either a module address
// or sentinel address (aka the end). If we haven't reached the end
// inside the loop, we need to set the next pointer to the last element
// because it skipped over to the next module which is neither included
// in the current page nor won't be included in the next one
// if you pass it as a start.
if (next != SENTINEL_MODULES) {
next = array[moduleCount - 1];
}
// Set correct size of returned array
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(array, moduleCount)
}
}
/// @dev Initializes the modules linked list.
/// @notice Should be called as part of the `setUp` / initializing function and can only be called once.
function setupModules() internal {
if (modules[SENTINEL_MODULES] != address(0))
revert SetupModulesAlreadyCalled();
modules[SENTINEL_MODULES] = SENTINEL_MODULES;
}
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {Enum} from "@gnosis.pm/safe-contracts/contracts/common/Enum.sol";
import {FactoryFriendly} from "../factory/FactoryFriendly.sol";
import {IAvatar} from "../interfaces/IAvatar.sol";
/// @title Module Interface - A contract that can pass messages to a Module Manager contract if enabled by that contract.
abstract contract Module is FactoryFriendly {
/// @dev Address that will ultimately execute function calls.
address public avatar;
/// @dev Address that this module will pass transactions to.
address public target;
/// @dev Emitted each time the avatar is set.
event AvatarSet(address indexed previousAvatar, address indexed newAvatar);
/// @dev Emitted each time the Target is set.
event TargetSet(address indexed previousTarget, address indexed newTarget);
/// @dev Sets the avatar to a new avatar (`newAvatar`).
/// @notice Can only be called by the current owner.
function setAvatar(address _avatar) public onlyOwner {
address previousAvatar = avatar;
avatar = _avatar;
emit AvatarSet(previousAvatar, _avatar);
}
/// @dev Sets the target to a new target (`newTarget`).
/// @notice Can only be called by the current owner.
function setTarget(address _target) public onlyOwner {
address previousTarget = target;
target = _target;
emit TargetSet(previousTarget, _target);
}
/// @dev Passes a transaction to be executed by the avatar.
/// @notice Can only be called by this contract.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction: 0 == call, 1 == delegate call.
function exec(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) internal virtual returns (bool success) {
return
IAvatar(target).execTransactionFromModule(to, value, data, operation);
}
/// @dev Passes a transaction to be executed by the target and returns data.
/// @notice Can only be called by this contract.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction: 0 == call, 1 == delegate call.
function execAndReturnData(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) internal virtual returns (bool success, bytes memory returnData) {
return
IAvatar(target).execTransactionFromModuleReturnData(
to,
value,
data,
operation
);
}
}// SPDX-License-Identifier: LGPL-3.0-only
/// @title Zodiac FactoryFriendly - A contract that allows other contracts to be initializable and pass bytes as arguments to define contract state
pragma solidity >=0.7.0 <0.9.0;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
abstract contract FactoryFriendly is OwnableUpgradeable {
function setUp(bytes memory initializeParams) public virtual;
}// SPDX-License-Identifier: LGPL-3.0-only
/// @title Zodiac Avatar - A contract that manages modules that can execute transactions via this contract.
pragma solidity >=0.7.0 <0.9.0;
import {Enum} from "@gnosis.pm/safe-contracts/contracts/common/Enum.sol";
interface IAvatar {
event EnabledModule(address module);
event DisabledModule(address module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionFromModuleFailure(address indexed module);
/// @dev Enables a module on the avatar.
/// @notice Can only be called by the avatar.
/// @notice Modules should be stored as a linked list.
/// @notice Must emit EnabledModule(address module) if successful.
/// @param module Module to be enabled.
function enableModule(address module) external;
/// @dev Disables a module on the avatar.
/// @notice Can only be called by the avatar.
/// @notice Must emit DisabledModule(address module) if successful.
/// @param prevModule Address that pointed to the module to be removed in the linked list
/// @param module Module to be removed.
function disableModule(address prevModule, address module) external;
/// @dev Allows a Module to execute a transaction.
/// @notice Can only be called by an enabled module.
/// @notice Must emit ExecutionFromModuleSuccess(address module) if successful.
/// @notice Must emit ExecutionFromModuleFailure(address module) if unsuccessful.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction: 0 == call, 1 == delegate call.
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success);
/// @dev Allows a Module to execute a transaction and return data
/// @notice Can only be called by an enabled module.
/// @notice Must emit ExecutionFromModuleSuccess(address module) if successful.
/// @notice Must emit ExecutionFromModuleFailure(address module) if unsuccessful.
/// @param to Destination address of module transaction.
/// @param value Ether value of module transaction.
/// @param data Data payload of module transaction.
/// @param operation Operation type of module transaction: 0 == call, 1 == delegate call.
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success, bytes memory returnData);
/// @dev Returns if an module is enabled
/// @return True if the module is enabled
function isModuleEnabled(address module) external view returns (bool);
/// @dev Returns array of modules.
/// @param start Start of the page.
/// @param pageSize Maximum number of modules that should be returned.
/// @return array Array of modules.
/// @return next Start of the next page.
function getModulesPaginated(
address start,
uint256 pageSize
) external view returns (address[] memory array, address next);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0 <0.9.0;
/// @title ExecutionTracker - A contract that keeps track of executed and invalidated hashes
contract ExecutionTracker {
error HashAlreadyConsumed(bytes32);
event HashExecuted(bytes32);
event HashInvalidated(bytes32);
mapping(address => mapping(bytes32 => bool)) public consumed;
function invalidate(bytes32 hash) external {
consumed[msg.sender][hash] = true;
emit HashInvalidated(hash);
}
}// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity >=0.7.0 <0.9.0;
interface IERC1271 {
/**
* @notice EIP1271 method to validate a signature.
* @param hash Hash of the data signed on the behalf of address(this).
* @param signature Signature byte array associated with _data.
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(
bytes32 hash,
bytes memory signature
) external view returns (bytes4);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0 <0.9.0;
import {IERC1271} from "./IERC1271.sol";
/// @title SignatureChecker - A contract that retrieves and validates signatures appended to transaction calldata.
/// @dev currently supports eip-712 and eip-1271 signatures
abstract contract SignatureChecker {
/**
* @notice Searches for a signature, validates it, and returns the signer's address.
* @dev When signature not found or invalid, zero address is returned
* @return The address of the signer.
*/
function moduleTxSignedBy() internal view returns (bytes32, address) {
bytes calldata data = msg.data;
/*
* The idea is to extend `onlyModule` and provide signature checking
* without code changes to inheriting contracts (Modifiers).
*
* Since it's a generic mechanism, there is no way to conclusively
* identify the trailing bytes as a signature. We simply slice those
* and recover signer.
*
* As a result, we impose a minimum calldata length equal to a function
* selector plus salt, plus a signature (i.e., 4 + 32 + 65 bytes), any
* shorter and calldata it guaranteed to not contain a signature.
*/
if (data.length < 4 + 32 + 65) {
return (bytes32(0), address(0));
}
(uint8 v, bytes32 r, bytes32 s) = _splitSignature(data);
uint256 end = data.length - (32 + 65);
bytes32 salt = bytes32(data[end:]);
/*
* When handling contract signatures:
* v - is zero
* r - contains the signer
* s - contains the offset within calldata where the signer specific
* signature is located
*
* We detect contract signatures by checking:
* 1- `v` is zero
* 2- `s` points within the buffer, is after selector, is before
* salt and delimits a non-zero length buffer
*/
if (v == 0) {
uint256 start = uint256(s);
if (start < 4 || start > end) {
return (bytes32(0), address(0));
}
address signer = address(uint160(uint256(r)));
bytes32 hash = moduleTxHash(data[:start], salt);
return
_isValidContractSignature(signer, hash, data[start:end])
? (hash, signer)
: (bytes32(0), address(0));
} else {
bytes32 hash = moduleTxHash(data[:end], salt);
return (hash, ecrecover(hash, v, r, s));
}
}
/**
* @notice Hashes the transaction EIP-712 data structure.
* @dev The produced hash is intended to be signed.
* @param data The current transaction's calldata.
* @param salt The salt value.
* @return The 32-byte hash that is to be signed.
*/
function moduleTxHash(
bytes calldata data,
bytes32 salt
) public view returns (bytes32) {
bytes32 domainSeparator = keccak256(
abi.encode(DOMAIN_SEPARATOR_TYPEHASH, block.chainid, this)
);
bytes memory moduleTxData = abi.encodePacked(
bytes1(0x19),
bytes1(0x01),
domainSeparator,
keccak256(abi.encode(MODULE_TX_TYPEHASH, keccak256(data), salt))
);
return keccak256(moduleTxData);
}
/**
* @dev Extracts signature from calldata, and divides it into `uint8 v, bytes32 r, bytes32 s`.
* @param data The current transaction's calldata.
* @return v The ECDSA v value
* @return r The ECDSA r value
* @return s The ECDSA s value
*/
function _splitSignature(
bytes calldata data
) private pure returns (uint8 v, bytes32 r, bytes32 s) {
v = uint8(bytes1(data[data.length - 1:]));
r = bytes32(data[data.length - 65:]);
s = bytes32(data[data.length - 33:]);
}
/**
* @dev Calls the signer contract, and validates the contract signature.
* @param signer The address of the signer contract.
* @param hash Hash of the data signed
* @param signature The contract signature.
* @return result Indicates whether the signature is valid.
*/
function _isValidContractSignature(
address signer,
bytes32 hash,
bytes calldata signature
) internal view returns (bool result) {
uint256 size;
// eslint-disable-line no-inline-assembly
assembly {
size := extcodesize(signer)
}
if (size == 0) {
return false;
}
(, bytes memory returnData) = signer.staticcall(
abi.encodeWithSelector(
IERC1271.isValidSignature.selector,
hash,
signature
)
);
return bytes4(returnData) == EIP1271_MAGIC_VALUE;
}
// keccak256(
// "EIP712Domain(uint256 chainId,address verifyingContract)"
// );
bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH =
0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
// keccak256(
// "ModuleTx(bytes data,bytes32 salt)"
// );
bytes32 private constant MODULE_TX_TYPEHASH =
0x2939aeeda3ca260200c9f7b436b19e13207547ccc65cfedc857751c5ea6d91d4;
// bytes4(keccak256(
// "isValidSignature(bytes32,bytes)"
// ));
bytes4 private constant EIP1271_MAGIC_VALUE = 0x1626ba7e;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_avatar","type":"address"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_cooldown","type":"uint256"},{"internalType":"uint256","name":"_expiration","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"AlreadyDisabledModule","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"AlreadyEnabledModule","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"HashAlreadyConsumed","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"InvalidModule","type":"error"},{"inputs":[],"name":"InvalidPageSize","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"SetupModulesAlreadyCalled","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousAvatar","type":"address"},{"indexed":true,"internalType":"address","name":"newAvatar","type":"address"}],"name":"AvatarSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"initiator","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"avatar","type":"address"},{"indexed":false,"internalType":"address","name":"target","type":"address"}],"name":"DelaySetup","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"DisabledModule","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"module","type":"address"}],"name":"EnabledModule","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"module","type":"address"}],"name":"ExecutionFromModuleFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"module","type":"address"}],"name":"ExecutionFromModuleSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"","type":"bytes32"}],"name":"HashExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"","type":"bytes32"}],"name":"HashInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTarget","type":"address"},{"indexed":true,"internalType":"address","name":"newTarget","type":"address"}],"name":"TargetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queueNonce","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"txHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"enum Enum.Operation","name":"operation","type":"uint8"}],"name":"TransactionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cooldown","type":"uint256"}],"name":"TxCooldownSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"TxExpirationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"TxNonceSet","type":"event"},{"inputs":[],"name":"avatar","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"consumed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"prevModule","type":"address"},{"internalType":"address","name":"module","type":"address"}],"name":"disableModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"module","type":"address"}],"name":"enableModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum Enum.Operation","name":"operation","type":"uint8"}],"name":"execTransactionFromModule","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum Enum.Operation","name":"operation","type":"uint8"}],"name":"execTransactionFromModuleReturnData","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum Enum.Operation","name":"operation","type":"uint8"}],"name":"executeNextTx","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"start","type":"address"},{"internalType":"uint256","name":"pageSize","type":"uint256"}],"name":"getModulesPaginated","outputs":[{"internalType":"address[]","name":"array","type":"address[]"},{"internalType":"address","name":"next","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum Enum.Operation","name":"operation","type":"uint8"}],"name":"getTransactionHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getTxCreatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getTxHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"invalidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_module","type":"address"}],"name":"isModuleEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"moduleTxHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queueNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_avatar","type":"address"}],"name":"setAvatar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"}],"name":"setTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txCooldown","type":"uint256"}],"name":"setTxCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txExpiration","type":"uint256"}],"name":"setTxExpiration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txNonce","type":"uint256"}],"name":"setTxNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"initParams","type":"bytes"}],"name":"setUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skipExpired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"target","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"txCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"txCreatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"txExpiration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"txHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"txNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in XDAI
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.