Overview
ETH Balance
ETH Value
$0.00Latest 7 from a total of 7 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Execute Bundle | 426417258 | 4 days ago | IN | 0 ETH | 0.00000405 | ||||
| Execute Bundle | 425374852 | 7 days ago | IN | 0 ETH | 0.00000404 | ||||
| Execute Bundle | 424413659 | 10 days ago | IN | 0 ETH | 0.00000412 | ||||
| Execute Bundle | 424335252 | 10 days ago | IN | 0 ETH | 0.00000404 | ||||
| Execute Bundle | 423030094 | 14 days ago | IN | 0 ETH | 0.00002776 | ||||
| Execute Bundle | 421230632 | 19 days ago | IN | 0 ETH | 0.00000412 | ||||
| Execute Bundle | 420556492 | 21 days ago | IN | 0 ETH | 0.00000632 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 419154426 | 25 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712TypedDataLib} from "../libraries/EIP712TypedDataLib.sol";
import {Errors} from "../Errors.sol";
import {IAdminVault} from "../interfaces/IAdminVault.sol";
import {ISafe} from "../interfaces/safe/ISafe.sol";
import {IOwnerManager} from "../interfaces/safe/IOwnerManager.sol";
import {ISafeDeployment} from "../interfaces/ISafeDeployment.sol";
import {ITokenRegistry} from "../interfaces/ITokenRegistry.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IGasPriceAdaptor} from "../interfaces/IGasPriceAdaptor.sol";
import {Enum} from "../libraries/Enum.sol";
import {ActionBase} from "../actions/ActionBase.sol";
import {ISequenceExecutor} from "../interfaces/ISequenceExecutor.sol";
import {IEip712TypedDataSafeModule as ITyped} from "../interfaces/IEip712TypedDataSafeModule.sol";
/// @title EIP712TypedDataSafeModule
/// @notice Safe module that handles EIP-712 typed data signing for cross-chain bundle execution
/// @notice Verifies signatures against Safe owners and forwards validated sequences to the sequence executor
/// @notice Includes optional gas refund functionality with economic protections
/// @dev Designed for 1-of-1 Safes: this module verifies the signer is an owner but does not enforce Safe threshold
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
contract EIP712TypedDataSafeModule {
using ECDSA for bytes32;
using SafeERC20 for IERC20;
// EIP-712 helpers are provided by a library to reduce bytecode size
// Struct types provided by interface ITyped
struct ExecutorSequence {
string name;
bytes[] callData;
bytes4[] actionIds;
}
IAdminVault public ADMIN_VAULT;
address public SEQUENCE_EXECUTOR_ADDR;
ISafeDeployment public SAFE_DEPLOYMENT;
ITokenRegistry public TOKEN_REGISTRY;
address public FEE_RECIPIENT;
address public usdcToken; // set post-deploy to preserve deterministic bytecode
address public immutable CONFIG_SETTER;
bytes4 public constant EXECUTE_SEQUENCE_SELECTOR = ISequenceExecutor.executeSequence.selector;
string public domainName;
string public domainVersion;
bool public isInitialized;
mapping(address => uint256) public sequenceNonces;
// Gas/refund context is computed inline in executeBundle; no persistent storage required
event BundleExecuted(address indexed safe, uint256 indexed expiry, uint256 indexed chainId, uint256 sequenceNonce);
event GasRefundProcessed(address indexed safe, address indexed refundToken, uint256 refundAmount, address indexed recipient);
// =============================
// Gas refund config
// =============================
uint256 public gasRefundOverhead;
address public gasPriceAdaptor;
event SignatureVerified(address indexed safe, address indexed signer, bytes32 indexed bundleHash);
event SafeDeployedForExecution(address indexed signer, address indexed safeAddress);
event ConfigInitialized(
address adminVault,
address sequenceExecutor,
address safeDeployment,
address tokenRegistry,
address feeRecipient,
string name,
string version
);
constructor(address _configSetter) {
require(_configSetter != address(0), "Invalid input");
CONFIG_SETTER = _configSetter;
}
/// @notice One-time initializer to set all external references and domain fields
/// @dev Callable only once by CONFIG_SETTER for deterministic deployment across chains
/// @param _gasRefundOverhead Gas consumed after measurement point (transfers, events, return path)
function initializeConfig(
address _adminVault,
address _sequenceExecutor,
address _safeDeployment,
address _tokenRegistry,
address _feeRecipient,
address _usdcToken,
address _gasPriceAdaptor,
uint256 _gasRefundOverhead,
string memory _domainName,
string memory _domainVersion
) external {
require(msg.sender == CONFIG_SETTER, "Unauthorized");
require(!isInitialized, "Already initialized");
require(
_adminVault != address(0) &&
_sequenceExecutor != address(0) &&
_safeDeployment != address(0) &&
_tokenRegistry != address(0) &&
_feeRecipient != address(0) &&
_usdcToken != address(0) &&
_gasPriceAdaptor != address(0),
"Invalid input"
);
ADMIN_VAULT = IAdminVault(_adminVault);
SEQUENCE_EXECUTOR_ADDR = _sequenceExecutor;
SAFE_DEPLOYMENT = ISafeDeployment(_safeDeployment);
TOKEN_REGISTRY = ITokenRegistry(_tokenRegistry);
FEE_RECIPIENT = _feeRecipient;
usdcToken = _usdcToken;
gasPriceAdaptor = _gasPriceAdaptor;
gasRefundOverhead = _gasRefundOverhead;
domainName = _domainName;
domainVersion = _domainVersion;
isInitialized = true;
emit ConfigInitialized(
_adminVault,
_sequenceExecutor,
_safeDeployment,
_tokenRegistry,
_feeRecipient,
_domainName,
_domainVersion
);
}
/// @notice Executes a validated bundle for the current chain and nonce
/// @dev This is the main entry point with explicit Safe address and controlled deployment
/// @dev Expects single-owner Safes; verifies signer ownership but does not enforce Safe threshold
/// @param _safeAddr The Safe address to execute on (used for domain verification)
/// @param _bundle The bundle containing sequences for multiple chains
/// @param _signature EIP-712 signature from a Safe owner
function executeBundle(
address _safeAddr,
ITyped.Bundle calldata _bundle,
bytes calldata _signature
) external payable {
// Record gas and executor at entry
uint256 gasStart = gasleft();
// Guard: config set during initializeConfig(); a single check is enough
require(address(ADMIN_VAULT) != address(0), "Config not initialized");
// Verify bundle hasn't expired
if (_bundle.expiry <= block.timestamp) {
revert Errors.EIP712TypedDataSafeModule_BundleExpired();
}
// Verify EIP-712 signature using Safe address as verifying contract
bytes32 digest = EIP712TypedDataLib.hashBundleForSigning(domainName, domainVersion, _safeAddr, _bundle);
address signer = digest.recover(_signature);
if (signer == address(0)) {
revert Errors.EIP712TypedDataSafeModule_InvalidSignature();
}
emit SignatureVerified(_safeAddr, signer, digest);
// Find the sequence for current chain and next nonce
uint256 expectedSequenceNonce = sequenceNonces[_safeAddr];
ITyped.ChainSequence memory targetSequence = _findChainSequence(
_bundle.sequences,
block.chainid,
expectedSequenceNonce
);
// Handle Safe deployment if requested
if (targetSequence.deploySafe) {
// Validate that the provided Safe address matches predicted deployment address
address predictedSafeAddr = SAFE_DEPLOYMENT.predictSafeAddress(signer);
if (_safeAddr != predictedSafeAddr) {
revert Errors.EIP712TypedDataSafeModule_SafeAddressMismatch(_safeAddr, predictedSafeAddr);
}
// Deploy Safe if it doesn't exist
if (!SAFE_DEPLOYMENT.isSafeDeployed(signer)) {
try SAFE_DEPLOYMENT.deploySafe(signer) returns (address deployedSafeAddr) {
emit SafeDeployedForExecution(signer, deployedSafeAddr);
} catch {
revert Errors.EIP712TypedDataSafeModule_SafeDeploymentFailed();
}
}
}
// Verify signer is a Safe owner (after potential deployment)
if (!IOwnerManager(_safeAddr).isOwner(signer)) {
revert Errors.EIP712TypedDataSafeModule_SignerNotOwner(signer);
}
// Validate actions and detect if a gas refund action is present (reverse scan for gas efficiency)
(bytes4[] memory actionIds, bool hasRefundAction) = _validateSequenceActionsAndDetectRefund(
targetSequence.sequence,
targetSequence.refundRecipient
);
// Enforce enableGasRefund flag consistency with presence of GasRefundAction
if (targetSequence.enableGasRefund && !hasRefundAction) {
revert Errors.EIP712TypedDataSafeModule_RefundActionRequired();
}
if (!targetSequence.enableGasRefund && hasRefundAction) {
revert Errors.EIP712TypedDataSafeModule_RefundActionNotAllowed();
}
// Update sequence nonce
sequenceNonces[_safeAddr] = expectedSequenceNonce + 1;
// Execute the sequence via Safe module transaction
bool ok = _execThroughSafe(
_safeAddr,
ExecutorSequence({
name: targetSequence.sequence.name,
callData: targetSequence.sequence.callData,
actionIds: actionIds
}),
_bundle,
_signature
);
if (!ok) {
revert Errors.EIP712TypedDataSafeModule_ExecutionFailed();
}
// Perform gas refund within module scope if enabled
if (targetSequence.enableGasRefund) {
_executeGasRefund(
_safeAddr,
targetSequence.maxRefundAmount,
targetSequence.refundRecipient,
gasStart
);
}
emit BundleExecuted(_safeAddr, _bundle.expiry, block.chainid, expectedSequenceNonce);
}
/// @dev Uses `bytes memory` for signature (not calldata) to support estimateBundleGas
/// which passes an empty signature. Gas impact is negligible since abi.encodeWithSelector
/// copies the data anyway.
function _execThroughSafe(
address safeAddr,
ExecutorSequence memory execSeq,
ITyped.Bundle calldata bundle,
bytes memory signature
) private returns (bool) {
return ISafe(safeAddr).execTransactionFromModule(
SEQUENCE_EXECUTOR_ADDR,
0,
abi.encodeWithSelector(
EXECUTE_SEQUENCE_SELECTOR,
execSeq,
bundle,
signature,
uint16(0)
),
Enum.Operation.DelegateCall
);
}
// Gas context is handled inline in executeBundle
/// @notice Gets the next expected sequence nonce for a Safe
/// @param _safeAddr Address of the Safe
/// @return The next expected sequence nonce
function getSequenceNonce(address _safeAddr) external view returns (uint256) {
return sequenceNonces[_safeAddr];
}
/// @notice Gets the EIP-712 domain separator for a specific Safe address
/// @param _safeAddr The Safe address to use as verifying contract
/// @return The domain separator
/// @dev Uses hardcoded chainID 1 for cross-chain compatibility as part of cross-chain domain design
function getDomainSeparator(address _safeAddr) external view returns (bytes32) {
return EIP712TypedDataLib.domainSeparator(domainName, domainVersion, _safeAddr);
}
/// @notice Computes the EIP-712 hash for a bundle (view function for external verification)
/// @param _safeAddr The Safe address to use as verifying contract
/// @param _bundle The bundle to hash
/// @return The EIP-712 hash that should be signed
function getBundleHash(address _safeAddr, ITyped.Bundle calldata _bundle) external view returns (bytes32) {
return EIP712TypedDataLib.hashBundleForSigning(domainName, domainVersion, _safeAddr, _bundle);
}
/// @notice Computes the raw bundle hash (for testing purposes)
/// @param _bundle The bundle to hash
/// @return The raw bundle hash (before EIP-712 domain separator)
function getRawBundleHash(ITyped.Bundle calldata _bundle) external pure returns (bytes32) {
return EIP712TypedDataLib.hashBundle(_bundle);
}
// =============================
// Internal: Gas refund
// =============================
function _executeGasRefund(
address safe,
uint256 maxRefundAmount,
uint8 refundRecipient,
uint256 gasStart
) internal {
IERC20 token = IERC20(usdcToken);
uint256 moduleDeposit = token.balanceOf(address(this));
// If no deposit, nothing to do
if (moduleDeposit == 0) return;
// Calculate refund amount - use zero values if any step fails
uint256 refundAmount = 0;
address recipient = address(0);
// Try to get gas pricing rate
(uint256 ratePerGas, uint256 fixedFee) = _safeGetRefundRate();
if (ratePerGas > 0) {
// Measure gas consumption including overhead
uint256 gasUsed = gasStart > gasleft() ? (gasStart - gasleft() + gasRefundOverhead) : 0;
if (gasUsed > 0) {
// Calculate refund amount in USDC
refundAmount = (gasUsed * ratePerGas) / 1e18 + fixedFee;
// Cap at max if specified
if (maxRefundAmount > 0 && refundAmount > maxRefundAmount) {
refundAmount = maxRefundAmount;
}
// Determine recipient
recipient = refundRecipient == 0 ? tx.origin : FEE_RECIPIENT;
}
}
// Pay refund if we calculated a valid amount
uint256 paidAmount = 0;
if (refundAmount > 0 && recipient != address(0)) {
uint256 payAmount = refundAmount <= moduleDeposit ? refundAmount : moduleDeposit;
token.safeTransfer(recipient, payAmount);
paidAmount = payAmount;
}
// ALWAYS return any remaining balance to the Safe
uint256 remainder = token.balanceOf(address(this));
if (remainder > 0) {
token.safeTransfer(safe, remainder);
}
emit GasRefundProcessed(safe, usdcToken, paidAmount, recipient != address(0) ? recipient : safe);
}
/// @notice Safely get refund rate from gas price adaptor
/// @dev Returns (0, 0) if the call fails instead of reverting
function _safeGetRefundRate() internal view returns (uint256 ratePerGas, uint256 fixedFee) {
try IGasPriceAdaptor(gasPriceAdaptor).getRefundRate(usdcToken, msg.data)
returns (uint256 rate, uint256 fee)
{
return (rate, fee);
} catch {
return (0, 0);
}
}
// Oracle math is implemented in the adaptor
/// @notice Finds the chain sequence for the current chain and expected nonce
/// @param _sequences Array of chain sequences
/// @param _chainId Target chain ID
/// @param _expectedNonce Expected sequence nonce
/// @return The matching chain sequence
function _findChainSequence(
ITyped.ChainSequence[] memory _sequences,
uint256 _chainId,
uint256 _expectedNonce
) internal pure returns (ITyped.ChainSequence memory) {
for (uint256 i = 0; i < _sequences.length; i++) {
if (_sequences[i].chainId == _chainId && _sequences[i].sequenceNonce == _expectedNonce) {
return _sequences[i];
}
}
revert Errors.EIP712TypedDataSafeModule_ChainSequenceNotFound(_chainId, _expectedNonce);
}
/// @notice Validates action metadata, registration, and detects presence of GasRefundAction
/// @param _sequence The sequence to validate
/// @return actionIds Array of action IDs from the sequence
/// @return hasRefundAction True if a GasRefundAction is present in the sequence
function _validateSequenceActionsAndDetectRefund(ITyped.Sequence memory _sequence, uint8 _refundRecipient)
internal
view
returns (bytes4[] memory actionIds, bool hasRefundAction)
{
if (_sequence.actions.length != _sequence.callData.length ||
_sequence.actions.length != _sequence.actionIds.length) {
revert Errors.EIP712TypedDataSafeModule_LengthMismatch();
}
actionIds = _sequence.actionIds;
hasRefundAction = false;
// Scan from last to first expecting refund action near the end
for (uint256 i = _sequence.actions.length; i > 0; i--) {
uint256 idx = i - 1;
bytes4 actionId = _sequence.actionIds[idx];
// Get the action contract address
address actionAddr = ADMIN_VAULT.getActionAddress(actionId);
if (actionAddr == address(0)) {
revert Errors.EIP712TypedDataSafeModule_ActionNotFound(actionId);
}
// Verify protocol name and action type match
ActionBase action = ActionBase(actionAddr);
string memory actualProtocolName = action.protocolName();
uint8 actualActionType = action.actionType();
// Compare with expected values from typed data
ITyped.ActionDefinition memory expectedAction = _sequence.actions[idx];
if (
keccak256(bytes(actualProtocolName)) != keccak256(bytes(expectedAction.protocolName)) ||
actualActionType != expectedAction.actionType
) {
revert Errors.EIP712TypedDataSafeModule_ActionMismatch(
idx,
expectedAction.protocolName,
expectedAction.actionType,
actualProtocolName,
actualActionType
);
}
// Detect GasRefundAction via ActionType.FEE_ACTION
if (!hasRefundAction && actualActionType == uint8(ActionBase.ActionType.FEE_ACTION)) {
// Enforce valid refund recipient at module-level: 0=executor, 1=fee recipient
if (!(_refundRecipient == 0 || _refundRecipient == 1)) {
revert Errors.EIP712TypedDataSafeModule_InvalidRefundRecipient(_refundRecipient);
}
hasRefundAction = true;
}
}
}
// Gas refunds are processed by this module when enabled; a fee action deposits the refund token before execution.
// =============================================================
// EIP-712 HASHING HELPERS
// =============================================================
/// @notice Hash an ActionDefinition following proven EIP-712 patterns
// Hash helpers are implemented in the library
// =============================================================
// GAS ESTIMATION HELPER
// =============================================================
/// @notice Custom error used to signal successful gas estimation simulation
/// @param gasUsed The estimated gas consumed by the bundle execution
error SimulationComplete(uint256 gasUsed);
/// @notice Estimates gas for a bundle without requiring a signature
/// @dev This function ALWAYS reverts - it is designed for simulation only
/// @dev Call this via eth_call or Tenderly simulation with `from` set to user address
/// @dev State overrides should be used to:
/// - Set token balances on Safe (for CCTP destination chains)
/// @param _safeAddr The Safe address to execute on (must match predicted address for msg.sender)
/// @param _bundle The bundle containing sequences for multiple chains
/// @dev The function uses msg.sender as the signer, so simulations should set `from` to the user's address
function estimateBundleGas(
address _safeAddr,
ITyped.Bundle calldata _bundle
) external {
// Record gas at entry for accurate measurement
uint256 gasStart = gasleft();
// Guard: config set during initializeConfig()
require(address(ADMIN_VAULT) != address(0), "Config not initialized");
// No expiry check for estimation - we want to estimate regardless of timing
// Use msg.sender as the signer (simulation sets from=userAddress)
address signer = msg.sender;
// Find the sequence for current chain and next nonce
uint256 expectedSequenceNonce = sequenceNonces[_safeAddr];
ITyped.ChainSequence memory targetSequence = _findChainSequence(
_bundle.sequences,
block.chainid,
expectedSequenceNonce
);
// Handle Safe deployment if requested (deploys with msg.sender as owner)
if (targetSequence.deploySafe) {
// Validate that the provided Safe address matches predicted deployment address
address predictedSafeAddr = SAFE_DEPLOYMENT.predictSafeAddress(signer);
if (_safeAddr != predictedSafeAddr) {
revert Errors.EIP712TypedDataSafeModule_SafeAddressMismatch(_safeAddr, predictedSafeAddr);
}
// Deploy Safe if it doesn't exist
if (!SAFE_DEPLOYMENT.isSafeDeployed(signer)) {
try SAFE_DEPLOYMENT.deploySafe(signer) returns (address deployedSafeAddr) {
emit SafeDeployedForExecution(signer, deployedSafeAddr);
} catch {
revert Errors.EIP712TypedDataSafeModule_SafeDeploymentFailed();
}
}
}
// Skip ownership verification - msg.sender may not be owner yet if Safe was just deployed
// In real execution, the signature proves ownership. In simulation, we trust msg.sender.
// Validate actions and detect if a gas refund action is present
(bytes4[] memory actionIds, bool hasRefundAction) = _validateSequenceActionsAndDetectRefund(
targetSequence.sequence,
targetSequence.refundRecipient
);
// Enforce enableGasRefund flag consistency with presence of GasRefundAction
if (targetSequence.enableGasRefund && !hasRefundAction) {
revert Errors.EIP712TypedDataSafeModule_RefundActionRequired();
}
if (!targetSequence.enableGasRefund && hasRefundAction) {
revert Errors.EIP712TypedDataSafeModule_RefundActionNotAllowed();
}
// Note: We don't update the nonce in simulation - this is estimation only
// Execute the sequence via Safe module transaction
// For estimation, we pass empty signature - actions should not validate it for gas estimation
bool ok = _execThroughSafe(
_safeAddr,
ExecutorSequence({
name: targetSequence.sequence.name,
callData: targetSequence.sequence.callData,
actionIds: actionIds
}),
_bundle,
new bytes(0) // Empty signature - estimation only
);
if (!ok) {
revert Errors.EIP712TypedDataSafeModule_ExecutionFailed();
}
// Calculate gas used
uint256 gasUsed = gasStart - gasleft();
// Add gas refund overhead estimate if enabled
if (targetSequence.enableGasRefund) {
gasUsed += gasRefundOverhead;
}
// Always revert with the gas estimate - this prevents any state changes
// and allows the simulation to capture the gas used
revert SimulationComplete(gasUsed);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @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
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile 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 {MessageHashUtils-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]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
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.
assembly ("memory-safe") {
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, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile 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 {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
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[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
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.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// 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, s);
}
// 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, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @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, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IAdminVault} from "../interfaces/IAdminVault.sol";
import {ILogger} from "../interfaces/ILogger.sol";
import {Errors} from "../Errors.sol";
/// @title ActionBase - Base contract for all actions in the protocol
/// @notice Implements common functionality and interfaces for all actions
/// @dev This contract should be inherited by all specific action contracts
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
abstract contract ActionBase {
using SafeERC20 for IERC20;
/// @notice Interface for the admin vault
IAdminVault public immutable ADMIN_VAULT;
/// @notice Interface for the logger
ILogger public immutable LOGGER;
/// @notice Basis points for fee calculations (100% = 10000)
uint256 public constant FEE_BASIS_POINTS = 10000;
/// @notice Duration of a fee period (1 year)
uint256 public constant FEE_PERIOD = 365 days;
/// @notice Enum representing different types of actions
enum ActionType {
DEPOSIT_ACTION,
WITHDRAW_ACTION,
SWAP_ACTION,
COVER_ACTION,
FEE_ACTION,
TRANSFER_ACTION,
CUSTOM_ACTION
}
/// @notice Enum representing different types of logs
// List of log types, this list should be updated with each new log type added to the system.
// Existing values should not be changed/removed, as they may be already in use by a deployed action.
// UNUSED keeps the enum starting at index 1 for off-chain processing.
enum LogType {
UNUSED,
BALANCE_UPDATE,
BUY_COVER,
CURVE_3POOL_SWAP,
SEND_TOKEN,
PULL_TOKEN,
PARASWAP_SWAP,
UPGRADE_ACTION,
WITHDRAWAL_REQUEST,
BUY_COVER_WITH_PREMIUM,
ZERO_EX_SWAP,
GAS_REFUND,
CCTP_BRIDGE_SEND
}
/// @notice Initializes the ActionBase contract
/// @param _adminVault Address of the admin vault
/// @param _logger Address of the logger contract
constructor(address _adminVault, address _logger) {
ADMIN_VAULT = IAdminVault(_adminVault);
LOGGER = ILogger(_logger);
}
/// @notice Executes the implemented action
/// @dev This function should be overridden by inheriting contracts
/// @param _callData Encoded input data for the action
/// @param _strategyId The ID of the strategy executing this action (for logging use only)
function executeAction(bytes memory _callData, uint16 _strategyId) public payable virtual;
/// @notice Returns the type of action being implemented
/// @return uint8 The action type as defined in the ActionType enum
function actionType() public pure virtual returns (uint8);
/// @notice Processes the fee taking, figures out if it's a supply and we need to initialize the fee timestamp
/// @param _pool Address of the pool
/// @param _feePercentage Fee percentage in basis points
/// @param _feeToken Address of the fee token
/// @return feeInTokens The amount of fee taken
/// @dev it's rare but in some cases the _pool does differ from the _feeToken
function _processFee(
address _pool,
uint256 _feePercentage,
address _feeToken
) internal returns (uint256 feeInTokens) {
uint256 lastFeeTimestamp = ADMIN_VAULT.getLastFeeTimestamp(_pool);
// Initialize timestamp if not set, this will be the users first interaction with the pool
if (lastFeeTimestamp == 0) {
ADMIN_VAULT.setFeeTimestamp(_pool);
return 0;
}
uint256 currentTimestamp = block.timestamp;
if (lastFeeTimestamp == currentTimestamp) {
return 0; // Don't take fees twice in the same block
}
IERC20 vault = IERC20(_feeToken);
uint256 balance = vault.balanceOf(address(this));
uint256 fee = _calculateFee(balance, _feePercentage, lastFeeTimestamp, currentTimestamp);
if (fee > 0) {
vault.safeTransfer(ADMIN_VAULT.feeConfig().recipient, fee);
}
ADMIN_VAULT.setFeeTimestamp(_pool);
return fee;
}
/// @notice Calculates the fee due from the vault
/// @param _totalDeposit Total amount deposited in the vault
/// @param _feePercentage Fee percentage in basis points
/// @param _lastFeeTimestamp Timestamp of the last fee collection
/// @param _currentTimestamp Current timestamp
/// @return uint256 The calculated fee amount
function _calculateFee(
uint256 _totalDeposit,
uint256 _feePercentage,
uint256 _lastFeeTimestamp,
uint256 _currentTimestamp
) internal pure returns (uint256) {
uint256 secondsPassed = _currentTimestamp - _lastFeeTimestamp;
uint256 annualFee = (_totalDeposit * _feePercentage) / FEE_BASIS_POINTS;
uint256 feeForPeriod = (annualFee * secondsPassed) / FEE_PERIOD;
return feeForPeriod;
}
/// @notice Generates a pool ID from an address
/// @param _addr Address to generate the pool ID from
/// @return bytes4 The generated pool ID
function _poolIdFromAddress(address _addr) internal pure returns (bytes4) {
return bytes4(keccak256(abi.encodePacked(_addr)));
}
/// @notice Encodes balance update information
/// @param _strategyId ID of the strategy
/// @param _poolId ID of the pool
/// @param _balanceBefore Balance before the action
/// @param _balanceAfter Balance after the action
/// @param _feeInTokens Amount of fee taken in tokens
/// @return bytes Encoded balance update information
function _encodeBalanceUpdate(
uint16 _strategyId,
bytes4 _poolId,
uint256 _balanceBefore,
uint256 _balanceAfter,
uint256 _feeInTokens
) internal pure returns (bytes memory) {
return abi.encode(_strategyId, _poolId, _balanceBefore, _balanceAfter, _feeInTokens);
}
function _checkFeesTaken(address _token) internal view {
uint256 feeTimestamp = ADMIN_VAULT.getLastFeeTimestamp(_token);
require(feeTimestamp == 0 || feeTimestamp >= block.timestamp, Errors.Action_FeesNotPaid(protocolName(), actionType(), _token));
}
/// @notice Returns the name of the protocol
/// @return string The name of the protocol
function protocolName() public pure virtual returns (string memory);
/// @notice Reads a chain-specific configuration address for this action from AdminVault
/// @return configAddress The configured on-chain address for this action on the current chain
/// @notice Reads this action's chain-specific configuration address from AdminVault
function _configAddress() internal view returns (address configAddress) {
configAddress = ADMIN_VAULT.getActionConfig(protocolName(), actionType());
require(configAddress != address(0), Errors.InvalidInput(protocolName(), "config"));
}
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.28; /// @title Errors /// @notice This contract contains all custom errors used across the protocol /// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers contract Errors { // Generic errors error InvalidInput(string _contract, string _function); // AccessControlDelayed errors error AccessControlDelayed_InvalidDelay(); error AccessControlDelayed_MustHaveAdminRole(address account, bytes32 role); error AccessControlDelayed_CannotGrantOwnerRole(); error AccessControlDelayed_MustHaveRoleManagerOrOwner(address account); // AdminVault errors error AdminVault_InvalidInput(); error AdminVault_FeePercentageOutOfRange(uint256 _providedPercentage, uint256 _minAllowed, uint256 _maxAllowed); error AdminVault_InvalidFeeRange(uint256 _minFee, uint256 _maxFee); error AdminVault_DelayNotPassed(uint256 _currentTime, uint256 _requiredTime); error AdminVault_PoolNotFound(bytes4 _poolId); error AdminVault_ActionNotFound(bytes4 _actionId); error AdminVault_ConfigNotFound(bytes4 _configId); error AdminVault_NotProposed(); error AdminVault_AlreadyProposed(); error AdminVault_AlreadyAdded(); error AdminVault_NotPool(address _pool); error AdminVault_AlreadyGranted(); error AdminVault_NotGranted(); error AdminVault_TransactionNotProposed(); error AdminVault_TransactionAlreadyApproved(); error AdminVault_MissingRole(bytes32 role, address account); // FeeTakeSafeModule errors error FeeTakeSafeModule_SenderNotFeeTaker(address _sender); error FeeTakeSafeModule_InvalidActionType(bytes4 _actionId); error FeeTakeSafeModule_ExecutionFailed(); error FeeTakeSafeModule_LengthMismatch(); // Generic Action errors error Action_ZeroAmount(string _protocolName, uint8 _actionType); error Action_InsufficientSharesReceived( string _protocolName, uint8 _actionType, uint256 _sharesReceived, uint256 _minSharesReceived ); error Action_MaxSharesBurnedExceeded( string _protocolName, uint8 _actionType, uint256 _sharesBurned, uint256 _maxAllowed ); error Action_UnderlyingReceivedLessThanExpected(uint256 _underlyingReceived, uint256 _expected); error Action_FeesNotPaid(string _protocolName, uint8 _actionType, address _token); // CompoundV2Supply errors error Action_CompoundError(string _protocolName, uint8 _actionType, uint256 _errorCode); // Curve3PoolSwap errors error Curve3Pool__InvalidTokenIndices(int128 _fromToken, int128 _toToken); // ParaswapSwap errors error Paraswap__SwapFailed(); error Paraswap__InsufficientOutput(uint256 _amountReceived, uint256 _minToAmount); error Paraswap__TokenNotApproved(address token); error Paraswap__TokenMismatch(address expected, address actual); error Paraswap__InvalidCalldata(); error Paraswap__UnsupportedSelector(bytes4 selector); // 0x errors error ZeroEx__SwapFailed(); error ZeroEx__InsufficientOutput(uint256 _amountReceived, uint256 _minToAmount); error ZeroEx__InvalidSwapTarget(address provided, address expected); error ZeroEx__TokenNotApproved(address token); // SendToken errors error Action_InvalidRecipient(string _protocolName, uint8 _actionType); // UpgradeAction errors // EIP712TypedDataSafeModule errors error EIP712TypedDataSafeModule_InvalidSignature(); error EIP712TypedDataSafeModule_BundleExpired(); error EIP712TypedDataSafeModule_ChainSequenceNotFound(uint256 chainId, uint256 expectedNonce); error EIP712TypedDataSafeModule_ActionMismatch(uint256 actionIndex, string expectedProtocol, uint8 expectedType, string actualProtocol, uint8 actualType); error EIP712TypedDataSafeModule_ExecutionFailed(); error EIP712TypedDataSafeModule_SignerNotOwner(address signer); error EIP712TypedDataSafeModule_LengthMismatch(); error EIP712TypedDataSafeModule_SafeDeploymentFailed(); error EIP712TypedDataSafeModule_SafeAddressMismatch(address provided, address predicted); error EIP712TypedDataSafeModule_ActionNotFound(bytes4 actionId); // Gas refund errors error EIP712TypedDataSafeModule_InvalidRefundRecipient(uint8 refundTo); error EIP712TypedDataSafeModule_RefundActionRequired(); error EIP712TypedDataSafeModule_RefundActionNotAllowed(); // SafeDeployment errors error SafeDeployment_SafeAlreadyDeployed(); error SafeDeployment_SafeDeploymentFailed(); error SafeDeployment_SafeInitializationFailed(); // TokenRegistry errors error TokenRegistry_TokenNotApproved(); // CCTPBundleReceiver errors error CCTPReceiver_BadMessage(); error CCTPReceiver_BadVersion(uint32 provided); error CCTPReceiver_RelayFailed(); error CCTPReceiver_ShortHook(); error CCTPReceiver_OutOfBounds(); // CCTPBridgeSend errors error CCTPBridgeSend_InsufficientBalance(uint256 balance, uint256 amount); error CCTPBridgeSend_DepositFailed(); error CCTPBridgeSend_BalanceMismatch(uint256 beforeBalance, uint256 afterBalance, uint256 expectedDelta); error CCTPBridgeSend_BundleContextRequired(); }
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
interface IAdminVault {
// Errors
error SenderNotAdmin();
error SenderNotOwner();
error FeeTimestampNotInitialized();
error FeeTimestampAlreadyInitialized();
error FeePercentageOutOfRange();
error InvalidRange();
error InvalidRecipient();
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
// Structs
struct FeeConfig {
address recipient;
uint256 minBasis;
uint256 maxBasis;
uint256 proposalTime;
}
// View Functions
// solhint-disable-next-line func-name-mixedcase
function LOGGER() external view returns (address);
// solhint-disable-next-line func-name-mixedcase
function OWNER_ROLE() external view returns (bytes32);
// solhint-disable-next-line func-name-mixedcase
function ADMIN_ROLE() external view returns (bytes32);
function feeConfig() external view returns (FeeConfig memory);
function pendingFeeConfig() external view returns (FeeConfig memory);
function lastFeeTimestamp(address, address) external view returns (uint256);
function protocolPools(uint256 protocolId, bytes4 poolId) external view returns (address);
function actionAddresses(bytes4 actionId) external view returns (address);
function getPoolAddress(string calldata _protocolName, bytes4 _poolId) external view returns (address);
function getActionAddress(bytes4 _actionId) external view returns (address);
function getActionConfig(string calldata _protocolName, uint8 _actionType) external view returns (address);
function getLastFeeTimestamp(address _vault) external view returns (uint256);
function checkFeeBasis(uint256 _feeBasis) external view;
function getPoolProposalTime(string calldata protocolName, address poolAddress) external view returns (uint256);
function getActionProposalTime(bytes4 actionId, address actionAddress) external view returns (uint256);
function setActionConfig(string calldata _protocolName, uint8 _actionType, address _configAddress) external;
// Role Management Functions
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
// Fee Management Functions
function proposeFeeConfig(address recipient, uint256 min, uint256 max) external;
function cancelFeeConfigProposal() external;
function setFeeConfig() external;
function setFeeTimestamp(address _vault) external;
// Pool Management Functions
function proposePool(string calldata protocolName, address poolAddress) external;
function cancelPoolProposal(string calldata protocolName, address poolAddress) external;
function addPool(string calldata protocolName, address poolAddress) external;
function removePool(string calldata protocolName, address poolAddress) external;
// Action Management Functions
function proposeAction(bytes4 actionId, address actionAddress) external;
function cancelActionProposal(bytes4 actionId, address actionAddress) external;
function addAction(bytes4 actionId, address actionAddress) external;
function removeAction(bytes4 actionId) external;
// Transaction Management Functions
function proposeTransaction(bytes32 txHash) external;
function cancelTransactionProposal(bytes32 txHash) external;
function approveTransaction(bytes32 txHash) external;
function revokeTransaction(bytes32 txHash) external;
function isApprovedTransaction(bytes32 txHash) external view returns (bool);
// Delay Management Functions
function getDelayTimestamp() external returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.28; /// @title IEip712TypedDataSafeModule /// @notice Interface for EIP712TypedDataSafeModule contract to enable Bundle execution /// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers interface IEip712TypedDataSafeModule { /// @notice Action definition structure struct ActionDefinition { string protocolName; uint8 actionType; } /// @notice Sequence structure containing actions and calldata struct Sequence { string name; ActionDefinition[] actions; bytes4[] actionIds; bytes[] callData; } /// @notice Chain sequence structure for multi-chain operations struct ChainSequence { uint256 chainId; uint256 sequenceNonce; bool deploySafe; bool enableGasRefund; uint256 maxRefundAmount; uint8 refundRecipient; // 0=executor, 1=fee recipient Sequence sequence; } /// @notice Bundle structure containing multiple chain sequences struct Bundle { uint256 expiry; ChainSequence[] sequences; } /// @notice Executes a validated bundle for the current chain and nonce /// @param _safeAddr The Safe address to execute on /// @param _bundle The bundle containing sequences for multiple chains /// @param _signature EIP-712 signature from a Safe owner function executeBundle( address _safeAddr, Bundle calldata _bundle, bytes calldata _signature ) external payable; /// @notice Gets the next expected sequence nonce for a Safe /// @param _safeAddr Address of the Safe /// @return The next expected sequence nonce function getSequenceNonce(address _safeAddr) external view returns (uint256); /// @notice Gets the EIP-712 domain separator for a specific Safe address /// @param _safeAddr The Safe address to use as verifying contract /// @return The domain separator function getDomainSeparator(address _safeAddr) external view returns (bytes32); /// @notice Computes the EIP-712 hash for a bundle /// @param _safeAddr The Safe address to use as verifying contract /// @param _bundle The bundle to hash /// @return The EIP-712 hash that should be signed function getBundleHash(address _safeAddr, Bundle calldata _bundle) external view returns (bytes32); /// @notice Events emitted by the module event BundleExecuted(address indexed safe, uint256 indexed expiry, uint256 indexed chainId, uint256 sequenceNonce); event SignatureVerified(address indexed safe, address indexed signer, bytes32 indexed bundleHash); event SafeDeployedForExecution(address indexed signer, address indexed safeAddress); event ConfigInitialized( address adminVault, address sequenceExecutor, address safeDeployment, address tokenRegistry, address feeRecipient, string name, string version ); event GasRefundProcessed(address indexed safe, address indexed refundToken, uint256 refundAmount, address indexed recipient); }
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
/// @title IGasPriceAdaptor
/// @notice Chain-specific adaptor interface for pricing gas usage
/// @dev Provides gas pricing rate that allows caller to measure gas consumption accurately
interface IGasPriceAdaptor {
/// @notice Get the refund rate per gas unit in token terms
/// @dev Rate is scaled by 1e18 for precision: actualRefund = (gasUsed * ratePerGas) / 1e18 + fixedFee
/// @dev Caller measures gas after obtaining rate to ensure accurate measurement
/// @param refundToken Token to calculate rate for (e.g., USDC)
/// @param outerTxCalldata The calldata of the outer transaction (for L1 fee estimation on L2s)
/// @return ratePerGas Token units per gas (scaled by 1e18)
/// @return fixedFee Fixed cost component in token units (e.g., L1 data fee on OP Stack)
function getRefundRate(
address refundToken,
bytes calldata outerTxCalldata
) external view returns (uint256 ratePerGas, uint256 fixedFee);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
import {ActionBase} from "../actions/ActionBase.sol";
interface ILogger {
event ActionEvent(address caller, ActionBase.LogType logId, bytes data);
event AdminVaultEvent(uint256 logId, bytes data);
function logActionEvent(ActionBase.LogType _logType, bytes memory _data) external;
function logAdminVaultEvent(uint256 _logId, bytes memory _data) external;
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.28; /// @title ISafeDeployment /// @notice Interface for deploying Safe accounts with current configuration from registry /// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers /// @author BravaLabs.xyz interface ISafeDeployment { /// @notice Emitted when a Safe is successfully deployed and configured event SafeDeployed( address indexed userAddress, address indexed safeAddress ); /// @notice Deploys a Safe with the current configuration from the registry /// @param _userAddress The address that will own the Safe /// @return safeAddress The address of the deployed Safe function deploySafe(address _userAddress) external returns (address safeAddress); /// @notice Predicts the address of a Safe before deployment /// @param _userAddress The address that will own the Safe /// @return safeAddress The predicted Safe address function predictSafeAddress(address _userAddress) external view returns (address safeAddress); /// @notice Checks if a Safe is already deployed at the predicted address /// @param _userAddress The address that will own the Safe /// @return bool True if Safe is already deployed, false otherwise function isSafeDeployed(address _userAddress) external view returns (bool); /// @notice Gets the Safe singleton address used for deployments /// @return address The Safe singleton address function getSafeSingleton() external view returns (address); /// @notice Gets the setup registry address /// @return address The setup registry address function getSetupRegistry() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
import {IEip712TypedDataSafeModule} from "./IEip712TypedDataSafeModule.sol";
interface ISequenceExecutor {
struct Sequence {
string name;
bytes[] callData;
bytes4[] actionIds;
}
function executeSequence(
Sequence calldata _currSequence,
IEip712TypedDataSafeModule.Bundle calldata _bundle,
bytes calldata _signature,
uint16 _strategyId
) external payable;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
/// @title ITokenRegistry Interface
/// @notice Interface for the TokenRegistry contract that manages token approvals
interface ITokenRegistry {
/// @notice Proposes a new token for approval
/// @param _token The address of the token contract to propose
function proposeToken(address _token) external;
/// @notice Cancels a token proposal
/// @param _token The address of the token contract to cancel
function cancelTokenProposal(address _token) external;
/// @notice Approves a proposed token
/// @param _token The address of the token contract to approve
function approveToken(address _token) external;
/// @notice Revokes approval for a token
/// @param _token The address of the token contract to revoke
function revokeToken(address _token) external;
/// @notice Checks if a token is approved
/// @param _token The address of the token contract to check
/// @return bool True if the token is approved, false otherwise
function isApprovedToken(address _token) external view returns (bool);
/// @notice Canonical gas refund token used by GasRefundAction
function gasRefundToken() external view returns (address);
/// @notice Set the canonical gas refund token (OWNER_ROLE only)
function setGasRefundToken(address _token) external;
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title IFallbackManager - A contract interface managing fallback calls made to this contract.
* @author @safe-global/safe-protocol
*/
interface IFallbackManager {
event ChangedFallbackHandler(address indexed handler);
/**
* @notice Set Fallback Handler to `handler` for the Safe.
* @dev Only fallback calls without value and with data will be forwarded.
* This can only be done via a Safe transaction.
* Cannot be set to the Safe itself.
* @param handler contract to handle fallback calls.
*/
function setFallbackHandler(address handler) external;
}// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity ^0.8.0;
/**
* @title IGuardManager - A contract interface managing transaction guards which perform pre and post-checks on Safe transactions.
* @author @safe-global/safe-protocol
*/
interface IGuardManager {
event ChangedGuard(address indexed guard);
/**
* @dev Set a guard that checks transactions before execution
* This can only be done via a Safe transaction.
* ⚠️ IMPORTANT: Since a guard has full power to block Safe transaction execution,
* a broken guard can cause a denial of service for the Safe. Make sure to carefully
* audit the guard code and design recovery mechanisms.
* @notice Set Transaction Guard `guard` for the Safe. Make sure you trust the guard.
* @param guard The address of the guard to be used or the 0 address to disable the guard
*/
function setGuard(address guard) external;
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;
import {Enum} from "../../libraries/Enum.sol";
/**
* @title IModuleManager - An interface of contract managing Safe modules
* @notice Modules are extensions with unlimited access to a Safe that can be added to a Safe by its owners.
⚠️ WARNING: Modules are a security risk since they can execute arbitrary transactions,
so only trusted and audited modules should be added to a Safe. A malicious module can
completely takeover a Safe.
* @author @safe-global/safe-protocol
*/
interface IModuleManager {
event EnabledModule(address indexed module);
event DisabledModule(address indexed module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionFromModuleFailure(address indexed module);
event ChangedModuleGuard(address indexed moduleGuard);
/**
* @notice Enables the module `module` for the Safe.
* @dev This can only be done via a Safe transaction.
* @param module Module to be whitelisted.
*/
function enableModule(address module) external;
/**
* @notice Disables the module `module` for the Safe.
* @dev This can only be done via a Safe transaction.
* @param prevModule Previous module in the modules linked list.
* @param module Module to be removed.
*/
function disableModule(address prevModule, address module) external;
/**
* @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token)
* @dev Function is virtual to allow overriding for L2 singleton to emit an event for indexing.
* @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 Boolean flag indicating if the call succeeded.
*/
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success);
/**
* @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data
* @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 Boolean flag indicating if the call succeeded.
* @return returnData Data returned by the call.
*/
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success, bytes memory returnData);
/**
* @notice Returns if an module is enabled
* @return True if the module is enabled
*/
function isModuleEnabled(address module) external view returns (bool);
/**
* @notice Returns an 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 returns (address[] memory array, address next);
/**
* @dev Set a module guard that checks transactions initiated by the module before execution
* This can only be done via a Safe transaction.
* ⚠️ IMPORTANT: Since a module guard has full power to block Safe transaction execution initiatied via a module,
* a broken module guard can cause a denial of service for the Safe modules. Make sure to carefully
* audit the module guard code and design recovery mechanisms.
* @notice Set Module Guard `moduleGuard` for the Safe. Make sure you trust the module guard.
* @param moduleGuard The address of the module guard to be used or the zero address to disable the module guard.
*/
function setModuleGuard(address moduleGuard) external;
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title IOwnerManager - Interface for contract which manages Safe owners and a threshold to authorize transactions.
* @author @safe-global/safe-protocol
*/
interface IOwnerManager {
event AddedOwner(address indexed owner);
event RemovedOwner(address indexed owner);
event ChangedThreshold(uint256 threshold);
/**
* @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param owner New owner address.
* @param _threshold New threshold.
*/
function addOwnerWithThreshold(address owner, uint256 _threshold) external;
/**
* @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param prevOwner Owner that pointed to the owner to be removed in the linked list
* @param owner Owner address to be removed.
* @param _threshold New threshold.
*/
function removeOwner(address prevOwner, address owner, uint256 _threshold) external;
/**
* @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
* @dev This can only be done via a Safe transaction.
* @param prevOwner Owner that pointed to the owner to be replaced in the linked list
* @param oldOwner Owner address to be replaced.
* @param newOwner New owner address.
*/
function swapOwner(address prevOwner, address oldOwner, address newOwner) external;
/**
* @notice Changes the threshold of the Safe to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param _threshold New threshold.
*/
function changeThreshold(uint256 _threshold) external;
/**
* @notice Returns the number of required confirmations for a Safe transaction aka the threshold.
* @return Threshold number.
*/
function getThreshold() external view returns (uint256);
/**
* @notice Returns if `owner` is an owner of the Safe.
* @return Boolean if owner is an owner of the Safe.
*/
function isOwner(address owner) external view returns (bool);
/**
* @notice Returns a list of Safe owners.
* @return Array of Safe owners.
*/
function getOwners() external view returns (address[] memory);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;
import {Enum} from "../../libraries/Enum.sol";
import {IModuleManager} from "./IModuleManager.sol";
import {IOwnerManager} from "./IOwnerManager.sol";
import {IFallbackManager} from "./IFallbackManager.sol";
import {IGuardManager} from "./IGuardManager.sol";
/**
* @title ISafe - A multisignature wallet interface with support for confirmations using signed messages based on EIP-712.
* @author @safe-global/safe-protocol
*/
interface ISafe is IModuleManager, IGuardManager, IOwnerManager, IFallbackManager {
event SafeSetup(
address indexed initiator,
address[] owners,
uint256 threshold,
address initializer,
address fallbackHandler
);
event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
event SignMsg(bytes32 indexed msgHash);
event ExecutionFailure(bytes32 indexed txHash, uint256 payment);
event ExecutionSuccess(bytes32 indexed txHash, uint256 payment);
/**
* @notice Sets an initial storage of the Safe contract.
* @dev This method can only be called once.
* If a proxy was created without setting up, anyone can call setup and claim the proxy.
* @param _owners List of Safe owners.
* @param _threshold Number of required confirmations for a Safe transaction.
* @param to Contract address for optional delegate call.
* @param data Data payload for optional delegate call.
* @param fallbackHandler Handler for fallback calls to this contract
* @param paymentToken Token that should be used for the payment (0 is ETH)
* @param payment Value that should be paid
* @param paymentReceiver Address that should receive the payment (or 0 if tx.origin)
*/
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) external;
/** @notice Executes a `operation` {0: Call, 1: DelegateCall}} transaction to `to` with `value` (Native Currency)
* and pays `gasPrice` * `gasLimit` in `gasToken` token to `refundReceiver`.
* @dev The fees are always transferred, even if the user transaction fails.
* This method doesn't perform any sanity check of the transaction, such as:
* - if the contract at `to` address has code or not
* - if the `gasToken` is a contract or not
* It is the responsibility of the caller to perform such checks.
* @param to Destination address of Safe transaction.
* @param value Ether value of Safe transaction.
* @param data Data payload of Safe transaction.
* @param operation Operation type of Safe transaction.
* @param safeTxGas Gas that should be used for the Safe transaction.
* @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
* @param gasPrice Gas price that should be used for the payment calculation.
* @param gasToken Token address (or 0 if ETH) that is used for the payment.
* @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
* @return success Boolean indicating transaction's success.
*/
function execTransaction(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures
) external payable returns (bool success);
/**
* @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
*/
function checkSignatures(bytes32 dataHash, bytes memory signatures) external view;
/**
* @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
* @dev Since the EIP-1271 does an external call, be mindful of reentrancy attacks.
* @param executor Address that executing the transaction.
* ⚠️⚠️⚠️ Make sure that the executor address is a legitmate executor.
* Incorrectly passed the executor might reduce the threshold by 1 signature. ⚠️⚠️⚠️
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
* @param requiredSignatures Amount of required valid signatures.
*/
function checkNSignatures(
address executor,
bytes32 dataHash,
bytes memory signatures,
uint256 requiredSignatures
) external view;
/**
* @notice Marks hash `hashToApprove` as approved.
* @dev This can be used with a pre-approved hash transaction signature.
* IMPORTANT: The approved hash stays approved forever. There's no revocation mechanism, so it behaves similarly to ECDSA signatures
* @param hashToApprove The hash to mark as approved for signatures that are verified by this contract.
*/
function approveHash(bytes32 hashToApprove) external;
/**
* @dev Returns the domain separator for this contract, as defined in the EIP-712 standard.
* @return bytes32 The domain separator hash.
*/
function domainSeparator() external view returns (bytes32);
/**
* @notice Returns transaction hash to be signed by owners.
* @param to Destination address.
* @param value Ether value.
* @param data Data payload.
* @param operation Operation type.
* @param safeTxGas Gas that should be used for the safe transaction.
* @param baseGas Gas costs for data used to trigger the safe transaction.
* @param gasPrice Maximum gas price that should be used for this transaction.
* @param gasToken Token address (or 0 if ETH) that is used for the payment.
* @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
* @param _nonce Transaction nonce.
* @return Transaction hash.
*/
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) external view returns (bytes32);
/**
* External getter function for state variables.
*/
/**
* @notice Returns the version of the Safe contract.
* @return Version string.
*/
// solhint-disable-next-line
function VERSION() external view returns (string memory);
/**
* @notice Returns the nonce of the Safe contract.
* @return Nonce.
*/
function nonce() external view returns (uint256);
/**
* @notice Returns a uint if the messageHash is signed by the owner.
* @param messageHash Hash of message that should be checked.
* @return Number denoting if an owner signed the hash.
*/
function signedMessages(bytes32 messageHash) external view returns (uint256);
/**
* @notice Returns a uint if the messageHash is approved by the owner.
* @param owner Owner address that should be checked.
* @param messageHash Hash of message that should be checked.
* @return Number denoting if an owner approved the hash.
*/
function approvedHashes(address owner, bytes32 messageHash) external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;
import {IEip712TypedDataSafeModule} from "../interfaces/IEip712TypedDataSafeModule.sol";
/// @title EIP712TypedDataLib
/// @notice External library for EIP-712 type strings, type hashes, and hashing helpers to keep module bytecode small
library EIP712TypedDataLib {
// EIP-712 type strings
string private constant ACTION_DEFINITION_TYPE = "ActionDefinition(string protocolName,uint8 actionType)";
string private constant SEQUENCE_TYPE = "Sequence(string name,ActionDefinition[] actions,bytes4[] actionIds,bytes[] callData)ActionDefinition(string protocolName,uint8 actionType)";
string private constant CHAIN_SEQUENCE_TYPE = "ChainSequence(uint256 chainId,uint256 sequenceNonce,bool deploySafe,bool enableGasRefund,uint256 maxRefundAmount,uint8 refundRecipient,Sequence sequence)ActionDefinition(string protocolName,uint8 actionType)Sequence(string name,ActionDefinition[] actions,bytes4[] actionIds,bytes[] callData)";
string private constant BUNDLE_TYPE = "Bundle(uint256 expiry,ChainSequence[] sequences)ActionDefinition(string protocolName,uint8 actionType)ChainSequence(uint256 chainId,uint256 sequenceNonce,bool deploySafe,bool enableGasRefund,uint256 maxRefundAmount,uint8 refundRecipient,Sequence sequence)Sequence(string name,ActionDefinition[] actions,bytes4[] actionIds,bytes[] callData)";
string private constant DOMAIN_TYPE = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)";
// Precomputed type hashes
bytes32 private constant ACTION_DEFINITION_TYPEHASH = keccak256(abi.encodePacked(ACTION_DEFINITION_TYPE));
bytes32 private constant SEQUENCE_TYPEHASH = keccak256(abi.encodePacked(SEQUENCE_TYPE));
bytes32 private constant CHAIN_SEQUENCE_TYPEHASH = keccak256(abi.encodePacked(CHAIN_SEQUENCE_TYPE));
bytes32 private constant BUNDLE_TYPEHASH = keccak256(abi.encodePacked(BUNDLE_TYPE));
bytes32 private constant DOMAIN_TYPEHASH = keccak256(abi.encodePacked(DOMAIN_TYPE));
function hashActionDefinition(IEip712TypedDataSafeModule.ActionDefinition memory action) public pure returns (bytes32) {
return keccak256(abi.encode(
ACTION_DEFINITION_TYPEHASH,
keccak256(bytes(action.protocolName)),
action.actionType
));
}
function hashSequence(IEip712TypedDataSafeModule.Sequence memory sequence) public pure returns (bytes32) {
bytes32[] memory actionHashes = new bytes32[](sequence.actions.length);
for (uint256 i = 0; i < sequence.actions.length; i++) {
actionHashes[i] = hashActionDefinition(sequence.actions[i]);
}
bytes32[] memory callDataHashes = new bytes32[](sequence.callData.length);
for (uint256 i = 0; i < sequence.callData.length; i++) {
callDataHashes[i] = keccak256(sequence.callData[i]);
}
bytes32[] memory actionIdWords = new bytes32[](sequence.actionIds.length);
for (uint256 i = 0; i < sequence.actionIds.length; i++) {
actionIdWords[i] = bytes32(sequence.actionIds[i]);
}
return keccak256(abi.encode(
SEQUENCE_TYPEHASH,
keccak256(bytes(sequence.name)),
keccak256(abi.encodePacked(actionHashes)),
keccak256(abi.encodePacked(actionIdWords)),
keccak256(abi.encodePacked(callDataHashes))
));
}
function hashChainSequence(IEip712TypedDataSafeModule.ChainSequence memory chainSequence) public pure returns (bytes32) {
return keccak256(abi.encode(
CHAIN_SEQUENCE_TYPEHASH,
chainSequence.chainId,
chainSequence.sequenceNonce,
chainSequence.deploySafe,
chainSequence.enableGasRefund,
chainSequence.maxRefundAmount,
chainSequence.refundRecipient,
hashSequence(chainSequence.sequence)
));
}
function hashBundle(IEip712TypedDataSafeModule.Bundle memory bundle) public pure returns (bytes32) {
bytes32[] memory chainSequenceHashes = new bytes32[](bundle.sequences.length);
for (uint256 i = 0; i < bundle.sequences.length; i++) {
chainSequenceHashes[i] = hashChainSequence(bundle.sequences[i]);
}
return keccak256(abi.encode(
BUNDLE_TYPEHASH,
bundle.expiry,
keccak256(abi.encodePacked(chainSequenceHashes))
));
}
function domainSeparator(string memory name, string memory version, address verifyingContract) public pure returns (bytes32) {
return keccak256(abi.encode(
DOMAIN_TYPEHASH,
keccak256(bytes(name)),
keccak256(bytes(version)),
1, // hardcoded chainID 1
verifyingContract,
keccak256("BravaSafe")
));
}
function hashBundleForSigning(
string memory name,
string memory version,
address verifyingContract,
IEip712TypedDataSafeModule.Bundle calldata bundle
) public pure returns (bytes32) {
bytes32 ds = domainSeparator(name, version, verifyingContract);
return keccak256(abi.encodePacked("\x19\x01", ds, hashBundle(bundle)));
}
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;
/**
* @title Enum - Collection of enums used in Safe Smart Account contracts.
* @author @safe-global/safe-protocol
*/
library Enum {
enum Operation {
Call,
DelegateCall
}
}{
"optimizer": {
"enabled": true,
"runs": 1000000
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/auth/EIP712TypedDataSafeModule.sol": {
"EIP712TypedDataLib": "0x8c77694629c2b2916b10d952a58657d3fe4c6d89"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_configSetter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"uint256","name":"actionIndex","type":"uint256"},{"internalType":"string","name":"expectedProtocol","type":"string"},{"internalType":"uint8","name":"expectedType","type":"uint8"},{"internalType":"string","name":"actualProtocol","type":"string"},{"internalType":"uint8","name":"actualType","type":"uint8"}],"name":"EIP712TypedDataSafeModule_ActionMismatch","type":"error"},{"inputs":[{"internalType":"bytes4","name":"actionId","type":"bytes4"}],"name":"EIP712TypedDataSafeModule_ActionNotFound","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_BundleExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"expectedNonce","type":"uint256"}],"name":"EIP712TypedDataSafeModule_ChainSequenceNotFound","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_ExecutionFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"refundTo","type":"uint8"}],"name":"EIP712TypedDataSafeModule_InvalidRefundRecipient","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_InvalidSignature","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_LengthMismatch","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_RefundActionNotAllowed","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_RefundActionRequired","type":"error"},{"inputs":[{"internalType":"address","name":"provided","type":"address"},{"internalType":"address","name":"predicted","type":"address"}],"name":"EIP712TypedDataSafeModule_SafeAddressMismatch","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_SafeDeploymentFailed","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"EIP712TypedDataSafeModule_SignerNotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"name":"SimulationComplete","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sequenceNonce","type":"uint256"}],"name":"BundleExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"adminVault","type":"address"},{"indexed":false,"internalType":"address","name":"sequenceExecutor","type":"address"},{"indexed":false,"internalType":"address","name":"safeDeployment","type":"address"},{"indexed":false,"internalType":"address","name":"tokenRegistry","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ConfigInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":true,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"GasRefundProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":true,"internalType":"address","name":"safeAddress","type":"address"}],"name":"SafeDeployedForExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bundleHash","type":"bytes32"}],"name":"SignatureVerified","type":"event"},{"inputs":[],"name":"ADMIN_VAULT","outputs":[{"internalType":"contract IAdminVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONFIG_SETTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTE_SEQUENCE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFE_DEPLOYMENT","outputs":[{"internalType":"contract ISafeDeployment","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEQUENCE_EXECUTOR_ADDR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRY","outputs":[{"internalType":"contract ITokenRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"},{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"}],"name":"estimateBundleGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"},{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"executeBundle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gasPriceAdaptor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasRefundOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"},{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"}],"name":"getBundleHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"}],"name":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"}],"name":"getRawBundleHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"}],"name":"getSequenceNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_adminVault","type":"address"},{"internalType":"address","name":"_sequenceExecutor","type":"address"},{"internalType":"address","name":"_safeDeployment","type":"address"},{"internalType":"address","name":"_tokenRegistry","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"address","name":"_usdcToken","type":"address"},{"internalType":"address","name":"_gasPriceAdaptor","type":"address"},{"internalType":"uint256","name":"_gasRefundOverhead","type":"uint256"},{"internalType":"string","name":"_domainName","type":"string"},{"internalType":"string","name":"_domainVersion","type":"string"}],"name":"initializeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"sequenceNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdcToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a060405234801561001057600080fd5b50604051613f21380380613f2183398101604081905261002f9161008a565b6001600160a01b0381166100795760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b604482015260640160405180910390fd5b6001600160a01b03166080526100ba565b60006020828403121561009c57600080fd5b81516001600160a01b03811681146100b357600080fd5b9392505050565b608051613e456100dc6000396000818161030501526105bd0152613e456000f3fe60806040526004361061016a5760003560e01c80638a5b1d7a116100cb578063a607945b1161007f578063c7d8390611610059578063c7d839061461049d578063ebd09054146104ca578063f3dde61c146104f757600080fd5b8063a607945b14610417578063a8eb416c1461045a578063bd05a6b11461048757600080fd5b806395d7a060116100b057806395d7a060146103b75780639950d05c146103ca5780639eef8255146103ea57600080fd5b80638a5b1d7a1461036a5780638a8aec311461039757600080fd5b8063392e53cd116101225780633da67cd6116101075780633da67cd6146102f357806374beaed614610327578063895d73861461035557600080fd5b8063392e53cd146102645780633b0891811461028e57600080fd5b80631d43e1c0116101535780631d43e1c0146101f357806324568b5e1461021557806328480f321461023757600080fd5b806311eac8551461016f578063132620fd146101c6575b600080fd5b34801561017b57600080fd5b5060055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101d257600080fd5b5060005461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101ff57600080fd5b50610208610517565b6040516101bd91906126d3565b34801561022157600080fd5b506102356102303660046128ac565b6105a5565b005b34801561024357600080fd5b5060015461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561027057600080fd5b5060085461027e9060ff1681565b60405190151581526020016101bd565b34801561029a57600080fd5b506102c27f3d423fd40000000000000000000000000000000000000000000000000000000081565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016101bd565b3480156102ff57600080fd5b5061019c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561033357600080fd5b506103476103423660046129ad565b610928565b6040519081526020016101bd565b34801561036157600080fd5b506102086109cd565b34801561037657600080fd5b5060035461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103a357600080fd5b506102356103b23660046129ad565b6109da565b6102356103c53660046129fd565b610f28565b3480156103d657600080fd5b506103476103e5366004612aab565b611782565b3480156103f657600080fd5b50600b5461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561042357600080fd5b50610347610432366004612aab565b73ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090205490565b34801561046657600080fd5b50610347610475366004612aab565b60096020526000908152604090205481565b34801561049357600080fd5b50610347600a5481565b3480156104a957600080fd5b5060025461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104d657600080fd5b5060045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561050357600080fd5b50610347610512366004612ac8565b61181c565b6007805461052490612b05565b80601f016020809104026020016040519081016040528092919081815260200182805461055090612b05565b801561059d5780601f106105725761010080835404028352916020019161059d565b820191906000526020600020905b81548152906001019060200180831161058057829003601f168201915b505050505081565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e617574686f72697a6564000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60085460ff16156106b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8a16158015906106f0575073ffffffffffffffffffffffffffffffffffffffff891615155b8015610711575073ffffffffffffffffffffffffffffffffffffffff881615155b8015610732575073ffffffffffffffffffffffffffffffffffffffff871615155b8015610753575073ffffffffffffffffffffffffffffffffffffffff861615155b8015610774575073ffffffffffffffffffffffffffffffffffffffff851615155b8015610795575073ffffffffffffffffffffffffffffffffffffffff841615155b6107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420696e707574000000000000000000000000000000000000006044820152606401610640565b600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8d8116919091179092556001805482168c84161790556002805482168b84161790556003805482168a8416179055600480548216898416179055600580548216888416179055600b8054909116918616919091179055600a839055600661089f8382612ba0565b5060076108ac8282612ba0565b50600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f523f84e41556c5af02ae8009aa221886547803e16e52abbcf3194bc52642b94290610914908c908c908c908c908c9089908990612cb9565b60405180910390a150505050505050505050565b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb3906109839060069060079088908890600401613353565b602060405180830381865af41580156109a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c491906133b3565b90505b92915050565b6006805461052490612b05565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610a5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260096020908152604082205433929091610aab90610a9b908701876133cc565b610aa49161371c565b468461186f565b9050806040015115610dab576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa158015610b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4c9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610bd3576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808916600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015610c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c679190613830565b610da9576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015610d17575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610d1491810190613813565b60015b610d4d576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b600080610dc08360c001518460a0015161193e565b9150915082606001518015610dd3575080155b15610e0a576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260600151158015610e195750805b15610e50576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516060808201835260c0860180515183525101516020808301919091528183018590528251600080825291810190935291610e91918b918b90611d3d565b905080610eca576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a610ed7908961387c565b9050846060015115610ef357600a54610ef0908261388f565b90505b6040517fa9ea822800000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610fad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b42843511610fe7576040517fb51df0ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb390611042906006906007908b908b90600401613353565b602060405180830381865af415801561105f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108391906133b3565b905060006110c985858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611e829050565b905073ffffffffffffffffffffffffffffffffffffffff8116611118576040517f165dfe4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fcd182b7b23d2cf25e3288287cb62a2c6f0ba73d649eea19849d24c1e7d896a5f60405160405180910390a473ffffffffffffffffffffffffffffffffffffffff8716600090815260096020908152604082205491906111ad90610a9b908a018a6133cc565b90508060400151156114ad576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16146112d5576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c16600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015611345573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113699190613830565b6114ab576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015611419575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261141691810190613813565b60015b61144f576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b6040517f2f54bf6e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301528a1690632f54bf6e90602401602060405180830381865afa158015611519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153d9190613830565b61158b576040517f2132375600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000806115a08360c001518460a0015161193e565b91509150826060015180156115b3575080155b156115ea576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82606001511580156115f95750805b15611630576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61163b84600161388f565b73ffffffffffffffffffffffffffffffffffffffff8c1660009081526009602090815260408083209390935582516060808201855260c088018051518352510151818301528084018690528351601f8d018390048302810183019094528b845291926116c7928f9290918f918f908f9081908401838280828437600092019190915250611d3d92505050565b905080611700576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83606001511561171e5761171e8c85608001518660a001518b611eac565b468b600001358d73ffffffffffffffffffffffffffffffffffffffff167f2833eb2894ed7a554675d7668327a96a61008f575828de8a2694d7648d46ff448860405161176c91815260200190565b60405180910390a4505050505050505050505050565b6040517f7efa81c1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990637efa81c1906117db9060069060079087906004016138a2565b602060405180830381865af41580156117f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c791906133b3565b6040517f4a4dc2e1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990634a4dc2e1906117db9085906004016138ee565b6118776125f9565b60005b84518110156118fa578385828151811061189657611896613901565b6020026020010151600001511480156118cb5750828582815181106118bd576118bd613901565b602002602001015160200151145b156118f2578481815181106118e2576118e2613901565b6020026020010151915050611937565b60010161187a565b506040517feb0c4da10000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610640565b9392505050565b60606000836060015151846020015151141580611965575083604001515184602001515114155b1561199c576040517f4d200e6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060408201516020830151516000905b8015611d355760006119c060018361387c565b90506000866040015182815181106119da576119da613901565b6020908102919091010151600080546040517f1977ddee0000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000084166004820152929350909173ffffffffffffffffffffffffffffffffffffffff90911690631977ddee90602401602060405180830381865afa158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f9190613813565b905073ffffffffffffffffffffffffffffffffffffffff8116611b12576040517ff1a321d40000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000083166004820152602401610640565b600081905060008173ffffffffffffffffffffffffffffffffffffffff1663e567e8696040518163ffffffff1660e01b8152600401600060405180830381865afa158015611b64573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611baa9190810190613930565b905060008273ffffffffffffffffffffffffffffffffffffffff1663247492f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1d919061399e565b905060008b602001518781518110611c3757611c37613901565b602002602001015190508060000151805190602001208380519060200120141580611c6c5750806020015160ff168260ff1614155b15611cb257805160208201516040517f6871f291000000000000000000000000000000000000000000000000000000008152610640928a929091879087906004016139bb565b88158015611cc3575060ff82166004145b15611d1b5760ff8b161580611cdb57508a60ff166001145b611d16576040517fc95d9f7900000000000000000000000000000000000000000000000000000000815260ff8c166004820152602401610640565b600198505b505050505050508080611d2d90613a34565b9150506119ad565b509250929050565b60015460405160009173ffffffffffffffffffffffffffffffffffffffff8088169263468721a7929091169084907f3d423fd40000000000000000000000000000000000000000000000000000000090611da1908a908a908a908690602401613bbc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b9092168252611e36939291600190600401613cec565b6020604051808303816000875af1158015611e55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e799190613830565b95945050505050565b600080600080611e9286866121a6565b925092509250611ea282826121f3565b5090949350505050565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169060009082906370a0823190602401602060405180830381865afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4391906133b3565b905080600003611f545750506121a0565b600080600080611f626122fb565b9092509050811561200d5760005a8811611f7d576000611f95565b600a545a611f8b908a61387c565b611f95919061388f565b9050801561200b5781670de0b6b3a7640000611fb18584613d69565b611fbb9190613d80565b611fc5919061388f565b945060008a118015611fd657508985115b15611fdf578994505b60ff8916156120065760045473ffffffffffffffffffffffffffffffffffffffff16612008565b325b93505b505b60008085118015612033575073ffffffffffffffffffffffffffffffffffffffff841615155b1561207057600086861115612048578661204a565b855b905061206d73ffffffffffffffffffffffffffffffffffffffff891686836123c9565b90505b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8916906370a0823190602401602060405180830381865afa1580156120dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210191906133b3565b9050801561212a5761212a73ffffffffffffffffffffffffffffffffffffffff89168d836123c9565b73ffffffffffffffffffffffffffffffffffffffff851661214b578b61214d565b845b60055460405184815273ffffffffffffffffffffffffffffffffffffffff92831692918216918f16907f4491aef93914fa4c0b351f507d27ab20ff9bf264d92d730c356332786acfc1c09060200161176c565b50505050565b600080600083516041036121e05760208401516040850151606086015160001a6121d28882858561245b565b9550955095505050506121ec565b50508151600091506002905b9250925092565b600082600381111561220757612207613a05565b03612210575050565b600182600381111561222457612224613a05565b0361225b576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561226f5761226f613a05565b036122a9576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60038260038111156122bd576122bd613a05565b036122f7576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b5050565b600b546005546040517f1339293a000000000000000000000000000000000000000000000000000000008152600092839273ffffffffffffffffffffffffffffffffffffffff91821692631339293a9261235d92169085903690600401613dbb565b6040805180830381865afa9250505080156123b3575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526123b091810190613deb565b60015b6123c05750600091829150565b90939092509050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612456908490612555565b505050565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612496575060009150600390508261254b565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156124ea573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166125415750600092506001915082905061254b565b9250600091508190505b9450945094915050565b600080602060008451602086016000885af180612578576040513d6000823e3d81fd5b50506000513d915081156125905780600114156125aa565b73ffffffffffffffffffffffffffffffffffffffff84163b155b156121a0576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b6040518060e00160405280600081526020016000815260200160001515815260200160001515815260200160008152602001600060ff1681526020016126606040518060800160405280606081526020016060815260200160608152602001606081525090565b905290565b60005b83811015612680578181015183820152602001612668565b50506000910152565b600081518084526126a1816020860160208601612665565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109c46020830184612689565b73ffffffffffffffffffffffffffffffffffffffff8116811461270857600080fd5b50565b8035612716816126e6565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405290565b6040516080810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405160e0810167ffffffffffffffff8111828210171561276d5761276d61271b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156128005761280061271b565b604052919050565b600067ffffffffffffffff8211156128225761282261271b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600061286161285c84612808565b6127b9565b905082815283838301111561287557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261289d57600080fd5b6109c48383356020850161284e565b6000806000806000806000806000806101408b8d0312156128cc57600080fd5b6128d58b61270b565b99506128e360208c0161270b565b98506128f160408c0161270b565b97506128ff60608c0161270b565b965061290d60808c0161270b565b955061291b60a08c0161270b565b945061292960c08c0161270b565b935060e08b013592506101008b013567ffffffffffffffff81111561294d57600080fd5b6129598d828e0161288c565b9250506101208b013567ffffffffffffffff81111561297757600080fd5b6129838d828e0161288c565b9150509295989b9194979a5092959850565b6000604082840312156129a757600080fd5b50919050565b600080604083850312156129c057600080fd5b82356129cb816126e6565b9150602083013567ffffffffffffffff8111156129e757600080fd5b6129f385828601612995565b9150509250929050565b60008060008060608587031215612a1357600080fd5b8435612a1e816126e6565b9350602085013567ffffffffffffffff811115612a3a57600080fd5b612a4687828801612995565b935050604085013567ffffffffffffffff811115612a6357600080fd5b8501601f81018713612a7457600080fd5b803567ffffffffffffffff811115612a8b57600080fd5b876020828401011115612a9d57600080fd5b949793965060200194505050565b600060208284031215612abd57600080fd5b8135611937816126e6565b600060208284031215612ada57600080fd5b813567ffffffffffffffff811115612af157600080fd5b612afd84828501612995565b949350505050565b600181811c90821680612b1957607f821691505b6020821081036129a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561245657806000526020600020601f840160051c81016020851015612b795750805b601f840160051c820191505b81811015612b995760008155600101612b85565b5050505050565b815167ffffffffffffffff811115612bba57612bba61271b565b612bce81612bc88454612b05565b84612b52565b6020601f821160018114612c205760008315612bea5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612b99565b6000848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612c6e5787850151825560209485019460019092019101612c4e565b5084821015612caa57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b73ffffffffffffffffffffffffffffffffffffffff8816815273ffffffffffffffffffffffffffffffffffffffff8716602082015273ffffffffffffffffffffffffffffffffffffffff8616604082015273ffffffffffffffffffffffffffffffffffffffff8516606082015273ffffffffffffffffffffffffffffffffffffffff8416608082015260e060a08201526000612d5860e0830185612689565b82810360c0840152612d6a8185612689565b9a9950505050505050505050565b60008154612d8581612b05565b808552600182168015612d9f5760018114612dd957612e10565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083166020870152602082151560051b8701019350612e10565b84600052602060002060005b83811015612e075781546020828a010152600182019150602081019050612de5565b87016020019450505b50505092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4e57600080fd5b830160208101925035905067ffffffffffffffff811115612e6e57600080fd5b8060051b3603821315612e8057600080fd5b9250929050565b801515811461270857600080fd5b803561271681612e87565b60ff8116811461270857600080fd5b803561271681612ea0565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112612eee57600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f2c57600080fd5b830160208101925035905067ffffffffffffffff811115612f4c57600080fd5b803603821315612e8057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612eee57600080fd5b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461271657600080fd5b81835260208301925060008160005b8481101561305f577fffffffff0000000000000000000000000000000000000000000000000000000061304983612fd8565b1686526020958601959190910190600101613017565b5093949350505050565b60008383855260208501945060208460051b8201018360005b868110156130de577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484030188526130bb8287612ef7565b6130c6858284612f5b565b60209a8b019a90955093909301925050600101613082565b50909695505050505050565b60006130f68283612ef7565b60808552613108608086018284612f5b565b9150506131186020840184612e19565b85830360208701528281845260208401905060208260051b8501018360005b848110156131bd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030184526131708287612fa4565b61317a8182612ef7565b6040865261318c604087018284612f5b565b9150506020820135915061319f82612ea0565b60ff9190911660209485015293830193929190910190600101613137565b50506131cc6040880188612e19565b9550935087810360408901526131e3818686613008565b9450505050506131f66060840184612e19565b8583036060870152613209838284613069565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21833603018112612eee57600080fd5b8035825260006040830161325e6020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08987030183526132b78286613213565b803587526020808201359088015260408101356132d381612e87565b1515604088015260608101356132e881612e87565b151560608801526080818101359088015261330560a08201612eaf565b60ff1660a088015261331a60c0820182612eba565b905060e060c088015261333060e08801826130ea565b965050602092830192919091019060010161327e565b5093979650505050505050565b6080815260006133666080830187612d78565b82810360208401526133788187612d78565b905073ffffffffffffffffffffffffffffffffffffffff8516604084015282810360608401526133a88185613247565b979650505050505050565b6000602082840312156133c557600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261340157600080fd5b83018035915067ffffffffffffffff82111561341c57600080fd5b6020019150600581901b3603821315612e8057600080fd5b600067ffffffffffffffff82111561344e5761344e61271b565b5060051b60200190565b600082601f83011261346957600080fd5b813561347761285c82613434565b8082825260208201915060208360051b86010192508583111561349957600080fd5b602085015b8381101561354a57803567ffffffffffffffff8111156134bd57600080fd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156134f157600080fd5b6134f961274a565b602082013567ffffffffffffffff81111561351357600080fd5b6135228a60208386010161288c565b8252506040820135915061353582612ea0565b6020818101929092528452928301920161349e565b5095945050505050565b600082601f83011261356557600080fd5b813561357361285c82613434565b8082825260208201915060208360051b86010192508583111561359557600080fd5b602085015b8381101561354a576135ab81612fd8565b83526020928301920161359a565b600082601f8301126135ca57600080fd5b81356135d861285c82613434565b8082825260208201915060208360051b8601019250858311156135fa57600080fd5b602085015b8381101561354a57803567ffffffffffffffff81111561361e57600080fd5b8601603f8101881361362f57600080fd5b6136418860208301356040840161284e565b845250602092830192016135ff565b60006080828403121561366257600080fd5b61366a612773565b9050813567ffffffffffffffff81111561368357600080fd5b61368f8482850161288c565b825250602082013567ffffffffffffffff8111156136ac57600080fd5b6136b884828501613458565b602083015250604082013567ffffffffffffffff8111156136d857600080fd5b6136e484828501613554565b604083015250606082013567ffffffffffffffff81111561370457600080fd5b613710848285016135b9565b60608301525092915050565b600061372a61285c84613434565b8381526020810190600585901b84013681111561374657600080fd5b845b8181101561380857803567ffffffffffffffff81111561376757600080fd5b860160e036829003121561377a57600080fd5b613782612796565b813581526020808301359082015261379c60408301612e95565b60408201526137ad60608301612e95565b6060820152608082810135908201526137c860a08301612eaf565b60a082015260c082013567ffffffffffffffff8111156137e757600080fd5b6137f336828501613650565b60c08301525085525060209384019301613748565b509095945050505050565b60006020828403121561382557600080fd5b8151611937816126e6565b60006020828403121561384257600080fd5b815161193781612e87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109c7576109c761384d565b808201808211156109c7576109c761384d565b6060815260006138b56060830186612d78565b82810360208401526138c78186612d78565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b6020815260006109c46020830184613247565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561394257600080fd5b815167ffffffffffffffff81111561395957600080fd5b8201601f8101841361396a57600080fd5b805161397861285c82612808565b81815285602083850101111561398d57600080fd5b611e79826020830160208601612665565b6000602082840312156139b057600080fd5b815161193781612ea0565b85815260a0602082015260006139d460a0830187612689565b60ff8616604084015282810360608401526139ef8186612689565b91505060ff831660808301529695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600081613a4357613a4361384d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600081518084526020840193506020830160005b8281101561305f5781517fffffffff0000000000000000000000000000000000000000000000000000000016865260209586019590910190600101613a7d565b80358252600060408301613ad46020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0898703018352613b2d8286613213565b80358752602080820135908801526040810135613b4981612e87565b151560408801526060810135613b5e81612e87565b1515606088015260808181013590880152613b7b60a08201612eaf565b60ff1660a0880152613b9060c0820182612eba565b905060e060c0880152613ba660e08801826130ea565b9650506020928301929190910190600101613af4565b608081526000855160606080840152613bd860e0840182612689565b6020888101518583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160a0870152805180845292935081019181840191600582901b85010160005b82811015613c71577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868303018452613c5c828651612689565b60209586019594909401939150600101613c22565b5060408b015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808782030160c0880152613cad8186613a69565b9450505050508281036020840152613cc58187613abd565b90508281036040840152613cd98186612689565b915050611e79606083018461ffff169052565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201526000613d216080830185612689565b905060028310613d5a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82606083015295945050505050565b80820281158282048414176109c7576109c761384d565b600082613db6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611e79604083018486612f5b565b60008060408385031215613dfe57600080fd5b50508051602090910151909290915056fea2646970667358221220cfb2980bf92440be29875dabaf6765125162ac6e89a62ddcd9715c2f7d6511ae64736f6c634300081c0033000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c
Deployed Bytecode
0x60806040526004361061016a5760003560e01c80638a5b1d7a116100cb578063a607945b1161007f578063c7d8390611610059578063c7d839061461049d578063ebd09054146104ca578063f3dde61c146104f757600080fd5b8063a607945b14610417578063a8eb416c1461045a578063bd05a6b11461048757600080fd5b806395d7a060116100b057806395d7a060146103b75780639950d05c146103ca5780639eef8255146103ea57600080fd5b80638a5b1d7a1461036a5780638a8aec311461039757600080fd5b8063392e53cd116101225780633da67cd6116101075780633da67cd6146102f357806374beaed614610327578063895d73861461035557600080fd5b8063392e53cd146102645780633b0891811461028e57600080fd5b80631d43e1c0116101535780631d43e1c0146101f357806324568b5e1461021557806328480f321461023757600080fd5b806311eac8551461016f578063132620fd146101c6575b600080fd5b34801561017b57600080fd5b5060055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101d257600080fd5b5060005461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101ff57600080fd5b50610208610517565b6040516101bd91906126d3565b34801561022157600080fd5b506102356102303660046128ac565b6105a5565b005b34801561024357600080fd5b5060015461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561027057600080fd5b5060085461027e9060ff1681565b60405190151581526020016101bd565b34801561029a57600080fd5b506102c27f3d423fd40000000000000000000000000000000000000000000000000000000081565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016101bd565b3480156102ff57600080fd5b5061019c7f000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c81565b34801561033357600080fd5b506103476103423660046129ad565b610928565b6040519081526020016101bd565b34801561036157600080fd5b506102086109cd565b34801561037657600080fd5b5060035461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103a357600080fd5b506102356103b23660046129ad565b6109da565b6102356103c53660046129fd565b610f28565b3480156103d657600080fd5b506103476103e5366004612aab565b611782565b3480156103f657600080fd5b50600b5461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561042357600080fd5b50610347610432366004612aab565b73ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090205490565b34801561046657600080fd5b50610347610475366004612aab565b60096020526000908152604090205481565b34801561049357600080fd5b50610347600a5481565b3480156104a957600080fd5b5060025461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104d657600080fd5b5060045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561050357600080fd5b50610347610512366004612ac8565b61181c565b6007805461052490612b05565b80601f016020809104026020016040519081016040528092919081815260200182805461055090612b05565b801561059d5780601f106105725761010080835404028352916020019161059d565b820191906000526020600020905b81548152906001019060200180831161058057829003601f168201915b505050505081565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c1614610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e617574686f72697a6564000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60085460ff16156106b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8a16158015906106f0575073ffffffffffffffffffffffffffffffffffffffff891615155b8015610711575073ffffffffffffffffffffffffffffffffffffffff881615155b8015610732575073ffffffffffffffffffffffffffffffffffffffff871615155b8015610753575073ffffffffffffffffffffffffffffffffffffffff861615155b8015610774575073ffffffffffffffffffffffffffffffffffffffff851615155b8015610795575073ffffffffffffffffffffffffffffffffffffffff841615155b6107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420696e707574000000000000000000000000000000000000006044820152606401610640565b600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8d8116919091179092556001805482168c84161790556002805482168b84161790556003805482168a8416179055600480548216898416179055600580548216888416179055600b8054909116918616919091179055600a839055600661089f8382612ba0565b5060076108ac8282612ba0565b50600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f523f84e41556c5af02ae8009aa221886547803e16e52abbcf3194bc52642b94290610914908c908c908c908c908c9089908990612cb9565b60405180910390a150505050505050505050565b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb3906109839060069060079088908890600401613353565b602060405180830381865af41580156109a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c491906133b3565b90505b92915050565b6006805461052490612b05565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610a5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260096020908152604082205433929091610aab90610a9b908701876133cc565b610aa49161371c565b468461186f565b9050806040015115610dab576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa158015610b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4c9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610bd3576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808916600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015610c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c679190613830565b610da9576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015610d17575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610d1491810190613813565b60015b610d4d576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b600080610dc08360c001518460a0015161193e565b9150915082606001518015610dd3575080155b15610e0a576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260600151158015610e195750805b15610e50576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516060808201835260c0860180515183525101516020808301919091528183018590528251600080825291810190935291610e91918b918b90611d3d565b905080610eca576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a610ed7908961387c565b9050846060015115610ef357600a54610ef0908261388f565b90505b6040517fa9ea822800000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610fad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b42843511610fe7576040517fb51df0ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb390611042906006906007908b908b90600401613353565b602060405180830381865af415801561105f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108391906133b3565b905060006110c985858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611e829050565b905073ffffffffffffffffffffffffffffffffffffffff8116611118576040517f165dfe4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fcd182b7b23d2cf25e3288287cb62a2c6f0ba73d649eea19849d24c1e7d896a5f60405160405180910390a473ffffffffffffffffffffffffffffffffffffffff8716600090815260096020908152604082205491906111ad90610a9b908a018a6133cc565b90508060400151156114ad576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16146112d5576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c16600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015611345573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113699190613830565b6114ab576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015611419575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261141691810190613813565b60015b61144f576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b6040517f2f54bf6e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301528a1690632f54bf6e90602401602060405180830381865afa158015611519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153d9190613830565b61158b576040517f2132375600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000806115a08360c001518460a0015161193e565b91509150826060015180156115b3575080155b156115ea576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82606001511580156115f95750805b15611630576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61163b84600161388f565b73ffffffffffffffffffffffffffffffffffffffff8c1660009081526009602090815260408083209390935582516060808201855260c088018051518352510151818301528084018690528351601f8d018390048302810183019094528b845291926116c7928f9290918f918f908f9081908401838280828437600092019190915250611d3d92505050565b905080611700576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83606001511561171e5761171e8c85608001518660a001518b611eac565b468b600001358d73ffffffffffffffffffffffffffffffffffffffff167f2833eb2894ed7a554675d7668327a96a61008f575828de8a2694d7648d46ff448860405161176c91815260200190565b60405180910390a4505050505050505050505050565b6040517f7efa81c1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990637efa81c1906117db9060069060079087906004016138a2565b602060405180830381865af41580156117f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c791906133b3565b6040517f4a4dc2e1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990634a4dc2e1906117db9085906004016138ee565b6118776125f9565b60005b84518110156118fa578385828151811061189657611896613901565b6020026020010151600001511480156118cb5750828582815181106118bd576118bd613901565b602002602001015160200151145b156118f2578481815181106118e2576118e2613901565b6020026020010151915050611937565b60010161187a565b506040517feb0c4da10000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610640565b9392505050565b60606000836060015151846020015151141580611965575083604001515184602001515114155b1561199c576040517f4d200e6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060408201516020830151516000905b8015611d355760006119c060018361387c565b90506000866040015182815181106119da576119da613901565b6020908102919091010151600080546040517f1977ddee0000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000084166004820152929350909173ffffffffffffffffffffffffffffffffffffffff90911690631977ddee90602401602060405180830381865afa158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f9190613813565b905073ffffffffffffffffffffffffffffffffffffffff8116611b12576040517ff1a321d40000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000083166004820152602401610640565b600081905060008173ffffffffffffffffffffffffffffffffffffffff1663e567e8696040518163ffffffff1660e01b8152600401600060405180830381865afa158015611b64573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611baa9190810190613930565b905060008273ffffffffffffffffffffffffffffffffffffffff1663247492f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1d919061399e565b905060008b602001518781518110611c3757611c37613901565b602002602001015190508060000151805190602001208380519060200120141580611c6c5750806020015160ff168260ff1614155b15611cb257805160208201516040517f6871f291000000000000000000000000000000000000000000000000000000008152610640928a929091879087906004016139bb565b88158015611cc3575060ff82166004145b15611d1b5760ff8b161580611cdb57508a60ff166001145b611d16576040517fc95d9f7900000000000000000000000000000000000000000000000000000000815260ff8c166004820152602401610640565b600198505b505050505050508080611d2d90613a34565b9150506119ad565b509250929050565b60015460405160009173ffffffffffffffffffffffffffffffffffffffff8088169263468721a7929091169084907f3d423fd40000000000000000000000000000000000000000000000000000000090611da1908a908a908a908690602401613bbc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b9092168252611e36939291600190600401613cec565b6020604051808303816000875af1158015611e55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e799190613830565b95945050505050565b600080600080611e9286866121a6565b925092509250611ea282826121f3565b5090949350505050565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169060009082906370a0823190602401602060405180830381865afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4391906133b3565b905080600003611f545750506121a0565b600080600080611f626122fb565b9092509050811561200d5760005a8811611f7d576000611f95565b600a545a611f8b908a61387c565b611f95919061388f565b9050801561200b5781670de0b6b3a7640000611fb18584613d69565b611fbb9190613d80565b611fc5919061388f565b945060008a118015611fd657508985115b15611fdf578994505b60ff8916156120065760045473ffffffffffffffffffffffffffffffffffffffff16612008565b325b93505b505b60008085118015612033575073ffffffffffffffffffffffffffffffffffffffff841615155b1561207057600086861115612048578661204a565b855b905061206d73ffffffffffffffffffffffffffffffffffffffff891686836123c9565b90505b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8916906370a0823190602401602060405180830381865afa1580156120dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210191906133b3565b9050801561212a5761212a73ffffffffffffffffffffffffffffffffffffffff89168d836123c9565b73ffffffffffffffffffffffffffffffffffffffff851661214b578b61214d565b845b60055460405184815273ffffffffffffffffffffffffffffffffffffffff92831692918216918f16907f4491aef93914fa4c0b351f507d27ab20ff9bf264d92d730c356332786acfc1c09060200161176c565b50505050565b600080600083516041036121e05760208401516040850151606086015160001a6121d28882858561245b565b9550955095505050506121ec565b50508151600091506002905b9250925092565b600082600381111561220757612207613a05565b03612210575050565b600182600381111561222457612224613a05565b0361225b576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561226f5761226f613a05565b036122a9576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60038260038111156122bd576122bd613a05565b036122f7576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b5050565b600b546005546040517f1339293a000000000000000000000000000000000000000000000000000000008152600092839273ffffffffffffffffffffffffffffffffffffffff91821692631339293a9261235d92169085903690600401613dbb565b6040805180830381865afa9250505080156123b3575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526123b091810190613deb565b60015b6123c05750600091829150565b90939092509050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612456908490612555565b505050565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612496575060009150600390508261254b565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156124ea573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166125415750600092506001915082905061254b565b9250600091508190505b9450945094915050565b600080602060008451602086016000885af180612578576040513d6000823e3d81fd5b50506000513d915081156125905780600114156125aa565b73ffffffffffffffffffffffffffffffffffffffff84163b155b156121a0576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b6040518060e00160405280600081526020016000815260200160001515815260200160001515815260200160008152602001600060ff1681526020016126606040518060800160405280606081526020016060815260200160608152602001606081525090565b905290565b60005b83811015612680578181015183820152602001612668565b50506000910152565b600081518084526126a1816020860160208601612665565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109c46020830184612689565b73ffffffffffffffffffffffffffffffffffffffff8116811461270857600080fd5b50565b8035612716816126e6565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405290565b6040516080810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405160e0810167ffffffffffffffff8111828210171561276d5761276d61271b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156128005761280061271b565b604052919050565b600067ffffffffffffffff8211156128225761282261271b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600061286161285c84612808565b6127b9565b905082815283838301111561287557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261289d57600080fd5b6109c48383356020850161284e565b6000806000806000806000806000806101408b8d0312156128cc57600080fd5b6128d58b61270b565b99506128e360208c0161270b565b98506128f160408c0161270b565b97506128ff60608c0161270b565b965061290d60808c0161270b565b955061291b60a08c0161270b565b945061292960c08c0161270b565b935060e08b013592506101008b013567ffffffffffffffff81111561294d57600080fd5b6129598d828e0161288c565b9250506101208b013567ffffffffffffffff81111561297757600080fd5b6129838d828e0161288c565b9150509295989b9194979a5092959850565b6000604082840312156129a757600080fd5b50919050565b600080604083850312156129c057600080fd5b82356129cb816126e6565b9150602083013567ffffffffffffffff8111156129e757600080fd5b6129f385828601612995565b9150509250929050565b60008060008060608587031215612a1357600080fd5b8435612a1e816126e6565b9350602085013567ffffffffffffffff811115612a3a57600080fd5b612a4687828801612995565b935050604085013567ffffffffffffffff811115612a6357600080fd5b8501601f81018713612a7457600080fd5b803567ffffffffffffffff811115612a8b57600080fd5b876020828401011115612a9d57600080fd5b949793965060200194505050565b600060208284031215612abd57600080fd5b8135611937816126e6565b600060208284031215612ada57600080fd5b813567ffffffffffffffff811115612af157600080fd5b612afd84828501612995565b949350505050565b600181811c90821680612b1957607f821691505b6020821081036129a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561245657806000526020600020601f840160051c81016020851015612b795750805b601f840160051c820191505b81811015612b995760008155600101612b85565b5050505050565b815167ffffffffffffffff811115612bba57612bba61271b565b612bce81612bc88454612b05565b84612b52565b6020601f821160018114612c205760008315612bea5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612b99565b6000848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612c6e5787850151825560209485019460019092019101612c4e565b5084821015612caa57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b73ffffffffffffffffffffffffffffffffffffffff8816815273ffffffffffffffffffffffffffffffffffffffff8716602082015273ffffffffffffffffffffffffffffffffffffffff8616604082015273ffffffffffffffffffffffffffffffffffffffff8516606082015273ffffffffffffffffffffffffffffffffffffffff8416608082015260e060a08201526000612d5860e0830185612689565b82810360c0840152612d6a8185612689565b9a9950505050505050505050565b60008154612d8581612b05565b808552600182168015612d9f5760018114612dd957612e10565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083166020870152602082151560051b8701019350612e10565b84600052602060002060005b83811015612e075781546020828a010152600182019150602081019050612de5565b87016020019450505b50505092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4e57600080fd5b830160208101925035905067ffffffffffffffff811115612e6e57600080fd5b8060051b3603821315612e8057600080fd5b9250929050565b801515811461270857600080fd5b803561271681612e87565b60ff8116811461270857600080fd5b803561271681612ea0565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112612eee57600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f2c57600080fd5b830160208101925035905067ffffffffffffffff811115612f4c57600080fd5b803603821315612e8057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612eee57600080fd5b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461271657600080fd5b81835260208301925060008160005b8481101561305f577fffffffff0000000000000000000000000000000000000000000000000000000061304983612fd8565b1686526020958601959190910190600101613017565b5093949350505050565b60008383855260208501945060208460051b8201018360005b868110156130de577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484030188526130bb8287612ef7565b6130c6858284612f5b565b60209a8b019a90955093909301925050600101613082565b50909695505050505050565b60006130f68283612ef7565b60808552613108608086018284612f5b565b9150506131186020840184612e19565b85830360208701528281845260208401905060208260051b8501018360005b848110156131bd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030184526131708287612fa4565b61317a8182612ef7565b6040865261318c604087018284612f5b565b9150506020820135915061319f82612ea0565b60ff9190911660209485015293830193929190910190600101613137565b50506131cc6040880188612e19565b9550935087810360408901526131e3818686613008565b9450505050506131f66060840184612e19565b8583036060870152613209838284613069565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21833603018112612eee57600080fd5b8035825260006040830161325e6020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08987030183526132b78286613213565b803587526020808201359088015260408101356132d381612e87565b1515604088015260608101356132e881612e87565b151560608801526080818101359088015261330560a08201612eaf565b60ff1660a088015261331a60c0820182612eba565b905060e060c088015261333060e08801826130ea565b965050602092830192919091019060010161327e565b5093979650505050505050565b6080815260006133666080830187612d78565b82810360208401526133788187612d78565b905073ffffffffffffffffffffffffffffffffffffffff8516604084015282810360608401526133a88185613247565b979650505050505050565b6000602082840312156133c557600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261340157600080fd5b83018035915067ffffffffffffffff82111561341c57600080fd5b6020019150600581901b3603821315612e8057600080fd5b600067ffffffffffffffff82111561344e5761344e61271b565b5060051b60200190565b600082601f83011261346957600080fd5b813561347761285c82613434565b8082825260208201915060208360051b86010192508583111561349957600080fd5b602085015b8381101561354a57803567ffffffffffffffff8111156134bd57600080fd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156134f157600080fd5b6134f961274a565b602082013567ffffffffffffffff81111561351357600080fd5b6135228a60208386010161288c565b8252506040820135915061353582612ea0565b6020818101929092528452928301920161349e565b5095945050505050565b600082601f83011261356557600080fd5b813561357361285c82613434565b8082825260208201915060208360051b86010192508583111561359557600080fd5b602085015b8381101561354a576135ab81612fd8565b83526020928301920161359a565b600082601f8301126135ca57600080fd5b81356135d861285c82613434565b8082825260208201915060208360051b8601019250858311156135fa57600080fd5b602085015b8381101561354a57803567ffffffffffffffff81111561361e57600080fd5b8601603f8101881361362f57600080fd5b6136418860208301356040840161284e565b845250602092830192016135ff565b60006080828403121561366257600080fd5b61366a612773565b9050813567ffffffffffffffff81111561368357600080fd5b61368f8482850161288c565b825250602082013567ffffffffffffffff8111156136ac57600080fd5b6136b884828501613458565b602083015250604082013567ffffffffffffffff8111156136d857600080fd5b6136e484828501613554565b604083015250606082013567ffffffffffffffff81111561370457600080fd5b613710848285016135b9565b60608301525092915050565b600061372a61285c84613434565b8381526020810190600585901b84013681111561374657600080fd5b845b8181101561380857803567ffffffffffffffff81111561376757600080fd5b860160e036829003121561377a57600080fd5b613782612796565b813581526020808301359082015261379c60408301612e95565b60408201526137ad60608301612e95565b6060820152608082810135908201526137c860a08301612eaf565b60a082015260c082013567ffffffffffffffff8111156137e757600080fd5b6137f336828501613650565b60c08301525085525060209384019301613748565b509095945050505050565b60006020828403121561382557600080fd5b8151611937816126e6565b60006020828403121561384257600080fd5b815161193781612e87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109c7576109c761384d565b808201808211156109c7576109c761384d565b6060815260006138b56060830186612d78565b82810360208401526138c78186612d78565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b6020815260006109c46020830184613247565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561394257600080fd5b815167ffffffffffffffff81111561395957600080fd5b8201601f8101841361396a57600080fd5b805161397861285c82612808565b81815285602083850101111561398d57600080fd5b611e79826020830160208601612665565b6000602082840312156139b057600080fd5b815161193781612ea0565b85815260a0602082015260006139d460a0830187612689565b60ff8616604084015282810360608401526139ef8186612689565b91505060ff831660808301529695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600081613a4357613a4361384d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600081518084526020840193506020830160005b8281101561305f5781517fffffffff0000000000000000000000000000000000000000000000000000000016865260209586019590910190600101613a7d565b80358252600060408301613ad46020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0898703018352613b2d8286613213565b80358752602080820135908801526040810135613b4981612e87565b151560408801526060810135613b5e81612e87565b1515606088015260808181013590880152613b7b60a08201612eaf565b60ff1660a0880152613b9060c0820182612eba565b905060e060c0880152613ba660e08801826130ea565b9650506020928301929190910190600101613af4565b608081526000855160606080840152613bd860e0840182612689565b6020888101518583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160a0870152805180845292935081019181840191600582901b85010160005b82811015613c71577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868303018452613c5c828651612689565b60209586019594909401939150600101613c22565b5060408b015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808782030160c0880152613cad8186613a69565b9450505050508281036020840152613cc58187613abd565b90508281036040840152613cd98186612689565b915050611e79606083018461ffff169052565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201526000613d216080830185612689565b905060028310613d5a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82606083015295945050505050565b80820281158282048414176109c7576109c761384d565b600082613db6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611e79604083018486612f5b565b60008060408385031215613dfe57600080fd5b50508051602090910151909290915056fea2646970667358221220cfb2980bf92440be29875dabaf6765125162ac6e89a62ddcd9715c2f7d6511ae64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c
-----Decoded View---------------
Arg [0] : _configSetter (address): 0x237E5d6CAf1ABc06B9A1a625FF04f8BC1b7F7e2c
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.