Source Code
Latest 25 from a total of 40 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Add Allowed Cont... | 23031464 | 219 days ago | IN | 0 ETH | 0.00012057 | ||||
| Add Allowed Cont... | 22736229 | 260 days ago | IN | 0 ETH | 0.00004227 | ||||
| Execute Calldata | 22279526 | 324 days ago | IN | 0 ETH | 0.00004051 | ||||
| Swap | 22279524 | 324 days ago | IN | 0 ETH | 0.00016267 | ||||
| Swap | 22279520 | 324 days ago | IN | 0 ETH | 0.00002481 | ||||
| Add Allowed Cont... | 22279368 | 324 days ago | IN | 0 ETH | 0.00004109 | ||||
| Forward Fund | 22243286 | 329 days ago | IN | 0 ETH | 0.00004297 | ||||
| Swap | 22243285 | 329 days ago | IN | 0 ETH | 0.00015211 | ||||
| Forward Fund | 22187992 | 337 days ago | IN | 0 ETH | 0.00002502 | ||||
| Forward Fund | 22187992 | 337 days ago | IN | 0 ETH | 0.00004365 | ||||
| Bridge | 22187992 | 337 days ago | IN | 0 ETH | 0.00007856 | ||||
| Bridge | 22180144 | 338 days ago | IN | 0 ETH | 0.00002213 | ||||
| Bridge | 22180129 | 338 days ago | IN | 0 ETH | 0.00002235 | ||||
| Bridge | 22180126 | 338 days ago | IN | 0 ETH | 0.00002373 | ||||
| Bridge | 22180053 | 338 days ago | IN | 0 ETH | 0.00002719 | ||||
| Bridge | 22180052 | 338 days ago | IN | 0 ETH | 0.00012886 | ||||
| Bridge | 22179792 | 338 days ago | IN | 0 ETH | 0.00013392 | ||||
| Bridge | 22122768 | 346 days ago | IN | 0 ETH | 0.00006014 | ||||
| Bridge | 22036555 | 358 days ago | IN | 0 ETH | 0.00001905 | ||||
| Bridge | 22036554 | 358 days ago | IN | 0 ETH | 0.00001913 | ||||
| Bridge | 22036550 | 358 days ago | IN | 0 ETH | 0.00002059 | ||||
| Bridge | 22036519 | 358 days ago | IN | 0 ETH | 0.00001946 | ||||
| Bridge | 22036517 | 358 days ago | IN | 0 ETH | 0.0000218 | ||||
| Bridge | 22036516 | 358 days ago | IN | 0 ETH | 0.00002216 | ||||
| Bridge | 22036499 | 358 days ago | IN | 0 ETH | 0.0000748 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61010034 | 21937401 | 372 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LiquidityRouter
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 5000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol";
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {
BridgeParams,
LiquidityRouterInterface,
RouterState,
SwapParams,
TransferOut
} from "./interfaces/LiquidityRouterInterface.sol";
import {LiquidityRouterEventsAndErrors} from "./interfaces/LiquidityRouterEventsAndErrors.sol";
import {InspectablePaymasterInterface} from "./interfaces/InspectablePaymasterInterface.sol";
import {OrderPaymaster} from "./paymaster/OrderPaymaster.sol";
import {GuardianOwnable} from "./utils/GuardianOwnable.sol";
import {WETH9Interface} from "./interfaces/WETH9Interface.sol";
import {EncodeLib} from "./utils/EncodeLib.sol";
contract LiquidityRouter is GuardianOwnable, LiquidityRouterInterface, LiquidityRouterEventsAndErrors {
using SafeERC20 for IERC20;
using EncodeLib for RouterState;
uint256 public timelockDuration = 1 days;
IEntryPoint public immutable ENTRY_POINT;
WETH9Interface public immutable WRAPPED_NATIVE_TOKEN;
address public immutable NATIVE_TOKEN = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
address public immutable USDT_TOKEN = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
uint256 constant BPS = 10000; // 1% = 100 basis points
uint256 public _REFUND_CUT_BPS_ = 5; // 0.05%
bool public _ALLOW_ALL_;
mapping(address target => bool isAllowed) public override _ALLOWED_SWAP_TARGETS_;
mapping(address target => bool isAllowed) public override _ALLOWED_BRIDGE_TARGETS_;
mapping(address operator => bool isAllowed) public override _ALLOWED_OPERATORS_;
mapping(uint256 chainId => bool isAllowed) public override _ALLOWED_CHAIN_IDS_;
mapping(address asset => uint256 excessAmount) public override _POOL_EXCESS_;
mapping(bytes32 => uint256) public override _TIMELOCK_EXPIRATION_;
mapping(address allowedContracts => bool isAllowed) public override _ALLOWED_CONTRACTS_;
/// @dev Active order accounts.
mapping(address depositAddress => bytes32 orderHash) internal _ORDERS_;
modifier allowedSwapTarget(address target) {
if (!(_ALLOW_ALL_ || _ALLOWED_SWAP_TARGETS_[target])) {
revert SwapTargetNotAllowed(target);
}
_;
}
modifier allowedBridgeTarget(address target) {
if (!(_ALLOW_ALL_ || _ALLOWED_BRIDGE_TARGETS_[target])) {
revert BridgeTargetNotAllowed(target);
}
_;
}
modifier refundIfExpired(address depositAddress, RouterState memory order) {
if (block.timestamp >= order.params.expiration) {
if (order.params.refundAddress == bytes32(0)) {
revert OrderExpired();
}
delete _ORDERS_[depositAddress];
_refundFunds(order);
emit RefundDispatched(depositAddress, order.heldAsset, order.heldAmount);
return;
}
_;
}
modifier Timelock() {
bytes32 hash = getCallHash(msg.sender, msg.data);
uint256 expiration = _TIMELOCK_EXPIRATION_[hash];
if (expiration == 0) {
_TIMELOCK_EXPIRATION_[hash] = block.timestamp + timelockDuration;
} else if (block.timestamp < expiration) {
revert TimelockNotExpired(hash, expiration);
} else {
delete _TIMELOCK_EXPIRATION_[hash];
_;
}
}
modifier onlyOperator() {
if (!_ALLOWED_OPERATORS_[msg.sender]) {
revert OnlyOperatorsAllowed(msg.sender);
}
_;
}
modifier withVerifiedOrder(RouterState memory order, address depositAddress) {
if (_ORDERS_[depositAddress] != order.hash()) {
revert OrderNotVerified(depositAddress, _ORDERS_[depositAddress], order.hash());
}
_;
}
receive() external payable {}
constructor(address guardian, IEntryPoint entryPoint, address wrappedNativeToken) {
_transferOwnership(guardian);
ENTRY_POINT = entryPoint;
WRAPPED_NATIVE_TOKEN = WETH9Interface(wrappedNativeToken);
}
function setAllowAll(bool isAllowed) external onlyOwner {
_ALLOW_ALL_ = isAllowed;
}
function setTimelockDuration(uint256 duration) external onlyOwner {
timelockDuration = duration;
}
function setRefundCut(uint256 cut) external onlyOwner {
require (cut <= BPS, RefundCutTooHigh());
_REFUND_CUT_BPS_ = cut;
}
function addAllowedSwapTargets(address[] calldata targets) external onlyOwner Timelock {
_updateAllowedSwapTargets(targets, true);
}
function addAllowedBridgeTargets(address[] calldata targets) external onlyOwner Timelock {
_updateAllowedBridgeTargets(targets, true);
}
function addAllowedChainIds(uint256[] calldata chainIds) external onlyOwner Timelock {
_updateAllowedChainIds(chainIds, true);
}
function addOperators(address[] calldata operators) external onlyOwner {
_updateAllowedOperators(operators, true);
}
function addAllowedContracts(address[] calldata contracts) external onlyOwner {
_updateAllowedContracts(contracts, true);
}
function removeAllowedSwapTargets(address[] calldata targets) external onlyOwner {
_updateAllowedSwapTargets(targets, false);
}
function removeAllowedBridgeTargets(address[] calldata targets) external onlyOwner {
_updateAllowedBridgeTargets(targets, false);
}
function removeAllowedChainIds(uint256[] calldata chainIds) external onlyOwner {
_updateAllowedChainIds(chainIds, false);
}
function removeOperators(address[] calldata operators) external onlyOwner {
_updateAllowedOperators(operators, false);
}
function removeAllowedContracts(address[] calldata contracts) external onlyOwner {
_updateAllowedContracts(contracts, false);
}
function withdrawFunds(address asset, uint256 amount) external onlyOwner {
if (asset == NATIVE_TOKEN) {
uint256 balance = address(this).balance - _POOL_EXCESS_[asset];
require(balance >= amount, InsufficientTokensToWithdraw(asset, amount, balance));
(bool success,) = payable(owner()).call{value: amount}("");
require(success, NativeTokenTransferFailed());
} else {
uint256 balance = IERC20(asset).balanceOf(address(this)) - _POOL_EXCESS_[asset];
require(balance >= amount, InsufficientTokensToWithdraw(asset, amount, balance));
IERC20(asset).safeTransfer(owner(), amount);
}
}
function setOperator(address operator, bool isAllowed) external onlyOwner {
_ALLOWED_OPERATORS_[operator] = isAllowed;
}
function addExcessToPool(address asset, uint256 amount) external payable {
if (asset == NATIVE_TOKEN) {
require(msg.value == amount, IncorrectAmountOfNativeToken(amount, msg.value));
} else {
IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);
}
_POOL_EXCESS_[asset] += amount;
emit ExcessAdded(asset, amount);
}
function removeExcessFromPool(address asset, uint256 amount) external onlyOwner {
// Will revert if amount is greater than excess balance.
_POOL_EXCESS_[asset] -= amount;
if (asset == NATIVE_TOKEN) {
(bool success,) = payable(msg.sender).call{value: amount}("");
require(success, NativeTokenTransferFailed());
} else {
IERC20(asset).safeTransfer(msg.sender, amount);
}
emit ExcessRemoved(asset, amount);
}
/**
* @notice Deposit funds to create a order account.
*/
function deposit(RouterState calldata order) external {
if (order.params.expiration <= block.timestamp) {
order.heldAsset.safeTransferFrom(msg.sender, address(this), order.heldAmount);
if (order.params.refundAddress == bytes32(0)) {
emit ExpiredOrder(msg.sender);
return;
} else {
_refundFunds(order);
return;
}
}
address depositAddress = msg.sender;
order.heldAsset.safeTransferFrom(depositAddress, address(this), order.heldAmount);
_ORDERS_[depositAddress] = order.hash();
emit Deposited(depositAddress, order.heldAsset, order.heldAmount);
}
function swap(address depositAddress, SwapParams calldata swapParams, RouterState memory order)
external
withVerifiedOrder(order, depositAddress)
refundIfExpired(depositAddress, order)
allowedSwapTarget(swapParams.target)
onlyOperator
{
// Write order state to storage.
(order.heldAsset, order.heldAmount) = _swap(swapParams, order);
_ORDERS_[depositAddress] = order.hash();
emit Swapped(depositAddress, swapParams.target, order.heldAsset, order.heldAmount);
}
function swapAndForward(address depositAddress, SwapParams calldata swapParams, RouterState memory order)
external
withVerifiedOrder(order, depositAddress)
refundIfExpired(depositAddress, order)
allowedSwapTarget(swapParams.target)
onlyOperator
{
(order.heldAsset, order.heldAmount) = _swap(swapParams, order);
_forward(depositAddress, order);
}
function bridge(address depositAddress, BridgeParams calldata bridgeParams, RouterState calldata order)
external
withVerifiedOrder(order, depositAddress)
refundIfExpired(depositAddress, order)
allowedBridgeTarget(bridgeParams.target)
onlyOperator
{
// Read order state from storage.
// Note: Read the whole thing into memory since we use it later.
IERC20 heldAsset = order.heldAsset;
uint256 heldAmount = order.heldAmount;
uint256 targetChainId = order.params.targetChainId;
// Sanity check that we are not already on the target chain.
if (targetChainId == block.chainid) {
revert BridgeAlreadyOnTargetChain();
}
// Require that the chain ID is allowed/supported.
if (!(_ALLOW_ALL_ || _ALLOWED_CHAIN_IDS_[targetChainId])) {
revert BridgeChainIdNotAllowed(targetChainId);
}
// Set the allowance on the bridge spender.
//
// Note: Using approve() instead of safeIncreaseAllowance() or forceApprove() under the
// assumption that all allowances from this contract will be zero in between transactions.
if (block.chainid == 1 && address(heldAsset) == USDT_TOKEN) {
heldAsset.safeApprove(bridgeParams.spender, heldAmount);
} else {
heldAsset.approve(bridgeParams.spender, heldAmount);
}
// Deduct the funds from the excess pool.
_recordUseExcessPoolFunds(NATIVE_TOKEN, bridgeParams.valueFromExcessPool);
// ute the bridge call.
_bridgeToRecipient(bridgeParams.target, bridgeParams.callData, bridgeParams.valueFromExcessPool);
// Require that the full allowance was spent.
//
// IMPORTANT NOTE: We assume the bridge contract supports spending an exact amount.
uint256 remainingAllowance = heldAsset.allowance(address(this), bridgeParams.spender);
if (remainingAllowance != 0) {
revert BridgeDidNotSpendExactAmount(remainingAllowance);
}
// Delete the order from storage.
delete _ORDERS_[depositAddress];
emit Bridged(
depositAddress,
bridgeParams.target,
bridgeParams.bridgeReceivedAsset,
bridgeParams.minBridgeReceivedAmount,
bridgeParams.valueFromExcessPool
);
}
/**
* @dev Execute a contract call with the given calldata to the recipient.
*/
function executeCalldata(address depositAddress, RouterState memory order)
external
withVerifiedOrder(order, depositAddress)
refundIfExpired(depositAddress, order)
onlyOperator
{
if (block.chainid != order.params.targetChainId) {
revert ExecuteCalldataChainNotReady(block.chainid);
}
if (order.params.recipient == bytes32(0)) {
revert ExecuteCalldataRecipientNotSet();
}
if (address(uint160(uint256(order.params.recipient))).code.length == 0) {
revert ExecuteCalldataRecipientNotContract();
}
_executeCalldata(depositAddress, order);
}
function swapAndExecuteCalldata(
address depositAddress,
SwapParams calldata swapParams,
RouterState memory order
) external withVerifiedOrder(order, depositAddress) refundIfExpired(depositAddress, order) onlyOperator {
(order.heldAsset, order.heldAmount) = _swap(swapParams, order);
_executeCalldata(depositAddress, order);
}
// apply to non userOp execution cases
function forwardFund(address depositAddress, RouterState memory order)
external
withVerifiedOrder(order, depositAddress)
refundIfExpired(depositAddress, order)
onlyOperator
{
if (block.chainid != order.params.targetChainId) {
revert ForwardFundChainNotReady(block.chainid);
}
if (order.params.recipient == bytes32(0)) {
revert ForwardFundRecipientNotSet();
}
_forward(depositAddress, order);
}
function getOrderHash(address depositAddress) external view returns (bytes32) {
return _getOrderHash(depositAddress);
}
function _refundFunds(RouterState memory order) internal {
address refundAddr = address(uint160(uint256(order.params.refundAddress)));
uint256 refundAmount = order.heldAmount * (BPS - _REFUND_CUT_BPS_) / BPS; // Deduct 0.05%
_POOL_EXCESS_[address(order.heldAsset)] += order.heldAmount - refundAmount;
if (order.heldAsset == IERC20(NATIVE_TOKEN)) {
(bool success,) = payable(refundAddr).call{value: refundAmount}("");
require(success, RefundTransferFailed(address(order.heldAsset), refundAmount));
} else {
order.heldAsset.safeTransfer(refundAddr, refundAmount);
}
}
function _forward(address depositAddress, RouterState memory order) internal {
IERC20 heldAsset = order.heldAsset;
uint256 heldAmount = order.heldAmount;
uint256 forwardAmount = order.params.targetAmount;
if (forwardAmount < heldAmount) {
_POOL_EXCESS_[address(heldAsset)] += heldAmount - forwardAmount;
} else if (forwardAmount <= heldAmount * (1 + order.params.slippage * 100 / BPS)) {
_recordUseExcessPoolFunds(address(heldAsset), forwardAmount - heldAmount);
} else {
revert ExecuteInvalidAmount(heldAmount, forwardAmount);
}
address targetAssetAddr = address(uint160(uint256(order.params.targetAsset)));
address recipientAddr = address(uint160(uint256(order.params.recipient)));
if (targetAssetAddr == NATIVE_TOKEN) {
if (heldAsset != WRAPPED_NATIVE_TOKEN) {
revert ForwardFundAssetNotReady(heldAsset);
} else {
WRAPPED_NATIVE_TOKEN.withdraw(forwardAmount);
(bool success, bytes memory returnData) = payable(recipientAddr).call{value: forwardAmount}("");
if (!success) {
revert ForwardFundReverted(returnData);
}
}
} else if (heldAsset != IERC20(targetAssetAddr)) {
revert ForwardFundAssetNotReady(heldAsset);
} else if (heldAsset == IERC20(targetAssetAddr)) {
heldAsset.safeTransfer(recipientAddr, forwardAmount);
} else {
revert ForwardFundAssetNotReady(heldAsset);
}
// Delete the order from storage.
delete _ORDERS_[depositAddress];
emit FundForwarded(depositAddress, forwardAmount, order.params.recipient);
}
function _swap(SwapParams calldata swapParams, RouterState memory order) internal returns (IERC20, uint256) {
// Read order state from storage.
IERC20 heldAsset = order.heldAsset;
uint256 heldAmount = order.heldAmount;
// Get starting balance of the asset to receive from the swap.
uint256 balanceBefore;
if (address(swapParams.receivedAsset) == NATIVE_TOKEN) {
balanceBefore = address(this).balance;
} else {
balanceBefore = IERC20(swapParams.receivedAsset).balanceOf(address(this));
}
{
// Deduct the funds from the excess pool.
uint256 valueFromExcessPool = swapParams.valueFromExcessPool;
_recordUseExcessPoolFunds(NATIVE_TOKEN, valueFromExcessPool);
bool success;
bytes memory returnData;
// Execute the swap.
if (swapParams.isETHSwap) {
if (heldAsset != WRAPPED_NATIVE_TOKEN) {
revert HeldAssetNotWETH(address(heldAsset));
}
WETH9Interface(WRAPPED_NATIVE_TOKEN).withdraw(heldAmount);
(success, returnData) =
swapParams.target.call{value: heldAmount + valueFromExcessPool}(swapParams.callData);
} else {
// Set the allowance on the swap spender.
//
// Note: Using approve() instead of safeIncreaseAllowance() or forceApprove() under the
// assumption that all allowances from this contract will be zero in between transactions.
if (block.chainid == 1 && address(heldAsset) == USDT_TOKEN) {
heldAsset.safeApprove(swapParams.spender, heldAmount);
} else {
heldAsset.approve(swapParams.spender, heldAmount);
}
(success, returnData) = swapParams.target.call{value: valueFromExcessPool}(swapParams.callData);
}
if (!success) {
revert SwapReverted(returnData);
}
}
uint256 receivedAmount;
IERC20 receivedAsset;
if (address(swapParams.receivedAsset) == NATIVE_TOKEN) {
// Note: The tx will revert if the received asset balance decreased.
receivedAmount = address(this).balance - balanceBefore;
WRAPPED_NATIVE_TOKEN.deposit{value: receivedAmount}();
receivedAsset = WRAPPED_NATIVE_TOKEN;
} else {
uint256 balanceAfter = IERC20(swapParams.receivedAsset).balanceOf(address(this));
// Note: The tx will revert if the received asset balance decreased.
receivedAmount = balanceAfter - balanceBefore;
receivedAsset = IERC20(swapParams.receivedAsset);
}
if (receivedAmount < swapParams.minReceivedAmount) {
revert SwapDidNotReceiveMinAmount(receivedAmount);
}
// Revokes the remaining allowance.
//
// IMPORTANT NOTE: We don't assume the swap contract supports spending an exact amount.
//
// Note: This check will fail with some ERC-20 implementations in the case
// where heldAmount = type(uint256).max. We assume that this is impossible in practice.
if (!swapParams.isETHSwap) {
uint256 remainingAllowance = heldAsset.allowance(address(this), swapParams.spender);
if (remainingAllowance != 0) {
IERC20(heldAsset).safeApprove(swapParams.spender, 0);
}
}
return (receivedAsset, receivedAmount);
}
function _executeCalldata(address depositAddress, RouterState memory order) internal {
address recipientAddr = address(uint160(uint256(order.params.recipient)));
if (!_ALLOWED_CONTRACTS_[recipientAddr]) {
revert OnlyContractsAllowed(recipientAddr);
}
IERC20 heldAsset = order.heldAsset;
uint256 heldAmount = order.heldAmount;
uint256 forwardAmount = order.params.targetAmount;
order.params.targetAmount = 0;
if (forwardAmount < heldAmount) {
_POOL_EXCESS_[address(heldAsset)] += heldAmount - forwardAmount;
} else if (forwardAmount <= heldAmount * (1 + order.params.slippage * 100 / BPS)) {
_recordUseExcessPoolFunds(address(heldAsset), forwardAmount - heldAmount);
} else {
revert ExecuteInvalidAmount(heldAmount, forwardAmount);
}
uint256[] memory _balancesBefore = new uint256[](order.params.transferOut.length);
for (uint256 i = 0; i < order.params.transferOut.length;) {
if (order.params.transferOut[i].token == NATIVE_TOKEN) {
_balancesBefore[i] = address(this).balance;
} else {
_balancesBefore[i] = IERC20(order.params.transferOut[i].token).balanceOf(address(this));
}
unchecked {
++i;
}
}
address targetAssetAddr = address(uint160(uint256(order.params.targetAsset)));
if (targetAssetAddr == NATIVE_TOKEN) {
if (heldAsset != WRAPPED_NATIVE_TOKEN) {
revert ExecuteAssetNotReady(heldAsset);
} else {
WRAPPED_NATIVE_TOKEN.withdraw(forwardAmount);
{
(bool success, bytes memory returnData) =
payable(recipientAddr).call{value: forwardAmount}(order.params.targetCalldata);
if (!success) {
revert ExecuteReverted(returnData);
}
}
for (uint256 i; i < order.params.transferOut.length;) {
if (order.params.transferOut[i].token == NATIVE_TOKEN) {
uint256 balanceAfter = address(this).balance;
uint256 receivedAmount = balanceAfter - _balancesBefore[i];
if (receivedAmount > 0) {
payable(order.params.transferOut[i].recipient).transfer(receivedAmount);
}
} else {
uint256 balanceAfter = IERC20(order.params.transferOut[i].token).balanceOf(address(this));
uint256 receivedAmount = balanceAfter - _balancesBefore[i];
if (receivedAmount > 0) {
IERC20(order.params.transferOut[i].token).transfer(
order.params.transferOut[i].recipient, receivedAmount
);
}
}
unchecked {
++i;
}
}
}
} else if (heldAsset != IERC20(targetAssetAddr)) {
revert ExecuteAssetNotReady(heldAsset);
} else if (heldAsset == IERC20(targetAssetAddr)) {
if (block.chainid == 1 && address(heldAsset) == USDT_TOKEN) {
heldAsset.safeApprove(recipientAddr, forwardAmount);
} else {
heldAsset.approve(recipientAddr, forwardAmount);
}
// Execute the contract call
{
(bool success, bytes memory returnData) = recipientAddr.call(order.params.targetCalldata);
if (!success) {
revert ExecuteReverted(returnData);
}
}
// Require that the full allowance was spent.
//
// IMPORTANT NOTE: We assume the bridge contract supports spending an exact amount.
uint256 remainingAllowance = heldAsset.allowance(address(this), recipientAddr);
if (remainingAllowance != 0) {
revert ExecuteDidNotSpendExactAmount(remainingAllowance);
}
// Transfer out the received tokens
for (uint256 i; i < order.params.transferOut.length;) {
if (order.params.transferOut[i].token == NATIVE_TOKEN) {
uint256 balanceAfter = address(this).balance;
uint256 receivedAmount = balanceAfter - _balancesBefore[i];
if (heldAsset == WRAPPED_NATIVE_TOKEN && order.params.transferOut[i].token == NATIVE_TOKEN) {
receivedAmount += forwardAmount;
}
if (receivedAmount > 0) {
payable(order.params.transferOut[i].recipient).transfer(receivedAmount);
}
} else {
uint256 balanceAfter = IERC20(order.params.transferOut[i].token).balanceOf(address(this));
uint256 receivedAmount = balanceAfter - _balancesBefore[i];
if (heldAsset == IERC20(order.params.transferOut[i].token)) {
receivedAmount += forwardAmount;
}
if (receivedAmount > 0) {
IERC20(order.params.transferOut[i].token).transfer(
order.params.transferOut[i].recipient, receivedAmount
);
}
}
unchecked {
++i;
}
}
} else {
revert ExecuteCalldataAssetNotReady(heldAsset);
}
// Delete the order from storage.
delete _ORDERS_[depositAddress];
emit CalldataExecuted(depositAddress, forwardAmount, order.params.recipient);
}
function _getOrderHash(address depositAddress) internal view returns (bytes32) {
bytes32 orderHash = _ORDERS_[depositAddress];
if (orderHash == bytes32(0)) {
revert OrderDoesNotExist();
}
return orderHash;
}
function _updateAllowedSwapTargets(address[] calldata targets, bool isAllowed) internal {
uint256 n = targets.length;
for (uint256 i; i < n; ++i) {
address target = targets[i];
_ALLOWED_SWAP_TARGETS_[target] = isAllowed;
emit UpdatedAllowedSwapTarget(target, isAllowed);
}
}
function _updateAllowedBridgeTargets(address[] calldata targets, bool isAllowed) internal {
uint256 n = targets.length;
for (uint256 i; i < n; ++i) {
address target = targets[i];
_ALLOWED_BRIDGE_TARGETS_[target] = isAllowed;
emit UpdatedAllowedBridgeTarget(target, isAllowed);
}
}
function _updateAllowedContracts(address[] calldata contracts, bool isAllowed) internal {
uint256 n = contracts.length;
for (uint256 i; i < n; ++i) {
address contractAdd = contracts[i];
_ALLOWED_CONTRACTS_[contractAdd] = isAllowed;
emit UpdatedAllowedContracts(contractAdd, isAllowed);
}
}
function _updateAllowedChainIds(uint256[] calldata chainids, bool isAllowed) internal {
uint256 n = chainids.length;
for (uint256 i; i < n; ++i) {
uint256 chainId = chainids[i];
_ALLOWED_CHAIN_IDS_[chainId] = isAllowed;
emit UpdatedAllowedChainIds(chainId, isAllowed);
}
}
function _updateAllowedOperators(address[] calldata operators, bool isAllowed) internal {
uint256 n = operators.length;
for (uint256 i; i < n; ++i) {
address operator = operators[i];
_ALLOWED_OPERATORS_[operator] = isAllowed;
emit UpdatedAllowedOperator(operator, isAllowed);
}
}
function _bridgeToRecipient(address target, bytes calldata callData, uint256 value) internal {
// as needed.
(bool success, bytes memory returnData) = target.call{value: value}(callData);
if (!success) {
revert BridgeReverted(returnData);
}
}
function _recordUseExcessPoolFunds(address asset, uint256 value) internal {
if (value > 0) {
uint256 excessPoolBalance = _POOL_EXCESS_[asset];
require(excessPoolBalance >= value, InsufficientTokensInExcessPoolForCall(asset, value, excessPoolBalance));
_POOL_EXCESS_[asset] -= value;
emit ExcessPoolFundsUsedForCall(asset, value);
}
}
function getCallHash(address sender, bytes calldata callData) internal pure returns (bytes32) {
return keccak256(abi.encode(sender, callData));
}
}/**
** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
** Only one instance required on each chain.
**/
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable avoid-low-level-calls */
/* solhint-disable no-inline-assembly */
/* solhint-disable reason-string */
import "./UserOperation.sol";
import "./IStakeManager.sol";
import "./IAggregator.sol";
import "./INonceManager.sol";
interface IEntryPoint is IStakeManager, INonceManager {
/***
* An event emitted after each successful request
* @param userOpHash - unique identifier for the request (hash its entire content, except signature).
* @param sender - the account that generates this request.
* @param paymaster - if non-null, the paymaster that pays for this request.
* @param nonce - the nonce value from the request.
* @param success - true if the sender transaction succeeded, false if reverted.
* @param actualGasCost - actual amount paid (by account or paymaster) for this UserOperation.
* @param actualGasUsed - total gas used by this UserOperation (including preVerification, creation, validation and execution).
*/
event UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed);
/**
* account "sender" was deployed.
* @param userOpHash the userOp that deployed this account. UserOperationEvent will follow.
* @param sender the account that is deployed
* @param factory the factory used to deploy this account (in the initCode)
* @param paymaster the paymaster used by this UserOp
*/
event AccountDeployed(bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster);
/**
* An event emitted if the UserOperation "callData" reverted with non-zero length
* @param userOpHash the request unique identifier.
* @param sender the sender of this request
* @param nonce the nonce used in the request
* @param revertReason - the return bytes from the (reverted) call to "callData".
*/
event UserOperationRevertReason(bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason);
/**
* an event emitted by handleOps(), before starting the execution loop.
* any event emitted before this event, is part of the validation.
*/
event BeforeExecution();
/**
* signature aggregator used by the following UserOperationEvents within this bundle.
*/
event SignatureAggregatorChanged(address indexed aggregator);
/**
* a custom revert error of handleOps, to identify the offending op.
* NOTE: if simulateValidation passes successfully, there should be no reason for handleOps to fail on it.
* @param opIndex - index into the array of ops to the failed one (in simulateValidation, this is always zero)
* @param reason - revert reason
* The string starts with a unique code "AAmn", where "m" is "1" for factory, "2" for account and "3" for paymaster issues,
* so a failure can be attributed to the correct entity.
* Should be caught in off-chain handleOps simulation and not happen on-chain.
* Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts.
*/
error FailedOp(uint256 opIndex, string reason);
/**
* error case when a signature aggregator fails to verify the aggregated signature it had created.
*/
error SignatureValidationFailed(address aggregator);
/**
* Successful result from simulateValidation.
* @param returnInfo gas and time-range returned values
* @param senderInfo stake information about the sender
* @param factoryInfo stake information about the factory (if any)
* @param paymasterInfo stake information about the paymaster (if any)
*/
error ValidationResult(ReturnInfo returnInfo,
StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo);
/**
* Successful result from simulateValidation, if the account returns a signature aggregator
* @param returnInfo gas and time-range returned values
* @param senderInfo stake information about the sender
* @param factoryInfo stake information about the factory (if any)
* @param paymasterInfo stake information about the paymaster (if any)
* @param aggregatorInfo signature aggregation info (if the account requires signature aggregator)
* bundler MUST use it to verify the signature, or reject the UserOperation
*/
error ValidationResultWithAggregation(ReturnInfo returnInfo,
StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo,
AggregatorStakeInfo aggregatorInfo);
/**
* return value of getSenderAddress
*/
error SenderAddressResult(address sender);
/**
* return value of simulateHandleOp
*/
error ExecutionResult(uint256 preOpGas, uint256 paid, uint48 validAfter, uint48 validUntil, bool targetSuccess, bytes targetResult);
//UserOps handled, per aggregator
struct UserOpsPerAggregator {
UserOperation[] userOps;
// aggregator address
IAggregator aggregator;
// aggregated signature
bytes signature;
}
/**
* Execute a batch of UserOperation.
* no signature aggregator is used.
* if any account requires an aggregator (that is, it returned an aggregator when
* performing simulateValidation), then handleAggregatedOps() must be used instead.
* @param ops the operations to execute
* @param beneficiary the address to receive the fees
*/
function handleOps(UserOperation[] calldata ops, address payable beneficiary) external;
/**
* Execute a batch of UserOperation with Aggregators
* @param opsPerAggregator the operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts)
* @param beneficiary the address to receive the fees
*/
function handleAggregatedOps(
UserOpsPerAggregator[] calldata opsPerAggregator,
address payable beneficiary
) external;
/**
* generate a request Id - unique identifier for this request.
* the request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid.
*/
function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32);
/**
* Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp.
* @dev this method always revert. Successful result is ValidationResult error. other errors are failures.
* @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data.
* @param userOp the user operation to validate.
*/
function simulateValidation(UserOperation calldata userOp) external;
/**
* gas and return values during simulation
* @param preOpGas the gas used for validation (including preValidationGas)
* @param prefund the required prefund for this operation
* @param sigFailed validateUserOp's (or paymaster's) signature check failed
* @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range)
* @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range)
* @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp)
*/
struct ReturnInfo {
uint256 preOpGas;
uint256 prefund;
bool sigFailed;
uint48 validAfter;
uint48 validUntil;
bytes paymasterContext;
}
/**
* returned aggregated signature info.
* the aggregator returned by the account, and its current stake.
*/
struct AggregatorStakeInfo {
address aggregator;
StakeInfo stakeInfo;
}
/**
* Get counterfactual sender address.
* Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation.
* this method always revert, and returns the address in SenderAddressResult error
* @param initCode the constructor code to be passed into the UserOperation.
*/
function getSenderAddress(bytes memory initCode) external;
/**
* simulate full execution of a UserOperation (including both validation and target execution)
* this method will always revert with "ExecutionResult".
* it performs full validation of the UserOperation, but ignores signature error.
* an optional target address is called after the userop succeeds, and its value is returned
* (before the entire call is reverted)
* Note that in order to collect the the success/failure of the target call, it must be executed
* with trace enabled to track the emitted events.
* @param op the UserOperation to simulate
* @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult
* are set to the return from that call.
* @param targetCallData callData to pass to target address
*/
function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import "./UserOperation.sol";
/**
* the interface exposed by a paymaster contract, who agrees to pay the gas for user's operations.
* a paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.
*/
interface IPaymaster {
enum PostOpMode {
opSucceeded, // user op succeeded
opReverted, // user op reverted. still has to pay for gas.
postOpReverted //user op succeeded, but caused postOp to revert. Now it's a 2nd call, after user's op was deliberately reverted.
}
/**
* payment validation: check if paymaster agrees to pay.
* Must verify sender is the entryPoint.
* Revert to reject this request.
* Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted)
* The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns.
* @param userOp the user operation
* @param userOpHash hash of the user's request data.
* @param maxCost the maximum cost of this transaction (based on maximum gas and gas price from userOp)
* @return context value to send to a postOp
* zero length to signify postOp is not required.
* @return validationData signature and time-range of this operation, encoded the same as the return value of validateUserOperation
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost)
external returns (bytes memory context, uint256 validationData);
/**
* post-operation handler.
* Must verify sender is the entryPoint
* @param mode enum with the following options:
* opSucceeded - user operation succeeded.
* opReverted - user op reverted. still has to pay for gas.
* postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert.
* Now this is the 2nd call, after user's op was deliberately reverted.
* @param context - the context value returned by validatePaymasterUserOp
* @param actualGasCost - actual gas used so far (without this postOp call).
*/
function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */
import {calldataKeccak} from "../core/Helpers.sol";
/**
* User Operation struct
* @param sender the sender account of this request.
* @param nonce unique value the sender uses to verify it is not a replay.
* @param initCode if set, the account contract will be created by this constructor/
* @param callData the method call to execute on this account.
* @param callGasLimit the gas limit passed to the callData method call.
* @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
* @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
* @param maxFeePerGas same as EIP-1559 gas parameter.
* @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
* @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender.
* @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID.
*/
struct UserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
uint256 callGasLimit;
uint256 verificationGasLimit;
uint256 preVerificationGas;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
bytes paymasterAndData;
bytes signature;
}
/**
* Utility functions helpful when working with UserOperation structs.
*/
library UserOperationLib {
function getSender(UserOperation calldata userOp) internal pure returns (address) {
address data;
//read sender from userOp, which is first userOp member (saves 800 gas...)
assembly {data := calldataload(userOp)}
return address(uint160(data));
}
//relayer/block builder might submit the TX with higher priorityFee, but the user should not
// pay above what he signed for.
function gasPrice(UserOperation calldata userOp) internal view returns (uint256) {
unchecked {
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
if (maxFeePerGas == maxPriorityFeePerGas) {
//legacy mode (for networks that don't support basefee opcode)
return maxFeePerGas;
}
return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
}
}
function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) {
address sender = getSender(userOp);
uint256 nonce = userOp.nonce;
bytes32 hashInitCode = calldataKeccak(userOp.initCode);
bytes32 hashCallData = calldataKeccak(userOp.callData);
uint256 callGasLimit = userOp.callGasLimit;
uint256 verificationGasLimit = userOp.verificationGasLimit;
uint256 preVerificationGas = userOp.preVerificationGas;
uint256 maxFeePerGas = userOp.maxFeePerGas;
uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);
return abi.encode(
sender, nonce,
hashInitCode, hashCallData,
callGasLimit, verificationGasLimit, preVerificationGas,
maxFeePerGas, maxPriorityFeePerGas,
hashPaymasterAndData
);
}
function hash(UserOperation calldata userOp) internal pure returns (bytes32) {
return keccak256(pack(userOp));
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 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 {
using Address for address;
/**
* @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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @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.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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 silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
struct RouterStateWithNonce {
RouterState state;
uint256 nonce;
}
struct RouterState {
RouterParams params;
IERC20 heldAsset;
uint256 heldAmount;
}
/// @dev Immutable parameters of an order.
struct RouterParams {
bytes32 userOpHash;
bytes32 targetAsset;
uint96 targetChainId;
uint128 targetAmount;
uint128 expiration;
bytes targetCalldata;
TransferOut[] transferOut;
bytes32 recipient;
uint32 slippage;
bytes32 refundAddress;
}
/// @notice A token and how to distribute it
struct TransferOut {
address token;
address recipient;
}
struct SwapParams {
address target;
address spender;
bytes callData;
IERC20 receivedAsset;
uint256 minReceivedAmount;
bool isETHSwap;
uint256 valueFromExcessPool;
}
struct BridgeParams {
address target;
address spender;
bytes callData;
IERC20 bridgeReceivedAsset;
uint256 minBridgeReceivedAmount;
uint256 valueFromExcessPool;
}
interface LiquidityRouterInterface {
function timelockDuration() external view returns (uint256);
function _ALLOWED_OPERATORS_(address operator) external view returns (bool);
function _ALLOWED_CONTRACTS_(address allowedContract) external view returns (bool);
function _ALLOWED_CHAIN_IDS_(uint256 chainId) external view returns (bool);
function _ALLOWED_SWAP_TARGETS_(address target) external view returns (bool);
function _ALLOWED_BRIDGE_TARGETS_(address target) external view returns (bool);
function _POOL_EXCESS_(address asset) external view returns (uint256);
function _TIMELOCK_EXPIRATION_(bytes32 callHash) external view returns (uint256);
function NATIVE_TOKEN() external view returns (address);
function _REFUND_CUT_BPS_() external view returns (uint256);
function deposit(RouterState calldata routerState) external;
function swap(address depositAddress, SwapParams calldata swapParams, RouterState memory order) external;
function swapAndForward(address depositAddress, SwapParams calldata swapParams, RouterState memory order) external;
function bridge(address depositAddress, BridgeParams calldata bridgeParams, RouterState memory order) external;
function getOrderHash(address depositAddress) external view returns (bytes32);
function forwardFund(address depositAddress, RouterState memory order) external;
function setOperator(address operator, bool isAllowed) external;
function setRefundCut(uint256 cut) external;
function addAllowedContracts(address[] calldata contracts) external;
function executeCalldata(address depositAddress, RouterState calldata order) external;
function swapAndExecuteCalldata(
address depositAddress,
SwapParams calldata swapParams,
RouterState calldata order
) external;
function removeAllowedContracts(address[] calldata contracts) external;
function addOperators(address[] calldata operators) external;
function removeOperators(address[] calldata operators) external;
function withdrawFunds(address asset, uint256 amount) external;
function addAllowedChainIds(uint256[] calldata chainIds) external;
function removeAllowedChainIds(uint256[] calldata chainIds) external;
function addExcessToPool(address asset, uint256 amount) external payable;
function removeExcessFromPool(address asset, uint256 amount) external;
function addAllowedSwapTargets(address[] calldata targets) external;
function addAllowedBridgeTargets(address[] calldata targets) external;
function removeAllowedSwapTargets(address[] calldata targets) external;
function removeAllowedBridgeTargets(address[] calldata targets) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface LiquidityRouterEventsAndErrors {
error OrderDoesNotExist();
error OrderExpired();
error SwapTargetNotAllowed(address target);
error SwapDidNotSpendExactAmount(uint256 remainingAllowance);
error SwapDidNotReceiveMinAmount(uint256 remainingBalance);
error SwapReverted(bytes errorData);
error HeldAssetNotWETH(address heldAsset);
error BridgeChainIdNotAllowed(uint256 chainId);
error BridgeTargetNotAllowed(address target);
error BridgeAlreadyOnTargetChain();
error BridgeDidNotSpendExactAmount(uint256 remainingAllowance);
error BridgeReverted(bytes errorData);
error ExecuteReverted(bytes errorData);
error ExecuteInvalidOpsLength();
error ExecuteChainNotReady(uint256 chainId);
error ExecuteAssetNotReady(IERC20 heldAsset);
error ExecuteInsufficientExcessBalance(uint256 oldExcessAmount, uint256 executionAmount, uint256 heldAmount);
error ExecuteInvalidUserOp(bytes32 calculatedUserOpHash);
error ExecuteUserOpReverted(IPaymaster.PostOpMode userOpMode);
error ExecuteInvalidAmount(uint256 heldAmount, uint256 executeAmount);
error ExecuteDidNotSpendExactAmount(uint256 remainingAllowance);
error TimelockNotExpired(bytes32 callHash, uint256 expiration);
error OnlyOperatorsAllowed(address caller);
error OnlyPaymasterAllowed(address caller, address paymaster);
error OnlyContractsAllowed(address contractAdd);
error ForwardFundChainNotReady(uint256 chainId);
error ForwardFundUserOpHashIsSet(bytes32);
error ForwardFundAssetNotReady(IERC20 asset);
error ForwardFundRecipientNotSet();
error ForwardFundReverted(bytes errorData);
error OrderNotVerified(address depositAddress, bytes32 orderHashExpected, bytes32 orderHashActual);
error IncorrectAmountOfNativeToken(uint256 expected, uint256 actual);
error NativeTokenTransferFailed();
error InsufficientTokensInExcessPoolForCall(address asset, uint256 required, uint256 available);
error InsufficientTokensToWithdraw(address asset, uint256 required, uint256 available);
error ExecuteCalldataChainNotReady(uint256 chainId);
error ExecuteCalldataUserOpHashIsSet(bytes32);
error ExecuteCalldataAssetNotReady(IERC20 asset);
error ExecuteCalldataRecipientNotSet();
error ExecuteCalldataRecipientNotContract();
error RefundCutTooHigh();
error RefundTransferFailed(address refundAsset, uint256 refundAmount);
event ExpiredOrder(address indexed depositAddress);
event UpdatedAllowedSwapTarget(address indexed target, bool isAllowed);
event UpdatedAllowedBridgeTarget(address indexed target, bool isAllowed);
event UpdatedAllowedChainIds(uint256 indexed chainId, bool isAllowed);
event UpdatedAllowedOperator(address indexed operator, bool isAllowed);
event UpdatedAllowedContracts(address indexed contractAdd, bool isAllowed);
event ExcessPoolFundsUsedForCall(address indexed asset, uint256 amount);
event ExcessAdded(address indexed asset, uint256 amount);
event ExcessRemoved(address indexed asset, uint256 amount);
event Deposited(address indexed depositAddress, IERC20 receivedAsset, uint256 receivedAmount);
event Bridged(
address indexed depositAddress,
address indexed bridgeTarget,
IERC20 receivedAsset,
uint256 minReceivedAmount,
uint256 nativeValueFromExcessPool
);
event Swapped(
address indexed depositAddress, address indexed swapTarget, IERC20 receivedAsset, uint256 receivedAmount
);
event Executed(address indexed depositAddress, uint256 executionAmount);
event FundForwarded(address indexed depositAddress, uint256 forwardAmount, bytes32 indexed recipient);
event CalldataExecuted(address indexed depositAddress, uint256 forwardAmount, bytes32 indexed recipient);
event RefundDispatched(address indexed depositAddress, IERC20 refundAsset, uint256 refundAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IPaymaster} from "@account-abstraction/contracts/interfaces/IPaymaster.sol";
interface InspectablePaymasterInterface {
function getLastOpMode() external view returns (IPaymaster.PostOpMode);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {BasePaymaster} from "@account-abstraction/contracts/core/BasePaymaster.sol";
import {IEntryPoint} from "@account-abstraction/contracts/interfaces/IEntryPoint.sol";
import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {InspectablePaymasterInterface} from "../interfaces/InspectablePaymasterInterface.sol";
import {OrderPaymasterEventsAndErrors} from "./OrderPaymasterEventsAndErrors.sol";
enum ActiveState {
UNSPECIFIED, // 0
INACTIVE, // 1
ACTIVE // 2
}
/**
* @title OrderPaymaster
*/
contract OrderPaymaster is BasePaymaster, InspectablePaymasterInterface, EIP712, OrderPaymasterEventsAndErrors {
string public constant EIP712_NAME = "OrderPaymaster";
string public constant VERSION = "2"; // Note: Was a uint256 in version 1.
bytes32 private constant SPONSOR_USER_OP_TYPEHASH =
keccak256("SponsorUserOp(" "bytes32 userOpHash," "uint64 deadline" ")");
bytes1 private constant CONTEXT_ACTIVE = bytes1(uint8(0));
bytes1 private constant CONTEXT_INACTIVE = bytes1(uint8(1));
ActiveState internal _ACTIVE_STATE_;
PostOpMode internal _LAST_OP_MODE_;
mapping(address => bool) internal _OPERATORS_;
mapping(address => bool) internal _SIGNERS_;
mapping(bytes32 => bool) internal _SPONSORED_USER_OP_HASHES_;
modifier onlyOperator() {
if (!_OPERATORS_[msg.sender]) {
revert OperatorNotAllowed(msg.sender);
}
_;
}
modifier activate() {
_ACTIVE_STATE_ = ActiveState.ACTIVE;
_;
_ACTIVE_STATE_ = ActiveState.INACTIVE;
}
constructor(IEntryPoint entryPoint) BasePaymaster(entryPoint) EIP712(EIP712_NAME, VERSION) {
_ACTIVE_STATE_ = ActiveState.INACTIVE;
}
function setOperators(address[] calldata operators, bool isAllowed) external onlyOwner {
uint256 n = operators.length;
for (uint256 i; i < n; ++i) {
address operator = operators[i];
_OPERATORS_[operator] = isAllowed;
emit OperatorSet(operator, isAllowed);
}
}
function setSigners(address[] calldata signers, bool isAllowed) external onlyOwner {
uint256 n = signers.length;
for (uint256 i; i < n; ++i) {
address signer = signers[i];
_SIGNERS_[signer] = isAllowed;
emit SignerSet(signer, isAllowed);
}
}
function activateAndCall(address target, bytes calldata callData)
external
payable
onlyOperator
activate
returns (bytes memory)
{
(bool success, bytes memory returnData) = payable(target).call{value: msg.value}(callData);
if (!success) {
assembly {
revert(add(returnData, 32), mload(returnData))
}
}
return returnData;
}
function getLastOpMode() external view returns (PostOpMode) {
return _LAST_OP_MODE_;
}
function isOperatorAllowed(address operator) external view returns (bool) {
return _OPERATORS_[operator];
}
function isSignerAllowed(address signer) external view returns (bool) {
return _SIGNERS_[signer];
}
function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
return _domainSeparatorV4();
}
/**
* @notice Validate a user operation that is using this paymaster.
*
* @param userOp ERC-4337 UserOperation.
*
* @return context The context containing the sponsor, spender, gasPriceUserOp, and opHash.
* @return validationData The validation result.
*/
function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32, /* opHash */ uint256 /* maxCost */ )
internal
override
returns (bytes memory context, uint256 validationData)
{
// Assume paymasterAndData.length >= 20 based on reasonable EntryPoint behavior.
uint256 len = userOp.paymasterAndData.length;
if (len > 20) {
// Format of paymasterAndData:
// - [0:20] address paymaster
// - [20:40] address signer
// - [40:48] uint64 deadline
// - [48:113] bytes signature
if (len != 113) {
revert InvalidPaymasterAndDataLength(len);
}
address expectedSigner = address(bytes20(userOp.paymasterAndData[20:40]));
uint64 deadline = uint64(bytes8(userOp.paymasterAndData[40:48]));
bytes memory signature = userOp.paymasterAndData[48:];
_validateSponsoredUserOp(signature, expectedSigner, deadline, userOp);
context = abi.encodePacked(CONTEXT_ACTIVE);
} else {
context = abi.encodePacked(CONTEXT_INACTIVE);
}
validationData = 0;
}
/**
* @notice Post-operation handler.
* @dev Records the result of the user operation (e.g. success or revert).
*
* Also, reverts if the paymaster was not active, ensuring that only allowed
* operators can make use of this paymaster.
*
* @param mode The mode enum representing the operation result.
*/
function _postOp(PostOpMode mode, bytes calldata context, uint256 /* actualGasCost */ ) internal override {
if (context[0] == CONTEXT_INACTIVE || _ACTIVE_STATE_ != ActiveState.ACTIVE) {
revert Inactive();
}
_LAST_OP_MODE_ = mode;
}
function _validateSponsoredUserOp(
bytes memory signature,
address expectedSigner,
uint64 deadline,
UserOperation calldata userOp
) internal {
if (block.timestamp > deadline) {
revert SignatureExpired(deadline);
}
if (!_SIGNERS_[expectedSigner]) {
revert SignerNotAllowed(expectedSigner);
}
// Zero-out paymasterAndData before hashing the userOp.
UserOperation memory userOpClone = userOp;
userOpClone.paymasterAndData = bytes("");
userOpClone.signature = bytes("");
bytes32 userOpHash = entryPoint.getUserOpHash(userOpClone);
bytes32 structHash = keccak256(abi.encode(SPONSOR_USER_OP_TYPEHASH, userOpHash, deadline));
bytes32 digest = _hashTypedDataV4(structHash);
address recoveredSigner = ECDSA.recover(digest, signature);
if (recoveredSigner != expectedSigner) {
revert SignatureInvalid(recoveredSigner, expectedSigner);
}
if (_SPONSORED_USER_OP_HASHES_[userOpHash]) {
revert SponsoredUserOpRepeated(userOpHash);
}
_SPONSORED_USER_OP_HASHES_[userOpHash] = true;
emit UserOpSponsored(userOpHash);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {GuardianRescuable} from "./GuardianRescuable.sol";
/**
* @title GuardianOwnable
*/
abstract contract GuardianOwnable is Ownable2Step, GuardianRescuable {
error RenounceDisabled();
function guardian() public view override returns (address) {
return owner();
}
function renounceOwnership() public view override onlyOwner {
revert RenounceDisabled();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface WETH9Interface is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {
RouterStateWithNonce, RouterState, RouterParams, TransferOut
} from "../interfaces/LiquidityRouterInterface.sol";
library EncodeLib {
function encode(RouterStateWithNonce memory rswn) internal pure returns (bytes memory) {
return abi.encode(rswn);
}
function hash(RouterStateWithNonce memory rswn) internal pure returns (bytes32) {
return keccak256(encode(rswn));
}
function encode(RouterState memory rs) internal pure returns (bytes memory) {
return abi.encode(rs);
}
function hash(RouterState memory rs) internal pure returns (bytes32) {
return keccak256(encode(rs));
}
function encode(RouterParams memory rp) internal pure returns (bytes memory) {
return abi.encode(rp);
}
function hash(RouterParams memory rp) internal pure returns (bytes32) {
return keccak256(encode(rp));
}
function encode(TransferOut[] memory tos) internal pure returns (bytes memory) {
return abi.encode(tos);
}
function hash(TransferOut[] memory tos) internal pure returns (bytes32) {
return keccak256(encode(tos));
}
function encode(TransferOut memory to) internal pure returns (bytes memory) {
return abi.encode(to);
}
function hash(TransferOut memory to) internal pure returns (bytes32) {
return keccak256(encode(to));
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.12;
/**
* manage deposits and stakes.
* deposit is just a balance used to pay for UserOperations (either by a paymaster or an account)
* stake is value locked for at least "unstakeDelay" by the staked entity.
*/
interface IStakeManager {
event Deposited(
address indexed account,
uint256 totalDeposit
);
event Withdrawn(
address indexed account,
address withdrawAddress,
uint256 amount
);
/// Emitted when stake or unstake delay are modified
event StakeLocked(
address indexed account,
uint256 totalStaked,
uint256 unstakeDelaySec
);
/// Emitted once a stake is scheduled for withdrawal
event StakeUnlocked(
address indexed account,
uint256 withdrawTime
);
event StakeWithdrawn(
address indexed account,
address withdrawAddress,
uint256 amount
);
/**
* @param deposit the entity's deposit
* @param staked true if this entity is staked.
* @param stake actual amount of ether staked for this entity.
* @param unstakeDelaySec minimum delay to withdraw the stake.
* @param withdrawTime - first block timestamp where 'withdrawStake' will be callable, or zero if already locked
* @dev sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps)
* and the rest fit into a 2nd cell.
* 112 bit allows for 10^15 eth
* 48 bit for full timestamp
* 32 bit allows 150 years for unstake delay
*/
struct DepositInfo {
uint112 deposit;
bool staked;
uint112 stake;
uint32 unstakeDelaySec;
uint48 withdrawTime;
}
//API struct used by getStakeInfo and simulateValidation
struct StakeInfo {
uint256 stake;
uint256 unstakeDelaySec;
}
/// @return info - full deposit information of given account
function getDepositInfo(address account) external view returns (DepositInfo memory info);
/// @return the deposit (for gas payment) of the account
function balanceOf(address account) external view returns (uint256);
/**
* add to the deposit of the given account
*/
function depositTo(address account) external payable;
/**
* add to the account's stake - amount and delay
* any pending unstake is first cancelled.
* @param _unstakeDelaySec the new lock duration before the deposit can be withdrawn.
*/
function addStake(uint32 _unstakeDelaySec) external payable;
/**
* attempt to unlock the stake.
* the value can be withdrawn (using withdrawStake) after the unstake delay.
*/
function unlockStake() external;
/**
* withdraw from the (unlocked) stake.
* must first call unlockStake and wait for the unstakeDelay to pass
* @param withdrawAddress the address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external;
/**
* withdraw from the deposit.
* @param withdrawAddress the address to send withdrawn value.
* @param withdrawAmount the amount to withdraw.
*/
function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import "./UserOperation.sol";
/**
* Aggregated Signatures validator.
*/
interface IAggregator {
/**
* validate aggregated signature.
* revert if the aggregated signature does not match the given list of operations.
*/
function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view;
/**
* validate signature of a single userOp
* This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation
* First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps.
* @param userOp the userOperation received from the user.
* @return sigForUserOp the value to put into the signature field of the userOp when calling handleOps.
* (usually empty, unless account and aggregator support some kind of "multisig"
*/
function validateUserOpSignature(UserOperation calldata userOp)
external view returns (bytes memory sigForUserOp);
/**
* aggregate multiple signatures into a single value.
* This method is called off-chain to calculate the signature to pass with handleOps()
* bundler MAY use optimized custom code perform this aggregation
* @param userOps array of UserOperations to collect the signatures from.
* @return aggregatedSignature the aggregated signature
*/
function aggregateSignatures(UserOperation[] calldata userOps) external view returns (bytes memory aggregatedSignature);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
interface INonceManager {
/**
* Return the next nonce for this sender.
* Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop)
* But UserOp with different keys can come with arbitrary order.
*
* @param sender the account address
* @param key the high 192 bit of the nonce
* @return nonce a full nonce to pass for next UserOp with this sender.
*/
function getNonce(address sender, uint192 key)
external view returns (uint256 nonce);
/**
* Manually increment the nonce of the sender.
* This method is exposed just for completeness..
* Account does NOT need to call it, neither during validation, nor elsewhere,
* as the EntryPoint will update the nonce regardless.
* Possible use-case is call it with various keys to "initialize" their nonces to one, so that future
* UserOperations will not pay extra for the first transaction with a given key.
*/
function incrementNonce(uint192 key) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable no-inline-assembly */
/**
* returned data from validateUserOp.
* validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData`
* @param aggregator - address(0) - the account validated the signature by itself.
* address(1) - the account failed to validate the signature.
* otherwise - this is an address of a signature aggregator that must be used to validate the signature.
* @param validAfter - this UserOp is valid only after this timestamp.
* @param validaUntil - this UserOp is valid only up to this timestamp.
*/
struct ValidationData {
address aggregator;
uint48 validAfter;
uint48 validUntil;
}
//extract sigFailed, validAfter, validUntil.
// also convert zero validUntil to type(uint48).max
function _parseValidationData(uint validationData) pure returns (ValidationData memory data) {
address aggregator = address(uint160(validationData));
uint48 validUntil = uint48(validationData >> 160);
if (validUntil == 0) {
validUntil = type(uint48).max;
}
uint48 validAfter = uint48(validationData >> (48 + 160));
return ValidationData(aggregator, validAfter, validUntil);
}
// intersect account and paymaster ranges.
function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) {
ValidationData memory accountValidationData = _parseValidationData(validationData);
ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData);
address aggregator = accountValidationData.aggregator;
if (aggregator == address(0)) {
aggregator = pmValidationData.aggregator;
}
uint48 validAfter = accountValidationData.validAfter;
uint48 validUntil = accountValidationData.validUntil;
uint48 pmValidAfter = pmValidationData.validAfter;
uint48 pmValidUntil = pmValidationData.validUntil;
if (validAfter < pmValidAfter) validAfter = pmValidAfter;
if (validUntil > pmValidUntil) validUntil = pmValidUntil;
return ValidationData(aggregator, validAfter, validUntil);
}
/**
* helper to pack the return value for validateUserOp
* @param data - the ValidationData to pack
*/
function _packValidationData(ValidationData memory data) pure returns (uint256) {
return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48));
}
/**
* helper to pack the return value for validateUserOp, when not using an aggregator
* @param sigFailed - true for signature failure, false for success
* @param validUntil last timestamp this UserOperation is valid (or zero for infinite)
* @param validAfter first timestamp this UserOperation is valid
*/
function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) {
return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48));
}
/**
* keccak function over calldata.
* @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
*/
function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
assembly {
let mem := mload(0x40)
let len := data.length
calldatacopy(mem, data.offset, len)
ret := keccak256(mem, len)
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
/* solhint-disable reason-string */
import "@openzeppelin/contracts/access/Ownable.sol";
import "../interfaces/IPaymaster.sol";
import "../interfaces/IEntryPoint.sol";
import "./Helpers.sol";
/**
* Helper class for creating a paymaster.
* provides helper methods for staking.
* validates that the postOp is called only by the entryPoint
*/
abstract contract BasePaymaster is IPaymaster, Ownable {
IEntryPoint immutable public entryPoint;
constructor(IEntryPoint _entryPoint) {
entryPoint = _entryPoint;
}
/// @inheritdoc IPaymaster
function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost)
external override returns (bytes memory context, uint256 validationData) {
_requireFromEntryPoint();
return _validatePaymasterUserOp(userOp, userOpHash, maxCost);
}
function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost)
internal virtual returns (bytes memory context, uint256 validationData);
/// @inheritdoc IPaymaster
function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external override {
_requireFromEntryPoint();
_postOp(mode, context, actualGasCost);
}
/**
* post-operation handler.
* (verified to be called only through the entryPoint)
* @dev if subclass returns a non-empty context from validatePaymasterUserOp, it must also implement this method.
* @param mode enum with the following options:
* opSucceeded - user operation succeeded.
* opReverted - user op reverted. still has to pay for gas.
* postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert.
* Now this is the 2nd call, after user's op was deliberately reverted.
* @param context - the context value returned by validatePaymasterUserOp
* @param actualGasCost - actual gas used so far (without this postOp call).
*/
function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal virtual {
(mode,context,actualGasCost); // unused params
// subclass must override this method if validatePaymasterUserOp returns a context
revert("must override");
}
/**
* add a deposit for this paymaster, used for paying for transaction fees
*/
function deposit() public payable {
entryPoint.depositTo{value : msg.value}(address(this));
}
/**
* withdraw value from the deposit
* @param withdrawAddress target to send to
* @param amount to withdraw
*/
function withdrawTo(address payable withdrawAddress, uint256 amount) public onlyOwner {
entryPoint.withdrawTo(withdrawAddress, amount);
}
/**
* add stake for this paymaster.
* This method can also carry eth value to add to the current stake.
* @param unstakeDelaySec - the unstake delay for this paymaster. Can only be increased.
*/
function addStake(uint32 unstakeDelaySec) external payable onlyOwner {
entryPoint.addStake{value : msg.value}(unstakeDelaySec);
}
/**
* return current paymaster's deposit on the entryPoint.
*/
function getDeposit() public view returns (uint256) {
return entryPoint.balanceOf(address(this));
}
/**
* unlock the stake, in order to withdraw it.
* The paymaster can't serve requests once unlocked, until it calls addStake again
*/
function unlockStake() external onlyOwner {
entryPoint.unlockStake();
}
/**
* withdraw the entire paymaster's stake.
* stake must be unlocked first (and then wait for the unstakeDelay to be over)
* @param withdrawAddress the address to send withdrawn value.
*/
function withdrawStake(address payable withdrawAddress) external onlyOwner {
entryPoint.withdrawStake(withdrawAddress);
}
/// validate the call is made from a valid entrypoint
function _requireFromEntryPoint() internal virtual {
require(msg.sender == address(entryPoint), "Sender not EntryPoint");
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* _Available since v3.4._
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {EIP-5267}.
*
* _Available since v4.9._
*/
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface OrderPaymasterEventsAndErrors {
error Inactive();
error InvalidPaymasterAndDataLength(uint256 length);
error OperatorNotAllowed(address operator);
error SignerNotAllowed(address signer);
error SignatureExpired(uint256 deadline);
error SignatureInvalid(address recoveredSigner, address expectedSigner);
error SponsoredUserOpRepeated(bytes32 userOpHash);
event OperatorSet(address indexed operator, bool isAllowed);
event SignerSet(address indexed signer, bool isAllowed);
/// @dev Intentionally not indexed to save gas since most clients won't need this.
event UserOpSponsored(bytes32 userOpHash);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/**
* @title GuardianRescuable
*/
abstract contract GuardianRescuable {
using SafeERC20 for IERC20;
error NotGuardian(address sender);
modifier onlyGuardian() {
if (msg.sender != guardian()) {
revert NotGuardian(msg.sender);
}
_;
}
function guardian() public virtual returns (address);
function withdrawNative(address payable recipient, uint256 amount) external onlyGuardian {
recipient.transfer(amount);
}
function withdrawErc20(IERC20 token, address recipient, uint256 amount) external onlyGuardian {
token.safeTransfer(recipient, amount);
}
function withdrawAllNative(address payable recipient) external onlyGuardian {
recipient.transfer(address(this).balance);
}
function withdrawAllErc20(IERC20 token, address recipient) external onlyGuardian {
uint256 balance = token.balanceOf(address(this));
token.safeTransfer(recipient, balance);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@account-abstraction/contracts/=lib/account-abstraction/contracts/",
"account-abstraction/=lib/account-abstraction/contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 5000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"contract IEntryPoint","name":"entryPoint","type":"address"},{"internalType":"address","name":"wrappedNativeToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BridgeAlreadyOnTargetChain","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"BridgeChainIdNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"remainingAllowance","type":"uint256"}],"name":"BridgeDidNotSpendExactAmount","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"BridgeReverted","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"BridgeTargetNotAllowed","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"heldAsset","type":"address"}],"name":"ExecuteAssetNotReady","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"asset","type":"address"}],"name":"ExecuteCalldataAssetNotReady","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ExecuteCalldataChainNotReady","type":"error"},{"inputs":[],"name":"ExecuteCalldataRecipientNotContract","type":"error"},{"inputs":[],"name":"ExecuteCalldataRecipientNotSet","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ExecuteCalldataUserOpHashIsSet","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ExecuteChainNotReady","type":"error"},{"inputs":[{"internalType":"uint256","name":"remainingAllowance","type":"uint256"}],"name":"ExecuteDidNotSpendExactAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"oldExcessAmount","type":"uint256"},{"internalType":"uint256","name":"executionAmount","type":"uint256"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"name":"ExecuteInsufficientExcessBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"heldAmount","type":"uint256"},{"internalType":"uint256","name":"executeAmount","type":"uint256"}],"name":"ExecuteInvalidAmount","type":"error"},{"inputs":[],"name":"ExecuteInvalidOpsLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"calculatedUserOpHash","type":"bytes32"}],"name":"ExecuteInvalidUserOp","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"ExecuteReverted","type":"error"},{"inputs":[{"internalType":"enum IPaymaster.PostOpMode","name":"userOpMode","type":"uint8"}],"name":"ExecuteUserOpReverted","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"asset","type":"address"}],"name":"ForwardFundAssetNotReady","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ForwardFundChainNotReady","type":"error"},{"inputs":[],"name":"ForwardFundRecipientNotSet","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"ForwardFundReverted","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ForwardFundUserOpHashIsSet","type":"error"},{"inputs":[{"internalType":"address","name":"heldAsset","type":"address"}],"name":"HeldAssetNotWETH","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"IncorrectAmountOfNativeToken","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"InsufficientTokensInExcessPoolForCall","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"InsufficientTokensToWithdraw","type":"error"},{"inputs":[],"name":"NativeTokenTransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"NotGuardian","type":"error"},{"inputs":[{"internalType":"address","name":"contractAdd","type":"address"}],"name":"OnlyContractsAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"OnlyOperatorsAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"paymaster","type":"address"}],"name":"OnlyPaymasterAllowed","type":"error"},{"inputs":[],"name":"OrderDoesNotExist","type":"error"},{"inputs":[],"name":"OrderExpired","type":"error"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"internalType":"bytes32","name":"orderHashExpected","type":"bytes32"},{"internalType":"bytes32","name":"orderHashActual","type":"bytes32"}],"name":"OrderNotVerified","type":"error"},{"inputs":[],"name":"RefundCutTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"refundAsset","type":"address"},{"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"RefundTransferFailed","type":"error"},{"inputs":[],"name":"RenounceDisabled","type":"error"},{"inputs":[{"internalType":"uint256","name":"remainingBalance","type":"uint256"}],"name":"SwapDidNotReceiveMinAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"remainingAllowance","type":"uint256"}],"name":"SwapDidNotSpendExactAmount","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorData","type":"bytes"}],"name":"SwapReverted","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"SwapTargetNotAllowed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"callHash","type":"bytes32"},{"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"TimelockNotExpired","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":true,"internalType":"address","name":"bridgeTarget","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"receivedAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"minReceivedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeValueFromExcessPool","type":"uint256"}],"name":"Bridged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"forwardAmount","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"CalldataExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"receivedAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExcessAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExcessPoolFundsUsedForCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExcessRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"executionAmount","type":"uint256"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"}],"name":"ExpiredOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"forwardAmount","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"FundForwarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"refundAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"RefundDispatched","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositAddress","type":"address"},{"indexed":true,"internalType":"address","name":"swapTarget","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"receivedAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"UpdatedAllowedBridgeTarget","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"UpdatedAllowedChainIds","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAdd","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"UpdatedAllowedContracts","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"UpdatedAllowedOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"UpdatedAllowedSwapTarget","type":"event"},{"inputs":[],"name":"ENTRY_POINT","outputs":[{"internalType":"contract IEntryPoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDT_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WRAPPED_NATIVE_TOKEN","outputs":[{"internalType":"contract WETH9Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"_ALLOWED_BRIDGE_TARGETS_","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"_ALLOWED_CHAIN_IDS_","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"allowedContracts","type":"address"}],"name":"_ALLOWED_CONTRACTS_","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"_ALLOWED_OPERATORS_","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"_ALLOWED_SWAP_TARGETS_","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_ALLOW_ALL_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"_POOL_EXCESS_","outputs":[{"internalType":"uint256","name":"excessAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_REFUND_CUT_BPS_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"_TIMELOCK_EXPIRATION_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"}],"name":"addAllowedBridgeTargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"addAllowedChainIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"addAllowedContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"}],"name":"addAllowedSwapTargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addExcessToPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"operators","type":"address[]"}],"name":"addOperators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"contract IERC20","name":"bridgeReceivedAsset","type":"address"},{"internalType":"uint256","name":"minBridgeReceivedAmount","type":"uint256"},{"internalType":"uint256","name":"valueFromExcessPool","type":"uint256"}],"internalType":"struct BridgeParams","name":"bridgeParams","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"executeCalldata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"forwardFund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"}],"name":"getOrderHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"}],"name":"removeAllowedBridgeTargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"chainIds","type":"uint256[]"}],"name":"removeAllowedChainIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"removeAllowedContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"}],"name":"removeAllowedSwapTargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"removeExcessFromPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"operators","type":"address[]"}],"name":"removeOperators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"setAllowAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cut","type":"uint256"}],"name":"setRefundCut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setTimelockDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"contract IERC20","name":"receivedAsset","type":"address"},{"internalType":"uint256","name":"minReceivedAmount","type":"uint256"},{"internalType":"bool","name":"isETHSwap","type":"bool"},{"internalType":"uint256","name":"valueFromExcessPool","type":"uint256"}],"internalType":"struct SwapParams","name":"swapParams","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"contract IERC20","name":"receivedAsset","type":"address"},{"internalType":"uint256","name":"minReceivedAmount","type":"uint256"},{"internalType":"bool","name":"isETHSwap","type":"bool"},{"internalType":"uint256","name":"valueFromExcessPool","type":"uint256"}],"internalType":"struct SwapParams","name":"swapParams","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"swapAndExecuteCalldata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositAddress","type":"address"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"contract IERC20","name":"receivedAsset","type":"address"},{"internalType":"uint256","name":"minReceivedAmount","type":"uint256"},{"internalType":"bool","name":"isETHSwap","type":"bool"},{"internalType":"uint256","name":"valueFromExcessPool","type":"uint256"}],"internalType":"struct SwapParams","name":"swapParams","type":"tuple"},{"components":[{"components":[{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"bytes32","name":"targetAsset","type":"bytes32"},{"internalType":"uint96","name":"targetChainId","type":"uint96"},{"internalType":"uint128","name":"targetAmount","type":"uint128"},{"internalType":"uint128","name":"expiration","type":"uint128"},{"internalType":"bytes","name":"targetCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct TransferOut[]","name":"transferOut","type":"tuple[]"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint32","name":"slippage","type":"uint32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"}],"internalType":"struct RouterParams","name":"params","type":"tuple"},{"internalType":"contract IERC20","name":"heldAsset","type":"address"},{"internalType":"uint256","name":"heldAmount","type":"uint256"}],"internalType":"struct RouterState","name":"order","type":"tuple"}],"name":"swapAndForward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawAllErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"}],"name":"withdrawAllNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101003461016b57601f61470038819003918201601f19168301916001600160401b0383118484101761016f5780849260609460405283398101031261016b5761004881610183565b602082015190916001600160a01b038216820361016b5761006e60406100b99201610183565b9261007833610197565b6201518060025573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60c05273dac17f958d2ee523a2206206994597c13d831ec760e0526005600355610197565b6080526001600160a01b031660a05260405161451490816101ec823960805181610aec015260a05181818161163401528181612d3c01528181612e210152818161344d01528181613a720152613f00015260c0518181816107d20152818161104d0152818161120501528181611414015281816121e201528181612bef01528181612cda015281816134220152613954015260e051818181610fbd015281816124820152818161328c015261424b0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b038216820361016b57565b600180546001600160a01b03199081169091555f80546001600160a01b03938416928116831782559192909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806307b18bde146117d95780630b3c2411146116b9578063150fea09146116985780631593dee1146116585780631b3f8c5e1461161557806320c0953f146115e65780632680a404146115a957806327b8d9421461156a5780632bbca1571461154d5780632eab14551461143857806331f7d964146113f5578063377316af1461135e5780633b2d7fd614611321578063452a932014610bf15780634d7d9c01146112e85780634ea0e5a2146112ab57806350c56ca6146111bb578063558a729714611164578063580de174146111265780636067570414611021578063715018a614610fe157806377b330c914610f9e57806379ba509714610e925780637daa141b14610deb5780638196e98e14610dce5780638922197d14610d1757806389a9453a14610c755780638a7c349c14610c385780638c45433414610c165780638da5cb5b14610bf15780638f0ad13c14610bb25780639391d03214610b1057806394430fa514610acd5780639e59483d14610a2b578063a07aea1c14610987578063a3c6482c1461094f578063b75b6090146108fa578063c10753291461079a578063c5f3f46314610748578063ca7b3d3b1461071e578063cee5940e146105ed578063d365a3771461054b578063d966b29e1461050e578063d9f66db114610481578063e30c39781461045b578063e34accc2146103f4578063f2fde38b1461036f578063f56c4892146102e65763fa40ce340361000e57346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761026a90369060040161183d565b6102726128ae565b5f5b81811061027d57005b806001600160a01b0361029b6102966001948688612959565b611e4d565b16805f52600b60205260405f208360ff198254161790557f6163be4e9de13d310048eae21c71c771155520680b869551fc3e90ca3b52c13a6020604051858152a201610274565b5f80fd5b346102e2576102f436611b59565b906001600160a01b03831692835f52600c60205260405f2054610316846129f7565b03610325576100189350612850565b5050815f52600c60205261033d60405f2054916129f7565b917f1d03b3e8000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b346102e25760206003193601126102e2576001600160a01b03610390611827565b6103986128ae565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001556001600160a01b035f54167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346102e25760206003193601126102e2576001600160a01b03610415611827565b165f52600c60205260405f2054801561043357602090604051908152f35b7f5dcaf2d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e2575f6003193601126102e25760206001600160a01b0360015416604051908152f35b346102e25760206003193601126102e25761049a611827565b6001600160a01b035f541633036104e2575f808080934790829082156104d8575b6001600160a01b031690f1156104cd57005b6040513d5f823e3d90fd5b6108fc91506104bb565b7fa252c151000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b346102e25760206003193601126102e2576001600160a01b0361052f611827565b165f526006602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761057c90369060040161183d565b6105846128ae565b5f5b81811061058f57005b806001600160a01b036105a86102966001948688612959565b16805f52600760205260405f2060ff1981541690557f3ce179bb425f4afab8ab551b382acfa5d68573aa6363cad06bad95b15bc1330b60206040515f8152a201610586565b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761061e90369060040161183d565b906106276128ae565b6106313633612905565b90815f52600a60205260405f20549283155f14610669575050905061065860025442611bff565b905f52600a60205260405f20555f80f35b8342105f146106a25750507f46f71e7f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919092505f52600a6020525f60408120555f5b8181106106be57005b806001600160a01b036106d76102966001948688612959565b16805f52600560205260405f208360ff198254161790557f52187c41547927b6e1bcf48e821c5fd0c6b9918398fd10d770e5b9580b44c0696020604051858152a2016106b5565b346102e25760206003193601126102e2576004355f52600a602052602060405f2054604051908152f35b346102e25760206003193601126102e2576004356107646128ae565b612710811161077257600355005b7f7ba842b1000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e25760406003193601126102e2576107b3611827565b6024356107be6128ae565b6001600160a01b0382166001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681145f1461086b575f826108268295839561081c8596479087526009602052604087205490611fc2565b918183101561280b565b6001600160a01b038254165af161083b611fcf565b501561084357005b7f3022f2e4000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040516370a0823160e01b8152306004820152602081602481855afa9081156104cd575f916108c6575b50610018938361081c6108b593855f52600960205260405f205490611fc2565b6001600160a01b035f541690612996565b90506020813d6020116108f2575b816108e160209383611898565b810103126102e25751610018610895565b3d91506108d4565b346102e25761090836611bbf565b6001600160a01b03821691825f52600c60205260405f2054610929836129f7565b03610938576100189250612715565b50815f52600c60205261033d60405f2054916129f7565b346102e25760206003193601126102e2576001600160a01b03610970611827565b165f526009602052602060405f2054604051908152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e2576109b890369060040161183d565b6109c06128ae565b5f5b8181106109cb57005b806001600160a01b036109e46102966001948688612959565b16805f52600760205260405f208360ff198254161790557f3ce179bb425f4afab8ab551b382acfa5d68573aa6363cad06bad95b15bc1330b6020604051858152a2016109c2565b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257610a5c90369060040161183d565b610a646128ae565b5f5b818110610a6f57005b806001600160a01b03610a886102966001948688612959565b16805f52600660205260405f2060ff1981541690557ff007979304ad19c08251c22274ee0b988c783a3f565cc53ad61a96f83dcf02cd60206040515f8152a201610a66565b346102e2575f6003193601126102e25760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257610b4190369060040161183d565b610b496128ae565b5f5b818110610b5457005b806001600160a01b03610b6d6102966001948688612959565b16805f52600560205260405f2060ff1981541690557f52187c41547927b6e1bcf48e821c5fd0c6b9918398fd10d770e5b9580b44c06960206040515f8152a201610b4b565b346102e257610bc036611b59565b906001600160a01b03831692835f52600c60205260405f2054610be2846129f7565b0361032557610018935061262b565b346102e2575f6003193601126102e25760206001600160a01b035f5416604051908152f35b346102e2575f6003193601126102e257602060ff600454166040519015158152f35b346102e25760206003193601126102e2576001600160a01b03610c59611827565b165f52600b602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257610ca690369060040161183d565b610cae6128ae565b5f5b818110610cb957005b806001600160a01b03610cd26102966001948688612959565b16805f52600b60205260405f2060ff1981541690557f6163be4e9de13d310048eae21c71c771155520680b869551fc3e90ca3b52c13a60206040515f8152a201610cb0565b346102e25760606003193601126102e257610d30611827565b6024359067ffffffffffffffff82116102e25760c060031983360301126102e2576044359067ffffffffffffffff82116102e25760606003198360040193360301126102e257610d803683611939565b926001600160a01b03821693845f52600c60205260405f2054610da2826129f7565b03610db65750610018935060040190612104565b8490815f52600c60205261033d60405f2054916129f7565b346102e2575f6003193601126102e2576020600354604051908152f35b346102e25760406003193601126102e257610e04611827565b610e0c611882565b906001600160a01b035f541633036104e257604051916370a0823160e01b83523060048401526020836024816001600160a01b0386165afa9182156104cd575f92610e5c575b6100189350612996565b91506020833d602011610e8a575b81610e7760209383611898565b810103126102e257610018925191610e52565b3d9150610e6a565b346102e2575f6003193601126102e257600154336001600160a01b03821603610f34577fffffffffffffffffffffffff0000000000000000000000000000000000000000166001555f54337fffffffffffffffffffffffff00000000000000000000000000000000000000008216175f556001600160a01b033391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b608460405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102e2575f6003193601126102e25760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102e2575f6003193601126102e257610ff96128ae565b7f89051165000000000000000000000000000000000000000000000000000000005f5260045ffd5b60406003193601126102e257611035611827565b6001600160a01b036024359116906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682145f146110f1578034036110c25760207fb742da464f5cf7517f0a451e9feeb72d5645001a500605bccb7f972001ea9633915b835f526009825260405f206110b7828254611bff565b9055604051908152a2005b7f3ca29a83000000000000000000000000000000000000000000000000000000005f526004523460245260445ffd5b6020816111217fb742da464f5cf7517f0a451e9feeb72d5645001a500605bccb7f972001ea963393303387613329565b6110a1565b346102e25761113436611bbf565b6001600160a01b03821691825f52600c60205260405f2054611155836129f7565b03610938576100189250611ffe565b346102e25760406003193601126102e25761117d611827565b6024359081151582036102e2576001600160a01b039061119b6128ae565b165f52600760205260405f209060ff60ff19835416911515161790555f80f35b346102e25760406003193601126102e2576111d4611827565b6001600160a01b03602435916111e86128ae565b1690815f52600960205260405f20611201828254611fc2565b90557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168203611277575f80808084335af1611243611fcf565b50156108435760207f3bde90ddec8b620631bf91ff34269455f889277ab58bbde3b5d94c4a0428e25c915b604051908152a2005b6020816112a67f3bde90ddec8b620631bf91ff34269455f889277ab58bbde3b5d94c4a0428e25c933386612996565b61126e565b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257606060031982360301126102e25761001890600401611e94565b346102e25760206003193601126102e2576004358015158091036102e25761130e6128ae565b60ff60ff19600454169116176004555f80f35b346102e25760206003193601126102e2576001600160a01b03611342611827565b165f526005602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761138f90369060040161183d565b6113976128ae565b5f5b8181106113a257005b806113b06001928486612959565b35805f52600860205260405f2060ff1981541690557fd68bd2e440c0eb451dd2f1fa546d640c7e228770733d017d92fa648d54b311f660206040515f8152a201611399565b346102e2575f6003193601126102e25760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761146990369060040161183d565b906114726128ae565b61147c3633612905565b90815f52600a60205260405f20549283155f146114a3575050905061065860025442611bff565b8342105f146114dc5750507f46f71e7f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919092505f52600a6020525f60408120555f5b8181106114f857005b806115066001928486612959565b35805f52600860205260405f208360ff198254161790557fd68bd2e440c0eb451dd2f1fa546d640c7e228770733d017d92fa648d54b311f66020604051858152a2016114ef565b346102e2575f6003193601126102e2576020600254604051908152f35b346102e25761157836611b59565b906001600160a01b03831692835f52600c60205260405f205461159a846129f7565b03610325576100189350611c39565b346102e25760206003193601126102e2576001600160a01b036115ca611827565b165f526007602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e2576004355f526008602052602060ff60405f2054166040519015158152f35b346102e2575f6003193601126102e25760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102e25760606003193601126102e257611671611827565b611679611882565b906001600160a01b035f541633036104e2576100189160443591612996565b346102e25760206003193601126102e2576116b16128ae565b600435600255005b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e2576116ea90369060040161183d565b906116f36128ae565b6116fd3633612905565b90815f52600a60205260405f20549283155f14611724575050905061065860025442611bff565b8342105f1461175d5750507f46f71e7f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919092505f52600a6020525f60408120555f5b81811061177957005b806001600160a01b036117926102966001948688612959565b16805f52600660205260405f208360ff198254161790557ff007979304ad19c08251c22274ee0b988c783a3f565cc53ad61a96f83dcf02cd6020604051858152a201611770565b346102e25760406003193601126102e2576117f2611827565b602435906001600160a01b035f541633036104e2575f8080938193829082156104d8576001600160a01b031690f1156104cd57005b600435906001600160a01b03821682036102e257565b9181601f840112156102e25782359167ffffffffffffffff83116102e2576020808501948460051b0101116102e257565b35906001600160a01b03821682036102e257565b602435906001600160a01b03821682036102e257565b90601f601f19910116810190811067ffffffffffffffff8211176118bb57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b35906fffffffffffffffffffffffffffffffff821682036102e257565b67ffffffffffffffff81116118bb57601f01601f191660200190565b67ffffffffffffffff81116118bb5760051b60200190565b91906060838203126102e257604051906060820182811067ffffffffffffffff8211176118bb576040528193803567ffffffffffffffff81116102e257810190610140828403126102e25760405192610140840184811067ffffffffffffffff8211176118bb57604052823584526020830135602085015260408301356bffffffffffffffffffffffff811681036102e25760408501526119dc606084016118e8565b60608501526119ed608084016118e8565b608085015260a083013567ffffffffffffffff81116102e257830181601f820112156102e2578035611a1e81611905565b91611a2c6040519384611898565b81835283602083830101116102e257815f926020809301838601378301015260a085015260c083013567ffffffffffffffff81116102e257830181601f820112156102e257803590611a7d82611921565b92611a8b6040519485611898565b82845260208085019360061b830101918183116102e257602001925b828410611b06575050505060c084015260e082013560e08401526101008201359263ffffffff841684036102e25761012060409493859461010084015201356101208201528452611afa6020820161186e565b60208501520135910152565b6040848303126102e25760405190604082019082821067ffffffffffffffff8311176118bb576040926020928452611b3d8761186e565b8152611b4a83880161186e565b83820152815201930192611aa7565b60606003198201126102e2576004356001600160a01b03811681036102e2579160243567ffffffffffffffff81116102e25760e060031982850301126102e257600401916044359067ffffffffffffffff82116102e257611bbc91600401611939565b90565b9060406003198301126102e2576004356001600160a01b03811681036102e257916024359067ffffffffffffffff82116102e257611bbc91600401611939565b91908201809211611c0c57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b909180516fffffffffffffffffffffffffffffffff608082015116421015611da85750611c6583611e4d565b60ff600454168015611d89575b15611d545750335f52600760205260ff60405f20541615611d28576001600160a01b0381611d2382611cfa8782611ccd7f5a417e3ceaff68360f7300df6686a9d417ae12328724de7bc2fd6c012a2ffa8598611ce59b612ca9565b9a9096826020820198604083019d8e521688526129f7565b981697885f52600c60205260405f2055611e4d565b9251169551604051938493169683602090939291936001600160a01b0360408201951681520152565b0390a3565b7f6a0576da000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b6001600160a01b03907fb25f49d4000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506001600160a01b0381165f52600560205260ff60405f205416611c72565b610120919350015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b60208181015160409283015183516001600160a01b0390921682529181019190915290819081015b0390a2565b7fc56873ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b356001600160a01b03811681036102e25790565b9035907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1813603018212156102e2570190565b6080611ea08280611e61565b01356fffffffffffffffffffffffffffffffff81168091036102e257421015611f54577f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a7611e20611f2f60208401611f1d611f18611efd83611e4d565b96611f116040820135809930903390613329565b3690611939565b6129f7565b335f52600c60205260405f2055611e4d565b92604051918291339583602090939291936001600160a01b0360408201951681520152565b611f72611f6360208301611e4d565b60408301359030903390613329565b610120611f7f8280611e61565b0135611fad5750337ff675619421689a1f9bfda05f0997e733648107b14bf1eae11ab626e06e3d73b85f80a2565b611fbb611fc0913690611939565b612b70565b565b91908203918211611c0c57565b3d15611ff9573d90611fe082611905565b91611fee6040519384611898565b82523d5f602084013e565b606090565b81516fffffffffffffffffffffffffffffffff6080820151164210156120b7575090335f52600760205260ff60405f20541615611d28576bffffffffffffffffffffffff60408251015116460361208b5760e0815101511561206357611fc09161339e565b7f1fb2fee6000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f9930d34e000000000000000000000000000000000000000000000000000000005f524660045260245ffd5b610120015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b9190916121113683611939565b80516fffffffffffffffffffffffffffffffff60808201511642101561256f57505061213c83611e4d565b60045460ff16801593918185612550575b1561251b5750335f52600760205260ff60405f20541615611d285761217460208301611e4d565b936040612185818501359480611e61565b0135916bffffffffffffffffffffffff83168093036102e2574683146124f357906124dd575b156124b257506001461480612477575b156123cd576121d6906121d060208601611e4d565b846136e3565b60a083013591612206837f00000000000000000000000000000000000000000000000000000000000000006137e0565b5f8061221186611e4d565b8561221f60408901896125da565b9190826040519384928337810185815203925af161223b611fcf565b901561238b575060206122a66001600160a01b039261225b838801611e4d565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116602482015293849283919082906044820190565b0392165afa9081156104cd575f91612359575b508061232e575060606001600160a01b03807fe4e0270eceac2d839d8c05a68fea821be8b4ce569bcb11171a7b536077776e53931693845f52600c6020525f604081205561230686611e4d565b906080612314858901611e4d565b9784604051991689520135602088015260408701521693a3565b7f3ebc33f3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b90506020813d602011612383575b8161237460209383611898565b810103126102e257515f6122b9565b3d9150612367565b6123c9906040519182917ffc1dfe57000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b0390fd5b6020612428916123de828701611e4d565b60405193849283927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b0388165af180156104cd57612448575b506121d6565b6124699060203d602011612470575b6124618183611898565b8101906125c2565b505f612442565b503d612457565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001600160a01b038416146121bb565b7fb5b3cdba000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50805f52600860205260ff60405f2054166121ab565b7fd2b97d40000000000000000000000000000000000000000000000000000000005f5260045ffd5b6001600160a01b03907f2eec4899000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506001600160a01b0381165f52600660205260ff60405f20541661214d565b909350610120919250015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b908160209103126102e2575180151581036102e25790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102e2570180359067ffffffffffffffff82116102e2576020019181360383136102e257565b91909181516fffffffffffffffffffffffffffffffff6080820151164210156126c4575061265883611e4d565b60ff6004541680156126a5575b15611d545750335f52600760205260ff60405f20541615611d28576001600160a01b0361269583611fc095612ca9565b604085015216602083015261339e565b506001600160a01b0381165f52600560205260ff60405f205416612665565b61012091929350015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b81516fffffffffffffffffffffffffffffffff6080820151164210156120b7575090335f52600760205260ff60405f20541615611d28576bffffffffffffffffffffffff6040825101511646036127df5760e081510151156127b7576001600160a01b0360e082510151163b1561278f57611fc091613893565b7fd36e7aa3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f2f345f89000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f804f2b19000000000000000000000000000000000000000000000000000000005f524660045260245ffd5b1561281557505050565b6001600160a01b03907fef832a15000000000000000000000000000000000000000000000000000000005f521660045260245260445260645ffd5b91909181516fffffffffffffffffffffffffffffffff6080820151164210156126c45750335f52600760205260ff60405f20541615611d28576001600160a01b0361289e83611fc095612ca9565b6040850152166020830152613893565b6001600160a01b035f541633036128c157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b906129536080601f92601f196040519485926001600160a01b036020850198168852604080850152806060850152805f868601375f858286010152011681010301601f198101835282611898565b51902090565b91908110156129695760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0390921660248301526044820192909252611fc0916129f282606481015b03601f198101845283611898565b61434b565b60405160208101916020835281815160606040830152805160a0830152602081015160c08301526bffffffffffffffffffffffff60408201511660e08301526fffffffffffffffffffffffffffffffff6060820151166101008301526fffffffffffffffffffffffffffffffff608082015116610120830152612a8a60a0820151610140808501526101e0840190612c84565b9060c0810151917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6084820301610160850152602080845192838152019301905f5b818110612b2c57505050612953936101208260e0604094015161018087015263ffffffff610100820151166101a087015201516101c08501526001600160a01b0360208201511660608501520151608083015203601f198101835282611898565b825180516001600160a01b039081168752602091820151168187015288965060409095019490920191600101612acb565b81810292918115918404141715611c0c57565b6001600160a01b036101208251015116906040810191825160035461271003906127108211611c0c57612710612bab602093612bb493612b5d565b04809551611fc2565b9201916001600160a01b038351165f526009602052612bd860405f20918254611bff565b90556001600160a01b038251166001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681145f14612c6c57505f808080866001600160a01b03955af191612c31611fcf565b5051169015612c3e575050565b7f9412802d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b611fc0939250612996565b3580151581036102e25790565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b919060208101519060406001600160a01b035f93169101519160608501926001600160a01b03612cd885611e4d565b7f000000000000000000000000000000000000000000000000000000000000000095916001600160a01b038716911681036132b35747925b612d1f60c08a013580986137e0565b60a0890196612d2d88612c77565b15613189576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680880361315d57803b156102e2575f80916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528860048401525af180156104cd57613145575b508591612dc38392612dbd8d611e4d565b92611bff565b612dd060408d018d6125da565b9190826040519384928337810185815203925af1612dec611fcf565b905b1561310757506001600160a01b03612e0583611e4d565b160361307a5750612e169047611fc2565b946001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b1561306b576040517fd0e30db000000000000000000000000000000000000000000000000000000000815283816004818b865af1801561306f57908491613056575b5050935b6080820135871061302a57612e9d90612c77565b15612eaa575b5050509190565b602001612f036020612ebb83611e4d565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116602482015291829081906044820190565b0381875afa90811561301f578391612fed575b5015612ea357612f2590611e4d565b90612f8357612f7b916001600160a01b03604051927f095ea7b30000000000000000000000000000000000000000000000000000000060208501521660248301525f6044830152604482526129f2606483611898565b5f8080612ea3565b608460405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152fd5b90506020813d602011613017575b8161300860209383611898565b810103126102e257515f612f16565b3d9150612ffb565b6040513d85823e3d90fd5b602483887fce1eb50c000000000000000000000000000000000000000000000000000000008252600452fd5b8161306091611898565b61306b57825f612e85565b8280fd5b6040513d86823e3d90fd5b9590602460206001600160a01b036130918a611e4d565b16604051928380926370a0823160e01b82523060048301525afa90811561306f5784916130d3575b506130cd916130c791611fc2565b96611e4d565b93612e89565b90506020813d6020116130ff575b816130ee60209383611898565b810103126102e257516130cd6130b9565b3d91506130e1565b6123c9906040519182917fe6bec6e0000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b612dc39296505f61315591611898565b5f9591612dac565b877f663d459f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b896001461480613281575b156131eb57906131b25f936131ac6020869501611e4d565b8a6136e3565b6131bb8b611e4d565b906131c960408d018d6125da565b9190826040519384928337810185815203925af16131e5611fcf565b90612dee565b613246926131fc6020809301611e4d565b60405194859283927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f8b5af19081156104cd575f928392613262575b506131b2565b61327a9060203d602011612470576124618183611898565b505f61325c565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168814613194565b602460206001600160a01b036132c885611e4d565b16604051928380926370a0823160e01b82523060048301525afa9081156104cd575f916132f7575b5092612d10565b90506020813d602011613321575b8161331260209383611898565b810103126102e257515f6132f0565b3d9150613305565b9091926001600160a01b03611fc09481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526129f2608483611898565b63ffffffff60649116029063ffffffff8216918203611c0c57565b906020810151916001600160a01b035f9316916040810151918151926fffffffffffffffffffffffffffffffff60608501511680948282105f1461366457506133e691611fc2565b845f5260096020526133fd60405f20918254611bff565b90555b81516001600160a01b0360e08160208401511692015116906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681145f146135b457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316908582146134a957602487877fea433927000000000000000000000000000000000000000000000000000000008252600452fd5b90809293949695503b156102e2575f80926024604051809581937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528b60048401525af19182156104cd57869261359d575b508480809381935af161350d611fcf565b901561355f575060e07f7d46e6295053455362878a8dfb73723a66a3a917f58b471577319bdfd58ce01d926001600160a01b036020935b1694858152600c8452604081205551015193604051908152a3565b6123c9906040519182917f91fab87c000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b6135ab919295505f90611898565b5f93905f6134fc565b94969593948714806135ec57877fea433927000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b96909192939495965f1461363957926001600160a01b036020936136348860e0957f7d46e6295053455362878a8dfb73723a66a3a917f58b471577319bdfd58ce01d98612996565b613544565b7fea433927000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612710915061367e63ffffffff6101008193015116613383565b160460010180600111611c0c576136959082612b5d565b84116136b3576136a86136ae9185611fc2565b856137e0565b613400565b83907f972704e5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b91909181158015613747575b15612f83576040517f095ea7b30000000000000000000000000000000000000000000000000000000060208201526001600160a01b0390931660248401526044830191909152611fc091906129f282606481016129e4565b506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384166024820152602081806044810103816001600160a01b0386165afa9081156104cd575f916137ae575b50156136ef565b90506020813d6020116137d8575b816137c960209383611898565b810103126102e257515f6137a7565b3d91506137bc565b816137e9575050565b6001600160a01b031690815f52600960205260405f205481811061384d575060207f4b56ac9b13bbfdfc4a10b645235ab5e52a0c037b52077392b124c2f9aedff47a91835f526009825260405f20613842828254611fc2565b9055604051908152a2565b917f6a40ad7e000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b80518210156129695760209160051b010190565b909160e083510151906001600160a01b035f9216805f52600b60205260ff60405f20541615614320576001600160a01b03602086015116926040860151936060875101945f6fffffffffffffffffffffffffffffffff8751169652858181105f1461429e5761390191611fc2565b815f52600960205261391860405f20918254611bff565b90559492945b60c0875101515194601f1961394b61393588611921565b97613943604051998a611898565b808952611921565b013660208801377f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316945f5b60c08a5101518051821015613a4c5790876001600160a01b036139a3838e9561387f565b515116036139c25760019150476139ba828b61387f565b525b0161397f565b60206001600160a01b036139dd8360c060249651015161387f565b515116604051938480926370a0823160e01b82523060048301525afa80156104cd575f90613a1a575b60019250613a14828b61387f565b526139bc565b506020823d8211613a44575b81613a3360209383611898565b810103126102e25760019151613a06565b3d9150613a26565b50509196909593979492976001600160a01b03602087510151168481145f14613de757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316888114613acd5760248a8a7f1de76dca000000000000000000000000000000000000000000000000000000008252600452fd5b809192939495969798503b156102e2575f80916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528d60048401525af180156104cd57613dd2575b5087809160a0885101519089602083519301915af1613b3c611fcf565b9015613d945750865b60c0865101518051821015613d43576001600160a01b03613b6783879361387f565b51511603613bea5787613b8547613b7e848961387f565b5190611fc2565b8015888115613b9d575b505050506001905b01613b45565b839283926001600160a01b036020613bbb8960c0889751015161387f565b51015116908390613be1575bf115613bd657875f8088613b8f565b6040513d89823e3d90fd5b506108fc613bc7565b602460206001600160a01b03613c058460c08b51015161387f565b515116604051928380926370a0823160e01b82523060048301525afa8015613d05578990613d10575b613c3d9150613b7e838861387f565b9081613c4d575b60019150613b97565b6020613cce92886001600160a01b0383613c7e8660c084613c7283838951015161387f565b5151169551015161387f565b510151168c6040518097819582947fa9059cbb00000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1918215613d0557600192613ce7575b50613c44565b613cfe9060203d8111612470576124618183611898565b505f613ce1565b6040513d8b823e3d90fd5b506020813d8211613d3b575b81613d2960209383611898565b810103126102e257613c3d9051613c2e565b3d9150613d1c565b505095937f6393f99ea85268618b19edd8cc4121c97e155cffde3512fe94fe7b3add9864e49350602092506001600160a01b0360e0921694858152600c8452604081205551015193604051908152a3565b6123c9906040519182917f3d6fd7d4000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b613ddf9198505f90611898565b5f965f613b1f565b959695939493881480613e2057887f1de76dca000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b15614272576001461480614240575b156141ca57613e3f86828a6136e3565b5f8060a08951015160208151910182855af1613e59611fcf565b9015613d9457506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039190911660248201526020816044818b5afa9081156104cd575f91614198575b508061416d57505f5b60c087510151805182101561412e576001600160a01b03613edf83889361387f565b51511603613fb857613ef547613b7e838761387f565b866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168a1480613f96575b613f87575b508015888115613f45575b5050506001905b01613ebd565b5f809381936001600160a01b036020613f648960c0879851015161387f565b51015116908390613f7e575bf1156104cd575f8088613f38565b506108fc613f70565b613f9091611bff565b86613f2d565b50866001600160a01b03613faf8560c08d51015161387f565b51511614613f28565b602460206001600160a01b03613fd38460c08c51015161387f565b515116604051928380926370a0823160e01b82523060048301525afa80156104cd575f906140fb575b61400b9150613b7e838761387f565b90866001600160a01b036140248360c08c51015161387f565b5151168a146140ea575b508161403e575b60019150613f3f565b60206140b392896001600160a01b03836140638660c084613c7283838951015161387f565b510151165f6040518097819582947fa9059cbb00000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af19182156104cd576001926140cc575b50614035565b6140e39060203d8111612470576124618183611898565b505f6140c6565b6140f49192611bff565b908661402e565b506020813d8211614126575b8161411460209383611898565b810103126102e25761400b9051613ffc565b3d9150614107565b50509694907f6393f99ea85268618b19edd8cc4121c97e155cffde3512fe94fe7b3add9864e49496506020935060e092506001600160a01b0390613544565b7f115f1a0e000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b90506020813d6020116141c2575b816141b360209383611898565b810103126102e257515f613eb4565b3d91506141a6565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018790526020816044815f8d5af180156104cd57614221575b50613e3f565b6142399060203d602011612470576124618183611898565b505f61421b565b506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168814613e2f565b877fdd4a79bb000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5061271063ffffffff6142b8816101008c51015116613383565b160460010180600111611c0c576142cf9082612b5d565b86116142f0576142e26142e89187611fc2565b826137e0565b94929461391e565b85907f972704e5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f17bceb78000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906001600160a01b036143ac92165f806040519361436a604086611898565b602085527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602086015260208151910182855af16143a6611fcf565b91614446565b805190811591821561442c575b5050156143c257565b608460405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b61443f92506020809183010191016125c2565b5f806143b9565b919290156144a7575081511561445a575090565b3b156144635790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156144ba5750805190602001fd5b6123c99060405191829162461bcd60e51b8352602060048401526024830190612c8456fea2646970667358221220f13d9c50ae4423701377a013332d2cb38971254ae5f8818dcf7fc9f15d1b582264736f6c634300081c0033000000000000000000000000eda8dec60b6c2055b61939dda41e9173bab372b20000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c806307b18bde146117d95780630b3c2411146116b9578063150fea09146116985780631593dee1146116585780631b3f8c5e1461161557806320c0953f146115e65780632680a404146115a957806327b8d9421461156a5780632bbca1571461154d5780632eab14551461143857806331f7d964146113f5578063377316af1461135e5780633b2d7fd614611321578063452a932014610bf15780634d7d9c01146112e85780634ea0e5a2146112ab57806350c56ca6146111bb578063558a729714611164578063580de174146111265780636067570414611021578063715018a614610fe157806377b330c914610f9e57806379ba509714610e925780637daa141b14610deb5780638196e98e14610dce5780638922197d14610d1757806389a9453a14610c755780638a7c349c14610c385780638c45433414610c165780638da5cb5b14610bf15780638f0ad13c14610bb25780639391d03214610b1057806394430fa514610acd5780639e59483d14610a2b578063a07aea1c14610987578063a3c6482c1461094f578063b75b6090146108fa578063c10753291461079a578063c5f3f46314610748578063ca7b3d3b1461071e578063cee5940e146105ed578063d365a3771461054b578063d966b29e1461050e578063d9f66db114610481578063e30c39781461045b578063e34accc2146103f4578063f2fde38b1461036f578063f56c4892146102e65763fa40ce340361000e57346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761026a90369060040161183d565b6102726128ae565b5f5b81811061027d57005b806001600160a01b0361029b6102966001948688612959565b611e4d565b16805f52600b60205260405f208360ff198254161790557f6163be4e9de13d310048eae21c71c771155520680b869551fc3e90ca3b52c13a6020604051858152a201610274565b5f80fd5b346102e2576102f436611b59565b906001600160a01b03831692835f52600c60205260405f2054610316846129f7565b03610325576100189350612850565b5050815f52600c60205261033d60405f2054916129f7565b917f1d03b3e8000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b346102e25760206003193601126102e2576001600160a01b03610390611827565b6103986128ae565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001556001600160a01b035f54167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346102e25760206003193601126102e2576001600160a01b03610415611827565b165f52600c60205260405f2054801561043357602090604051908152f35b7f5dcaf2d7000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e2575f6003193601126102e25760206001600160a01b0360015416604051908152f35b346102e25760206003193601126102e25761049a611827565b6001600160a01b035f541633036104e2575f808080934790829082156104d8575b6001600160a01b031690f1156104cd57005b6040513d5f823e3d90fd5b6108fc91506104bb565b7fa252c151000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b346102e25760206003193601126102e2576001600160a01b0361052f611827565b165f526006602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761057c90369060040161183d565b6105846128ae565b5f5b81811061058f57005b806001600160a01b036105a86102966001948688612959565b16805f52600760205260405f2060ff1981541690557f3ce179bb425f4afab8ab551b382acfa5d68573aa6363cad06bad95b15bc1330b60206040515f8152a201610586565b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761061e90369060040161183d565b906106276128ae565b6106313633612905565b90815f52600a60205260405f20549283155f14610669575050905061065860025442611bff565b905f52600a60205260405f20555f80f35b8342105f146106a25750507f46f71e7f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919092505f52600a6020525f60408120555f5b8181106106be57005b806001600160a01b036106d76102966001948688612959565b16805f52600560205260405f208360ff198254161790557f52187c41547927b6e1bcf48e821c5fd0c6b9918398fd10d770e5b9580b44c0696020604051858152a2016106b5565b346102e25760206003193601126102e2576004355f52600a602052602060405f2054604051908152f35b346102e25760206003193601126102e2576004356107646128ae565b612710811161077257600355005b7f7ba842b1000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e25760406003193601126102e2576107b3611827565b6024356107be6128ae565b6001600160a01b0382166001600160a01b037f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1681145f1461086b575f826108268295839561081c8596479087526009602052604087205490611fc2565b918183101561280b565b6001600160a01b038254165af161083b611fcf565b501561084357005b7f3022f2e4000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040516370a0823160e01b8152306004820152602081602481855afa9081156104cd575f916108c6575b50610018938361081c6108b593855f52600960205260405f205490611fc2565b6001600160a01b035f541690612996565b90506020813d6020116108f2575b816108e160209383611898565b810103126102e25751610018610895565b3d91506108d4565b346102e25761090836611bbf565b6001600160a01b03821691825f52600c60205260405f2054610929836129f7565b03610938576100189250612715565b50815f52600c60205261033d60405f2054916129f7565b346102e25760206003193601126102e2576001600160a01b03610970611827565b165f526009602052602060405f2054604051908152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e2576109b890369060040161183d565b6109c06128ae565b5f5b8181106109cb57005b806001600160a01b036109e46102966001948688612959565b16805f52600760205260405f208360ff198254161790557f3ce179bb425f4afab8ab551b382acfa5d68573aa6363cad06bad95b15bc1330b6020604051858152a2016109c2565b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257610a5c90369060040161183d565b610a646128ae565b5f5b818110610a6f57005b806001600160a01b03610a886102966001948688612959565b16805f52600660205260405f2060ff1981541690557ff007979304ad19c08251c22274ee0b988c783a3f565cc53ad61a96f83dcf02cd60206040515f8152a201610a66565b346102e2575f6003193601126102e25760206040516001600160a01b037f0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789168152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257610b4190369060040161183d565b610b496128ae565b5f5b818110610b5457005b806001600160a01b03610b6d6102966001948688612959565b16805f52600560205260405f2060ff1981541690557f52187c41547927b6e1bcf48e821c5fd0c6b9918398fd10d770e5b9580b44c06960206040515f8152a201610b4b565b346102e257610bc036611b59565b906001600160a01b03831692835f52600c60205260405f2054610be2846129f7565b0361032557610018935061262b565b346102e2575f6003193601126102e25760206001600160a01b035f5416604051908152f35b346102e2575f6003193601126102e257602060ff600454166040519015158152f35b346102e25760206003193601126102e2576001600160a01b03610c59611827565b165f52600b602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257610ca690369060040161183d565b610cae6128ae565b5f5b818110610cb957005b806001600160a01b03610cd26102966001948688612959565b16805f52600b60205260405f2060ff1981541690557f6163be4e9de13d310048eae21c71c771155520680b869551fc3e90ca3b52c13a60206040515f8152a201610cb0565b346102e25760606003193601126102e257610d30611827565b6024359067ffffffffffffffff82116102e25760c060031983360301126102e2576044359067ffffffffffffffff82116102e25760606003198360040193360301126102e257610d803683611939565b926001600160a01b03821693845f52600c60205260405f2054610da2826129f7565b03610db65750610018935060040190612104565b8490815f52600c60205261033d60405f2054916129f7565b346102e2575f6003193601126102e2576020600354604051908152f35b346102e25760406003193601126102e257610e04611827565b610e0c611882565b906001600160a01b035f541633036104e257604051916370a0823160e01b83523060048401526020836024816001600160a01b0386165afa9182156104cd575f92610e5c575b6100189350612996565b91506020833d602011610e8a575b81610e7760209383611898565b810103126102e257610018925191610e52565b3d9150610e6a565b346102e2575f6003193601126102e257600154336001600160a01b03821603610f34577fffffffffffffffffffffffff0000000000000000000000000000000000000000166001555f54337fffffffffffffffffffffffff00000000000000000000000000000000000000008216175f556001600160a01b033391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b608460405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152fd5b346102e2575f6003193601126102e25760206040516001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168152f35b346102e2575f6003193601126102e257610ff96128ae565b7f89051165000000000000000000000000000000000000000000000000000000005f5260045ffd5b60406003193601126102e257611035611827565b6001600160a01b036024359116906001600160a01b037f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1682145f146110f1578034036110c25760207fb742da464f5cf7517f0a451e9feeb72d5645001a500605bccb7f972001ea9633915b835f526009825260405f206110b7828254611bff565b9055604051908152a2005b7f3ca29a83000000000000000000000000000000000000000000000000000000005f526004523460245260445ffd5b6020816111217fb742da464f5cf7517f0a451e9feeb72d5645001a500605bccb7f972001ea963393303387613329565b6110a1565b346102e25761113436611bbf565b6001600160a01b03821691825f52600c60205260405f2054611155836129f7565b03610938576100189250611ffe565b346102e25760406003193601126102e25761117d611827565b6024359081151582036102e2576001600160a01b039061119b6128ae565b165f52600760205260405f209060ff60ff19835416911515161790555f80f35b346102e25760406003193601126102e2576111d4611827565b6001600160a01b03602435916111e86128ae565b1690815f52600960205260405f20611201828254611fc2565b90557f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03168203611277575f80808084335af1611243611fcf565b50156108435760207f3bde90ddec8b620631bf91ff34269455f889277ab58bbde3b5d94c4a0428e25c915b604051908152a2005b6020816112a67f3bde90ddec8b620631bf91ff34269455f889277ab58bbde3b5d94c4a0428e25c933386612996565b61126e565b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e257606060031982360301126102e25761001890600401611e94565b346102e25760206003193601126102e2576004358015158091036102e25761130e6128ae565b60ff60ff19600454169116176004555f80f35b346102e25760206003193601126102e2576001600160a01b03611342611827565b165f526005602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761138f90369060040161183d565b6113976128ae565b5f5b8181106113a257005b806113b06001928486612959565b35805f52600860205260405f2060ff1981541690557fd68bd2e440c0eb451dd2f1fa546d640c7e228770733d017d92fa648d54b311f660206040515f8152a201611399565b346102e2575f6003193601126102e25760206040516001600160a01b037f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee168152f35b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e25761146990369060040161183d565b906114726128ae565b61147c3633612905565b90815f52600a60205260405f20549283155f146114a3575050905061065860025442611bff565b8342105f146114dc5750507f46f71e7f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919092505f52600a6020525f60408120555f5b8181106114f857005b806115066001928486612959565b35805f52600860205260405f208360ff198254161790557fd68bd2e440c0eb451dd2f1fa546d640c7e228770733d017d92fa648d54b311f66020604051858152a2016114ef565b346102e2575f6003193601126102e2576020600254604051908152f35b346102e25761157836611b59565b906001600160a01b03831692835f52600c60205260405f205461159a846129f7565b03610325576100189350611c39565b346102e25760206003193601126102e2576001600160a01b036115ca611827565b165f526007602052602060ff60405f2054166040519015158152f35b346102e25760206003193601126102e2576004355f526008602052602060ff60405f2054166040519015158152f35b346102e2575f6003193601126102e25760206040516001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152f35b346102e25760606003193601126102e257611671611827565b611679611882565b906001600160a01b035f541633036104e2576100189160443591612996565b346102e25760206003193601126102e2576116b16128ae565b600435600255005b346102e25760206003193601126102e25760043567ffffffffffffffff81116102e2576116ea90369060040161183d565b906116f36128ae565b6116fd3633612905565b90815f52600a60205260405f20549283155f14611724575050905061065860025442611bff565b8342105f1461175d5750507f46f71e7f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b919092505f52600a6020525f60408120555f5b81811061177957005b806001600160a01b036117926102966001948688612959565b16805f52600660205260405f208360ff198254161790557ff007979304ad19c08251c22274ee0b988c783a3f565cc53ad61a96f83dcf02cd6020604051858152a201611770565b346102e25760406003193601126102e2576117f2611827565b602435906001600160a01b035f541633036104e2575f8080938193829082156104d8576001600160a01b031690f1156104cd57005b600435906001600160a01b03821682036102e257565b9181601f840112156102e25782359167ffffffffffffffff83116102e2576020808501948460051b0101116102e257565b35906001600160a01b03821682036102e257565b602435906001600160a01b03821682036102e257565b90601f601f19910116810190811067ffffffffffffffff8211176118bb57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b35906fffffffffffffffffffffffffffffffff821682036102e257565b67ffffffffffffffff81116118bb57601f01601f191660200190565b67ffffffffffffffff81116118bb5760051b60200190565b91906060838203126102e257604051906060820182811067ffffffffffffffff8211176118bb576040528193803567ffffffffffffffff81116102e257810190610140828403126102e25760405192610140840184811067ffffffffffffffff8211176118bb57604052823584526020830135602085015260408301356bffffffffffffffffffffffff811681036102e25760408501526119dc606084016118e8565b60608501526119ed608084016118e8565b608085015260a083013567ffffffffffffffff81116102e257830181601f820112156102e2578035611a1e81611905565b91611a2c6040519384611898565b81835283602083830101116102e257815f926020809301838601378301015260a085015260c083013567ffffffffffffffff81116102e257830181601f820112156102e257803590611a7d82611921565b92611a8b6040519485611898565b82845260208085019360061b830101918183116102e257602001925b828410611b06575050505060c084015260e082013560e08401526101008201359263ffffffff841684036102e25761012060409493859461010084015201356101208201528452611afa6020820161186e565b60208501520135910152565b6040848303126102e25760405190604082019082821067ffffffffffffffff8311176118bb576040926020928452611b3d8761186e565b8152611b4a83880161186e565b83820152815201930192611aa7565b60606003198201126102e2576004356001600160a01b03811681036102e2579160243567ffffffffffffffff81116102e25760e060031982850301126102e257600401916044359067ffffffffffffffff82116102e257611bbc91600401611939565b90565b9060406003198301126102e2576004356001600160a01b03811681036102e257916024359067ffffffffffffffff82116102e257611bbc91600401611939565b91908201809211611c0c57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b909180516fffffffffffffffffffffffffffffffff608082015116421015611da85750611c6583611e4d565b60ff600454168015611d89575b15611d545750335f52600760205260ff60405f20541615611d28576001600160a01b0381611d2382611cfa8782611ccd7f5a417e3ceaff68360f7300df6686a9d417ae12328724de7bc2fd6c012a2ffa8598611ce59b612ca9565b9a9096826020820198604083019d8e521688526129f7565b981697885f52600c60205260405f2055611e4d565b9251169551604051938493169683602090939291936001600160a01b0360408201951681520152565b0390a3565b7f6a0576da000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b6001600160a01b03907fb25f49d4000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506001600160a01b0381165f52600560205260ff60405f205416611c72565b610120919350015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b60208181015160409283015183516001600160a01b0390921682529181019190915290819081015b0390a2565b7fc56873ba000000000000000000000000000000000000000000000000000000005f5260045ffd5b356001600160a01b03811681036102e25790565b9035907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1813603018212156102e2570190565b6080611ea08280611e61565b01356fffffffffffffffffffffffffffffffff81168091036102e257421015611f54577f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a7611e20611f2f60208401611f1d611f18611efd83611e4d565b96611f116040820135809930903390613329565b3690611939565b6129f7565b335f52600c60205260405f2055611e4d565b92604051918291339583602090939291936001600160a01b0360408201951681520152565b611f72611f6360208301611e4d565b60408301359030903390613329565b610120611f7f8280611e61565b0135611fad5750337ff675619421689a1f9bfda05f0997e733648107b14bf1eae11ab626e06e3d73b85f80a2565b611fbb611fc0913690611939565b612b70565b565b91908203918211611c0c57565b3d15611ff9573d90611fe082611905565b91611fee6040519384611898565b82523d5f602084013e565b606090565b81516fffffffffffffffffffffffffffffffff6080820151164210156120b7575090335f52600760205260ff60405f20541615611d28576bffffffffffffffffffffffff60408251015116460361208b5760e0815101511561206357611fc09161339e565b7f1fb2fee6000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f9930d34e000000000000000000000000000000000000000000000000000000005f524660045260245ffd5b610120015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b9190916121113683611939565b80516fffffffffffffffffffffffffffffffff60808201511642101561256f57505061213c83611e4d565b60045460ff16801593918185612550575b1561251b5750335f52600760205260ff60405f20541615611d285761217460208301611e4d565b936040612185818501359480611e61565b0135916bffffffffffffffffffffffff83168093036102e2574683146124f357906124dd575b156124b257506001461480612477575b156123cd576121d6906121d060208601611e4d565b846136e3565b60a083013591612206837f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6137e0565b5f8061221186611e4d565b8561221f60408901896125da565b9190826040519384928337810185815203925af161223b611fcf565b901561238b575060206122a66001600160a01b039261225b838801611e4d565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116602482015293849283919082906044820190565b0392165afa9081156104cd575f91612359575b508061232e575060606001600160a01b03807fe4e0270eceac2d839d8c05a68fea821be8b4ce569bcb11171a7b536077776e53931693845f52600c6020525f604081205561230686611e4d565b906080612314858901611e4d565b9784604051991689520135602088015260408701521693a3565b7f3ebc33f3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b90506020813d602011612383575b8161237460209383611898565b810103126102e257515f6122b9565b3d9150612367565b6123c9906040519182917ffc1dfe57000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b0390fd5b6020612428916123de828701611e4d565b60405193849283927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f6001600160a01b0388165af180156104cd57612448575b506121d6565b6124699060203d602011612470575b6124618183611898565b8101906125c2565b505f612442565b503d612457565b506001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7166001600160a01b038416146121bb565b7fb5b3cdba000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50805f52600860205260ff60405f2054166121ab565b7fd2b97d40000000000000000000000000000000000000000000000000000000005f5260045ffd5b6001600160a01b03907f2eec4899000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506001600160a01b0381165f52600660205260ff60405f20541661214d565b909350610120919250015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b908160209103126102e2575180151581036102e25790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102e2570180359067ffffffffffffffff82116102e2576020019181360383136102e257565b91909181516fffffffffffffffffffffffffffffffff6080820151164210156126c4575061265883611e4d565b60ff6004541680156126a5575b15611d545750335f52600760205260ff60405f20541615611d28576001600160a01b0361269583611fc095612ca9565b604085015216602083015261339e565b506001600160a01b0381165f52600560205260ff60405f205416612665565b61012091929350015115611e25576001600160a01b037fea43f83fd01765d05c283667d4ee82c1c391cf2884434db95c56d2c2c4cc9a08911691825f52600c6020525f6040812055611df881612b70565b81516fffffffffffffffffffffffffffffffff6080820151164210156120b7575090335f52600760205260ff60405f20541615611d28576bffffffffffffffffffffffff6040825101511646036127df5760e081510151156127b7576001600160a01b0360e082510151163b1561278f57611fc091613893565b7fd36e7aa3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f2f345f89000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f804f2b19000000000000000000000000000000000000000000000000000000005f524660045260245ffd5b1561281557505050565b6001600160a01b03907fef832a15000000000000000000000000000000000000000000000000000000005f521660045260245260445260645ffd5b91909181516fffffffffffffffffffffffffffffffff6080820151164210156126c45750335f52600760205260ff60405f20541615611d28576001600160a01b0361289e83611fc095612ca9565b6040850152166020830152613893565b6001600160a01b035f541633036128c157565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b906129536080601f92601f196040519485926001600160a01b036020850198168852604080850152806060850152805f868601375f858286010152011681010301601f198101835282611898565b51902090565b91908110156129695760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0390921660248301526044820192909252611fc0916129f282606481015b03601f198101845283611898565b61434b565b60405160208101916020835281815160606040830152805160a0830152602081015160c08301526bffffffffffffffffffffffff60408201511660e08301526fffffffffffffffffffffffffffffffff6060820151166101008301526fffffffffffffffffffffffffffffffff608082015116610120830152612a8a60a0820151610140808501526101e0840190612c84565b9060c0810151917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6084820301610160850152602080845192838152019301905f5b818110612b2c57505050612953936101208260e0604094015161018087015263ffffffff610100820151166101a087015201516101c08501526001600160a01b0360208201511660608501520151608083015203601f198101835282611898565b825180516001600160a01b039081168752602091820151168187015288965060409095019490920191600101612acb565b81810292918115918404141715611c0c57565b6001600160a01b036101208251015116906040810191825160035461271003906127108211611c0c57612710612bab602093612bb493612b5d565b04809551611fc2565b9201916001600160a01b038351165f526009602052612bd860405f20918254611bff565b90556001600160a01b038251166001600160a01b037f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1681145f14612c6c57505f808080866001600160a01b03955af191612c31611fcf565b5051169015612c3e575050565b7f9412802d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b611fc0939250612996565b3580151581036102e25790565b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b919060208101519060406001600160a01b035f93169101519160608501926001600160a01b03612cd885611e4d565b7f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee95916001600160a01b038716911681036132b35747925b612d1f60c08a013580986137e0565b60a0890196612d2d88612c77565b15613189576001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21680880361315d57803b156102e2575f80916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528860048401525af180156104cd57613145575b508591612dc38392612dbd8d611e4d565b92611bff565b612dd060408d018d6125da565b9190826040519384928337810185815203925af1612dec611fcf565b905b1561310757506001600160a01b03612e0583611e4d565b160361307a5750612e169047611fc2565b946001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216803b1561306b576040517fd0e30db000000000000000000000000000000000000000000000000000000000815283816004818b865af1801561306f57908491613056575b5050935b6080820135871061302a57612e9d90612c77565b15612eaa575b5050509190565b602001612f036020612ebb83611e4d565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116602482015291829081906044820190565b0381875afa90811561301f578391612fed575b5015612ea357612f2590611e4d565b90612f8357612f7b916001600160a01b03604051927f095ea7b30000000000000000000000000000000000000000000000000000000060208501521660248301525f6044830152604482526129f2606483611898565b5f8080612ea3565b608460405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152fd5b90506020813d602011613017575b8161300860209383611898565b810103126102e257515f612f16565b3d9150612ffb565b6040513d85823e3d90fd5b602483887fce1eb50c000000000000000000000000000000000000000000000000000000008252600452fd5b8161306091611898565b61306b57825f612e85565b8280fd5b6040513d86823e3d90fd5b9590602460206001600160a01b036130918a611e4d565b16604051928380926370a0823160e01b82523060048301525afa90811561306f5784916130d3575b506130cd916130c791611fc2565b96611e4d565b93612e89565b90506020813d6020116130ff575b816130ee60209383611898565b810103126102e257516130cd6130b9565b3d91506130e1565b6123c9906040519182917fe6bec6e0000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b612dc39296505f61315591611898565b5f9591612dac565b877f663d459f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b896001461480613281575b156131eb57906131b25f936131ac6020869501611e4d565b8a6136e3565b6131bb8b611e4d565b906131c960408d018d6125da565b9190826040519384928337810185815203925af16131e5611fcf565b90612dee565b613246926131fc6020809301611e4d565b60405194859283927f095ea7b300000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03815f8b5af19081156104cd575f928392613262575b506131b2565b61327a9060203d602011612470576124618183611898565b505f61325c565b506001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168814613194565b602460206001600160a01b036132c885611e4d565b16604051928380926370a0823160e01b82523060048301525afa9081156104cd575f916132f7575b5092612d10565b90506020813d602011613321575b8161331260209383611898565b810103126102e257515f6132f0565b3d9150613305565b9091926001600160a01b03611fc09481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526129f2608483611898565b63ffffffff60649116029063ffffffff8216918203611c0c57565b906020810151916001600160a01b035f9316916040810151918151926fffffffffffffffffffffffffffffffff60608501511680948282105f1461366457506133e691611fc2565b845f5260096020526133fd60405f20918254611bff565b90555b81516001600160a01b0360e08160208401511692015116906001600160a01b037f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1681145f146135b457507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316908582146134a957602487877fea433927000000000000000000000000000000000000000000000000000000008252600452fd5b90809293949695503b156102e2575f80926024604051809581937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528b60048401525af19182156104cd57869261359d575b508480809381935af161350d611fcf565b901561355f575060e07f7d46e6295053455362878a8dfb73723a66a3a917f58b471577319bdfd58ce01d926001600160a01b036020935b1694858152600c8452604081205551015193604051908152a3565b6123c9906040519182917f91fab87c000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b6135ab919295505f90611898565b5f93905f6134fc565b94969593948714806135ec57877fea433927000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b96909192939495965f1461363957926001600160a01b036020936136348860e0957f7d46e6295053455362878a8dfb73723a66a3a917f58b471577319bdfd58ce01d98612996565b613544565b7fea433927000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612710915061367e63ffffffff6101008193015116613383565b160460010180600111611c0c576136959082612b5d565b84116136b3576136a86136ae9185611fc2565b856137e0565b613400565b83907f972704e5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b91909181158015613747575b15612f83576040517f095ea7b30000000000000000000000000000000000000000000000000000000060208201526001600160a01b0390931660248401526044830191909152611fc091906129f282606481016129e4565b506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384166024820152602081806044810103816001600160a01b0386165afa9081156104cd575f916137ae575b50156136ef565b90506020813d6020116137d8575b816137c960209383611898565b810103126102e257515f6137a7565b3d91506137bc565b816137e9575050565b6001600160a01b031690815f52600960205260405f205481811061384d575060207f4b56ac9b13bbfdfc4a10b645235ab5e52a0c037b52077392b124c2f9aedff47a91835f526009825260405f20613842828254611fc2565b9055604051908152a2565b917f6a40ad7e000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b80518210156129695760209160051b010190565b909160e083510151906001600160a01b035f9216805f52600b60205260ff60405f20541615614320576001600160a01b03602086015116926040860151936060875101945f6fffffffffffffffffffffffffffffffff8751169652858181105f1461429e5761390191611fc2565b815f52600960205261391860405f20918254611bff565b90559492945b60c0875101515194601f1961394b61393588611921565b97613943604051998a611898565b808952611921565b013660208801377f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0316945f5b60c08a5101518051821015613a4c5790876001600160a01b036139a3838e9561387f565b515116036139c25760019150476139ba828b61387f565b525b0161397f565b60206001600160a01b036139dd8360c060249651015161387f565b515116604051938480926370a0823160e01b82523060048301525afa80156104cd575f90613a1a575b60019250613a14828b61387f565b526139bc565b506020823d8211613a44575b81613a3360209383611898565b810103126102e25760019151613a06565b3d9150613a26565b50509196909593979492976001600160a01b03602087510151168481145f14613de757507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316888114613acd5760248a8a7f1de76dca000000000000000000000000000000000000000000000000000000008252600452fd5b809192939495969798503b156102e2575f80916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528d60048401525af180156104cd57613dd2575b5087809160a0885101519089602083519301915af1613b3c611fcf565b9015613d945750865b60c0865101518051821015613d43576001600160a01b03613b6783879361387f565b51511603613bea5787613b8547613b7e848961387f565b5190611fc2565b8015888115613b9d575b505050506001905b01613b45565b839283926001600160a01b036020613bbb8960c0889751015161387f565b51015116908390613be1575bf115613bd657875f8088613b8f565b6040513d89823e3d90fd5b506108fc613bc7565b602460206001600160a01b03613c058460c08b51015161387f565b515116604051928380926370a0823160e01b82523060048301525afa8015613d05578990613d10575b613c3d9150613b7e838861387f565b9081613c4d575b60019150613b97565b6020613cce92886001600160a01b0383613c7e8660c084613c7283838951015161387f565b5151169551015161387f565b510151168c6040518097819582947fa9059cbb00000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af1918215613d0557600192613ce7575b50613c44565b613cfe9060203d8111612470576124618183611898565b505f613ce1565b6040513d8b823e3d90fd5b506020813d8211613d3b575b81613d2960209383611898565b810103126102e257613c3d9051613c2e565b3d9150613d1c565b505095937f6393f99ea85268618b19edd8cc4121c97e155cffde3512fe94fe7b3add9864e49350602092506001600160a01b0360e0921694858152600c8452604081205551015193604051908152a3565b6123c9906040519182917f3d6fd7d4000000000000000000000000000000000000000000000000000000008352602060048401526024830190612c84565b613ddf9198505f90611898565b5f965f613b1f565b959695939493881480613e2057887f1de76dca000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b15614272576001461480614240575b156141ca57613e3f86828a6136e3565b5f8060a08951015160208151910182855af1613e59611fcf565b9015613d9457506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039190911660248201526020816044818b5afa9081156104cd575f91614198575b508061416d57505f5b60c087510151805182101561412e576001600160a01b03613edf83889361387f565b51511603613fb857613ef547613b7e838761387f565b866001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168a1480613f96575b613f87575b508015888115613f45575b5050506001905b01613ebd565b5f809381936001600160a01b036020613f648960c0879851015161387f565b51015116908390613f7e575bf1156104cd575f8088613f38565b506108fc613f70565b613f9091611bff565b86613f2d565b50866001600160a01b03613faf8560c08d51015161387f565b51511614613f28565b602460206001600160a01b03613fd38460c08c51015161387f565b515116604051928380926370a0823160e01b82523060048301525afa80156104cd575f906140fb575b61400b9150613b7e838761387f565b90866001600160a01b036140248360c08c51015161387f565b5151168a146140ea575b508161403e575b60019150613f3f565b60206140b392896001600160a01b03836140638660c084613c7283838951015161387f565b510151165f6040518097819582947fa9059cbb00000000000000000000000000000000000000000000000000000000845260048401602090939291936001600160a01b0360408201951681520152565b03925af19182156104cd576001926140cc575b50614035565b6140e39060203d8111612470576124618183611898565b505f6140c6565b6140f49192611bff565b908661402e565b506020813d8211614126575b8161411460209383611898565b810103126102e25761400b9051613ffc565b3d9150614107565b50509694907f6393f99ea85268618b19edd8cc4121c97e155cffde3512fe94fe7b3add9864e49496506020935060e092506001600160a01b0390613544565b7f115f1a0e000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b90506020813d6020116141c2575b816141b360209383611898565b810103126102e257515f613eb4565b3d91506141a6565b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018790526020816044815f8d5af180156104cd57614221575b50613e3f565b6142399060203d602011612470576124618183611898565b505f61421b565b506001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168814613e2f565b877fdd4a79bb000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5061271063ffffffff6142b8816101008c51015116613383565b160460010180600111611c0c576142cf9082612b5d565b86116142f0576142e26142e89187611fc2565b826137e0565b94929461391e565b85907f972704e5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f17bceb78000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906001600160a01b036143ac92165f806040519361436a604086611898565b602085527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602086015260208151910182855af16143a6611fcf565b91614446565b805190811591821561442c575b5050156143c257565b608460405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b61443f92506020809183010191016125c2565b5f806143b9565b919290156144a7575081511561445a575090565b3b156144635790565b606460405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156144ba5750805190602001fd5b6123c99060405191829162461bcd60e51b8352602060048401526024830190612c8456fea2646970667358221220f13d9c50ae4423701377a013332d2cb38971254ae5f8818dcf7fc9f15d1b582264736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000eda8dec60b6c2055b61939dda41e9173bab372b20000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : guardian (address): 0xeDa8Dec60B6C2055B61939dDA41E9173Bab372b2
Arg [1] : entryPoint (address): 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
Arg [2] : wrappedNativeToken (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000eda8dec60b6c2055b61939dda41e9173bab372b2
Arg [1] : 0000000000000000000000005ff137d4b0fdcd49dca30c7cf57e578a026d2789
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
Net Worth in USD
$39.38
Net Worth in ETH
0.01991
Token Allocations
USDC
78.67%
WBNB
7.46%
USDT0
4.23%
Others
9.64%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 74.04% | $0.999902 | 29.1635 | $29.16 | |
| ETH | 1.17% | $0.999991 | 0.4623 | $0.4623 | |
| ETH | 0.63% | $2.89 | 0.086 | $0.2484 | |
| BSC | 7.46% | $628.85 | 0.00466978 | $2.94 | |
| BSC | 3.51% | $0.999968 | 1.3819 | $1.38 | |
| BSC | 1.77% | $0.99991 | 0.6957 | $0.6956 | |
| POL | 4.23% | $0.998295 | 1.6691 | $1.67 | |
| POL | 0.37% | $0.098655 | 1.495 | $0.1474 | |
| BASE | 2.60% | $0.999996 | 1.024 | $1.02 | |
| BASE | 1.63% | $0.999922 | 0.6436 | $0.6435 | |
| ARB | 2.32% | $2,258.88 | 0.00040392 | $0.9124 | |
| OP | 0.26% | $1 | 0.1043 | $0.1043 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.