Source Code
Overview
MON Balance
MON Value
$0.00Loading...
Loading
Contract Name:
UnumRouter
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 999999 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "./libraries/ErrorUtils.sol";
import "./Permit2/interfaces/ISignatureTransfer.sol";
/// @title Smart contract that takes fee based on difference of trade `amountOutMin` and `amountOut`
contract UnumRouter is ReentrancyGuardTransient, Ownable2Step {
using SafeERC20 for IERC20;
ISignatureTransfer public immutable permit2;
/// @notice Collected trade data
struct TradeData {
/// Smart contract to call to execute trade
address payable callTarget;
/// Calldata to execute trade with
bytes callData;
/// Custom address to approve tokens IN.
/// May be set as address(0) if token in is native or must be approved to `callTarget`
address approvalAddress;
/// Token IN address. address(0) if token IN is native
IERC20 tokenIn;
/// Amount IN of tokens to take from `msg.sender` and to approve to `approvalAddress`
uint256 amountIn;
/// Address of main receiver of tokens
address payable mainReceiver;
/// Token OUT address. address(0) if token OUT is native
IERC20 tokenOut;
/// Minimum expected amount OUT
uint256 amountOutMin;
/// Address of fee receiver
address payable feeReceiver;
/// Fee share in basis points (5_000 = 50%) of amountOut - amountOutMin difference
uint16 feeShare;
}
/// @notice Collected trade data to be used with permit2 contract
struct Permit2TradeData {
/// Trade data
TradeData tradeData;
/// Permit2 deadline
uint256 deadline;
/// Permit2 nonce
uint256 nonce;
}
event TradeComplete(
address spender,
address mainReceiver,
address tokenIn,
uint256 amountIn,
address tokenOut,
uint256 amountOut,
address feeReceiver,
uint256 feeAmount
);
error BelowAmountOutMin(uint256 received);
error CallFailed(bytes errorMessage);
error InvalidFeeShare();
error InvalidMsgValue();
error NativeTransferFailed(address receiver, bytes errorMessage);
error TokenInHasTransferFee();
error TokenOutHasTransferFee();
error ZeroAddress();
error ZeroBalance();
/// @param _permit2 Permit2 contract address
/// @param initialOwner Initial owner address
constructor(
ISignatureTransfer _permit2,
address initialOwner
) Ownable(initialOwner) {
if (
address(_permit2) == address(0)
|| initialOwner == address(0)
) {
revert ZeroAddress();
}
permit2 = _permit2;
}
receive() external payable {}
// ==================================================================================
// ===================================== PERMIT =====================================
// ==================================================================================
/// @notice Function to execute trade and distribute fees with ERC20Permit token IN
/// @dev Smart contract expects to receive tokensOut after trade
/// @param tradeData Trade data
/// @param deadline Permit deadline
/// @param v Permit {signature.v} value
/// @param r Permit {signature.r} value
/// @param s Permit {signature.s} value
/// @return Amount of tokens OUT received by main receiver
/// @dev If token IN is fee-on-transfer token, specific error will be thrown
/// @dev If token OUT is fee-on-transfer token:
/// - fees will not be collected
/// - calldata will be updated, so that tokens will be sent to `mainReceiver` in the first place
/// @dev Expects tokens IN to be approved to this contract
function executeWithPermit(
TradeData calldata tradeData,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable nonReentrant returns (uint256) {
IERC20Permit(address(tradeData.tokenIn)).permit(
msg.sender,
address(this),
tradeData.amountIn,
deadline,
v,
r,
s
);
_takeTokensIn(tradeData);
return _execute(tradeData);
}
// ===================================================================================
// ===================================== PERMIT2 =====================================
// ===================================================================================
string internal constant PERMIT2_TYPE = string(abi.encodePacked(
"Permit2TradeData witness)",
WITNESS_TYPE,
TOKEN_PERMISSIONS_TYPE,
TRADE_DATA_TYPE
));
bytes internal constant TOKEN_PERMISSIONS_TYPE = abi.encodePacked("TokenPermissions(address token,uint256 amount)");
bytes internal constant WITNESS_TYPE = abi.encodePacked(
"Permit2TradeData(TradeData tradeData,uint256 deadline,uint256 nonce)"
);
bytes32 internal constant WITNESS_TYPE_HASH = keccak256(abi.encodePacked(
WITNESS_TYPE,
TRADE_DATA_TYPE
));
bytes internal constant TRADE_DATA_TYPE = abi.encodePacked(
"TradeData(",
"address callTarget,",
"bytes callData,",
"address approvalAddress,",
"address tokenIn,",
"uint256 amountIn,",
"address mainReceiver,",
"address tokenOut,",
"uint256 amountOutMin,",
"address feeReceiver,"
"uint16 feeShare)"
);
bytes32 internal constant TRADE_DATA_TYPE_HASH = keccak256(TRADE_DATA_TYPE);
/// @notice Function to execute trade and distribute fees with Permit2 contract
/// @dev Smart contract expects to receive tokensOut after trade
/// @param permit2TradeData Permit2 trade data
/// @param userSignature Permit {signature.s} value
/// @return Amount of tokens OUT received by main receiver
/// @dev If token IN is fee-on-transfer token, specific error will be thrown
/// @dev If token OUT is fee-on-transfer token:
/// - fees will not be collected
/// - calldata will be updated, so that tokens will be sent to `mainReceiver` in the first place
/// @dev Expects tokens IN to be approved to this contract
function executeWithPermit2(
Permit2TradeData calldata permit2TradeData,
bytes calldata userSignature
) external payable nonReentrant returns (uint256) {
bytes32 tradeDataHash = keccak256(
abi.encode(
TRADE_DATA_TYPE_HASH,
permit2TradeData.tradeData.callTarget,
keccak256(permit2TradeData.tradeData.callData),
permit2TradeData.tradeData.approvalAddress,
permit2TradeData.tradeData.tokenIn,
permit2TradeData.tradeData.amountIn,
permit2TradeData.tradeData.mainReceiver,
permit2TradeData.tradeData.tokenOut,
permit2TradeData.tradeData.amountOutMin,
permit2TradeData.tradeData.feeReceiver,
permit2TradeData.tradeData.feeShare
)
);
bytes32 permit2TradeDataHash = keccak256(
abi.encode(
WITNESS_TYPE_HASH,
tradeDataHash,
permit2TradeData.deadline,
permit2TradeData.nonce
)
);
permit2.permitWitnessTransferFrom(
ISignatureTransfer.PermitTransferFrom({
permitted: ISignatureTransfer.TokenPermissions(
{token: address(permit2TradeData.tradeData.tokenIn), amount: permit2TradeData.tradeData.amountIn}
),
nonce: permit2TradeData.nonce,
deadline: permit2TradeData.deadline
}),
ISignatureTransfer.SignatureTransferDetails({
to: address(this),
requestedAmount: permit2TradeData.tradeData.amountIn
}),
msg.sender,
permit2TradeDataHash,
PERMIT2_TYPE,
userSignature
);
return _execute(permit2TradeData.tradeData);
}
// ==================================================================================
// ==================================== APPROVAL ====================================
// ==================================================================================
/// @notice Function to execute trade and distribute fees
/// @dev Smart contract expects to receive tokensOut after trade
/// @dev Smart contract expects to have allowance to take tokenIn from msg.sender
/// @param tradeData Trade data
/// @return Amount of tokens OUT received by main receiver
/// @dev If token OUT is fee-on-transfer token:
/// - fees will not be collected
/// - calldata will be updated, so that tokens will be sent to `mainReceiver` in the first place
/// @dev Expects tokens IN to be approved to this contract
function execute(TradeData calldata tradeData) external payable nonReentrant returns (uint256) {
_takeTokensIn(tradeData);
return _execute(tradeData);
}
// =================================================================================
// ================================ ADMIN FUNCTIONS ================================
// =================================================================================
/// @notice Recover stuck tokens in case of emergency
/// @param token ERC20 token address or address(0) for native token
/// @param receiver Recovered tokens receiver
/// @dev Can be called only by the owner
function emergencyRecoverTokens(
IERC20 token,
address payable receiver
) external onlyOwner {
uint256 balance = _getBalance(token, address(this));
if (balance == 0) revert ZeroBalance();
_transferTokens(token, receiver, balance);
}
/// @notice Internal function to execute trade and distribute fees, if neither token IN or token OUT is fee on transfer token
/// 1) Call `callTarget` with `callData` and `msg.value`
/// 2) Check actual amountOut
/// 3) Send `(amountOutMin - amountOut) * feeShare / 10_000` to `feeReceiver`
/// 3) Send rest of tokens OUT to `mainReceiver`
/// @dev Smart contract expects to receive tokensOut after trade
/// @dev Smart contract expects to have allowance to take tokenIn from msg.sender
/// @param tradeData Trade data
/// @return mainReceiverReceived Amount of tokens OUT received by main receiver
/// @dev If token IN or token OUT is fee-on-transfer token, specific error will be thrown
function _execute(
TradeData calldata tradeData
) internal returns (uint256 mainReceiverReceived) {
_approveTokensIn(tradeData);
if (
tradeData.callTarget == address(0)
|| tradeData.mainReceiver == address(0)
) {
revert ZeroAddress();
}
if (tradeData.feeShare > 10_000) revert InvalidFeeShare();
uint256 received = 0;
{
uint256 initialBalance = _getBalance(tradeData.tokenOut, address(this));
(bool success, bytes memory errorData) = tradeData.callTarget.call{value: msg.value}(tradeData.callData);
if (!success) {
revert CallFailed(errorData);
}
received = _getBalance(tradeData.tokenOut, address(this)) - initialBalance;
if (received < tradeData.amountOutMin) {
revert BelowAmountOutMin(received);
}
}
uint256 feeAmount = (received - tradeData.amountOutMin) * tradeData.feeShare / 10_000;
// Transferring remaining tokens to main receiver
{
uint256 mainAmountOut = received - feeAmount;
uint256 mainReceiverInitialBalance = _getBalance(tradeData.tokenOut, tradeData.mainReceiver);
_transferTokens(tradeData.tokenOut, tradeData.mainReceiver, mainAmountOut);
mainReceiverReceived = _getBalance(tradeData.tokenOut, tradeData.mainReceiver)
- mainReceiverInitialBalance;
if (mainReceiverReceived < mainAmountOut) {
revert TokenOutHasTransferFee();
}
}
// Transferring fees
_transferTokens(tradeData.tokenOut, tradeData.feeReceiver, feeAmount);
emit TradeComplete(
msg.sender,
tradeData.mainReceiver,
address(tradeData.tokenIn),
tradeData.amountIn,
address(tradeData.tokenOut),
received - feeAmount,
tradeData.feeReceiver,
feeAmount
);
}
/// @notice If token is not native - transfers ERC20 tokens to this contract
/// @param tradeData Trade data
function _takeTokensIn(
TradeData calldata tradeData
) internal {
if (tradeData.tokenIn == IERC20(address(0))) {
// No need to transfer native tokens
return;
}
tradeData.tokenIn.safeTransferFrom(msg.sender, address(this), tradeData.amountIn);
if (tradeData.tokenIn.balanceOf(address(this)) < tradeData.amountIn) {
revert TokenInHasTransferFee();
}
}
/// @notice If token is not native - approve token to `approvalAddress` or `callTarget`
/// @param tradeData Trade data
function _approveTokensIn(
TradeData calldata tradeData
) internal {
if (tradeData.tokenIn == IERC20(address(0))) {
// No need to approve native tokens
return;
}
address approveTo = tradeData.approvalAddress == address(0)
? tradeData.callTarget
: tradeData.approvalAddress;
tradeData.tokenIn.forceApprove(approveTo, tradeData.amountIn);
}
/// @notice Returns tokens balance
/// @param token Token address. address(0) for native token
/// @param account Account address
function _getBalance(IERC20 token, address account) internal view returns (uint256) {
if (address(token) == address(0)) {
return account.balance;
}
return token.balanceOf(account);
}
/// @notice Transfer tokens
/// @param token Token address. address(0) for native token
/// @param account Tokens receiver
/// @param amount Amount to transfer
function _transferTokens(IERC20 token, address payable account, uint256 amount) internal {
if (amount == 0) return;
if (address(token) == address(0)) {
(bool success, bytes memory errorMessage) = account.call{value: amount}("");
if (!success) revert NativeTransferFailed(account, errorMessage);
} else {
token.safeTransfer(account, amount);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../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.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./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.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. 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.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
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();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 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 v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol)
pragma solidity ^0.8.24;
import {TransientSlot} from "./TransientSlot.sol";
/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*
* _Available since v5.1._
*/
abstract contract ReentrancyGuardTransient {
using TransientSlot for *;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
}
function _nonReentrantAfter() private {
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
pragma solidity ^0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary values that are removed after the current transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* * Example reading and writing values using transient storage:
* ```solidity
* contract Lock {
* using TransientSlot for *;
*
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
*
* modifier locked() {
* require(!_LOCK_SLOT.asBoolean().tload());
*
* _LOCK_SLOT.asBoolean().tstore(true);
* _;
* _LOCK_SLOT.asBoolean().tstore(false);
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library TransientSlot {
/**
* @dev UDVT that represents a slot holding an address.
*/
type AddressSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a AddressSlot.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
return AddressSlot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a bool.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a bytes32.
*/
type Bytes32Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Bytes32Slot.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
return Bytes32Slot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a uint256.
*/
type Uint256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Uint256Slot.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
return Uint256Slot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a int256.
*/
type Int256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Int256Slot.
*/
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
return Int256Slot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlot slot) internal view returns (address value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlot slot, address value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32Slot slot, bytes32 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256Slot slot) internal view returns (uint256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256Slot slot, uint256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256Slot slot) internal view returns (int256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256Slot slot, int256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title Utils to handle/work with errors
library ErrorUtils {
error CallFailed();
/// @dev Reverts with returnData if present. Otherwise reverts with {CallFailed}.
function revertWithErrorData(bytes memory returnData) internal 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 CallFailed();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IEIP712 {
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IEIP712} from "./IEIP712.sol";
/// @title SignatureTransfer
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface ISignatureTransfer is IEIP712 {
/// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
/// @param maxAmount The maximum amount a spender can request to transfer
error InvalidAmount(uint256 maxAmount);
/// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
/// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
error LengthMismatch();
/// @notice Emits an event when the owner successfully invalidates an unordered nonce.
event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);
/// @notice The token and amount details for a transfer signed in the permit transfer signature
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}
/// @notice The signed permit message for a single token transfer
struct PermitTransferFrom {
TokenPermissions permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice Specifies the recipient address and amount for batched transfers.
/// @dev Recipients and amounts correspond to the index of the signed token permissions array.
/// @dev Reverts if the requested amount is greater than the permitted signed amount.
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}
/// @notice Used to reconstruct the signed permit message for multiple token transfers
/// @dev Do not need to pass in spender address as it is required that it is msg.sender
/// @dev Note that a user still signs over a spender address
struct PermitBatchTransferFrom {
// the tokens and corresponding amounts permitted for a transfer
TokenPermissions[] permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
/// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
/// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
/// @dev It returns a uint256 bitmap
/// @dev The index, or wordPosition is capped at type(uint248).max
function nonceBitmap(address, uint256) external view returns (uint256);
/// @notice Transfers a token using a signed permit message
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param signature The signature to verify
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers a token using a signed permit message
/// @notice Includes extra data provided by the caller to verify signature over
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param signature The signature to verify
function permitTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
/// @notice Transfers multiple tokens using a signed permit message
/// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
/// @notice Includes extra data provided by the caller to verify signature over
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails Specifies the recipient and requested amount for the token transfer
/// @param witness Extra data to include when checking the user signature
/// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
/// @param signature The signature to verify
function permitWitnessTransferFrom(
PermitBatchTransferFrom memory permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32 witness,
string calldata witnessTypeString,
bytes calldata signature
) external;
/// @notice Invalidates the bits specified in mask for the bitmap at the word position
/// @dev The wordPos is maxed at type(uint248).max
/// @param wordPos A number to index the nonceBitmap at
/// @param mask A bitmap masked against msg.sender's current bitmap at the word position
function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}{
"optimizer": {
"enabled": true,
"runs": 999999
},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"evmVersion": "cancun",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ISignatureTransfer","name":"_permit2","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"received","type":"uint256"}],"name":"BelowAmountOutMin","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorMessage","type":"bytes"}],"name":"CallFailed","type":"error"},{"inputs":[],"name":"InvalidFeeShare","type":"error"},{"inputs":[],"name":"InvalidMsgValue","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"errorMessage","type":"bytes"}],"name":"NativeTransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenInHasTransferFee","type":"error"},{"inputs":[],"name":"TokenOutHasTransferFee","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroBalance","type":"error"},{"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":false,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"mainReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"feeReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"TradeComplete","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address payable","name":"receiver","type":"address"}],"name":"emergencyRecoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"callTarget","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"address","name":"approvalAddress","type":"address"},{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address payable","name":"mainReceiver","type":"address"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address payable","name":"feeReceiver","type":"address"},{"internalType":"uint16","name":"feeShare","type":"uint16"}],"internalType":"struct UnumRouter.TradeData","name":"tradeData","type":"tuple"}],"name":"execute","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"callTarget","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"address","name":"approvalAddress","type":"address"},{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address payable","name":"mainReceiver","type":"address"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address payable","name":"feeReceiver","type":"address"},{"internalType":"uint16","name":"feeShare","type":"uint16"}],"internalType":"struct UnumRouter.TradeData","name":"tradeData","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"executeWithPermit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address payable","name":"callTarget","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"address","name":"approvalAddress","type":"address"},{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address payable","name":"mainReceiver","type":"address"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address payable","name":"feeReceiver","type":"address"},{"internalType":"uint16","name":"feeShare","type":"uint16"}],"internalType":"struct UnumRouter.TradeData","name":"tradeData","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct UnumRouter.Permit2TradeData","name":"permit2TradeData","type":"tuple"},{"internalType":"bytes","name":"userSignature","type":"bytes"}],"name":"executeWithPermit2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","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":[],"name":"permit2","outputs":[{"internalType":"contract ISignatureTransfer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a060405234801561000f575f80fd5b5060405161228538038061228583398101604081905261002e91610132565b806001600160a01b03811661005c57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b610065816100b3565b506001600160a01b038216158061008357506001600160a01b038116155b156100a15760405163d92e233d60e01b815260040160405180910390fd5b506001600160a01b031660805261016a565b600180546001600160a01b03191690556100cc816100cf565b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146100cc575f80fd5b5f8060408385031215610143575f80fd5b825161014e8161011e565b602084015190925061015f8161011e565b809150509250929050565b6080516120fd6101885f395f818160cc01526109c401526120fd5ff3fe6080604052600436106100b0575f3560e01c806379ba509711610066578063b7e26a2e1161004c578063b7e26a2e146101b2578063e30c3978146101d1578063f2fde38b146101fb575f80fd5b806379ba5097146101755780638da5cb5b14610189575f80fd5b80632865fe14116100965780632865fe14146101395780636e13da3d1461014c578063715018a61461015f575f80fd5b806312261ee7146100bb5780631504931a14610118575f80fd5b366100b757005b5f80fd5b3480156100c6575f80fd5b506100ee7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61012b610126366004611bd3565b61021a565b60405190815260200161010f565b61012b610147366004611c0d565b610244565b61012b61015a366004611c78565b61032c565b34801561016a575f80fd5b50610173610def565b005b348015610180575f80fd5b50610173610e02565b348015610194575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166100ee565b3480156101bd575f80fd5b506101736101cc366004611d35565b610e7e565b3480156101dc575f80fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166100ee565b348015610206575f80fd5b50610173610215366004611d6c565b610edc565b5f610223610f8b565b61022c82611011565b61023582611151565b905061023f611586565b919050565b5f61024d610f8b565b61025d6080870160608801611d6c565b6040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152608088013560448201526064810187905260ff8616608482015260a4810185905260c4810184905273ffffffffffffffffffffffffffffffffffffffff919091169063d505accf9060e4015f604051808303815f87803b1580156102f1575f80fd5b505af1158015610303573d5f803e3d5ffd5b5050505061031086611011565b61031986611151565b9050610323611586565b95945050505050565b5f610335610f8b565b6040517f547261646544617461280000000000000000000000000000000000000000000060208201527f616464726573732063616c6c5461726765742c00000000000000000000000000602a8201527f62797465732063616c6c446174612c0000000000000000000000000000000000603d8201527f6164647265737320617070726f76616c416464726573732c0000000000000000604c8201527f6164647265737320746f6b656e496e2c0000000000000000000000000000000060648201527f75696e7432353620616d6f756e74496e2c00000000000000000000000000000060748201527f61646472657373206d61696e52656365697665722c000000000000000000000060858201527f6164647265737320746f6b656e4f75742c000000000000000000000000000000609a8201527f75696e7432353620616d6f756e744f75744d696e2c000000000000000000000060ab8201527f616464726573732066656552656365697665722c75696e74313620666565536860c08201527f617265290000000000000000000000000000000000000000000000000000000060e08201525f9060e401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012061051f8680611d87565b61052d906020810190611d6c565b6105378780611d87565b610545906020810190611dc3565b604051610553929190611e2b565b6040519081900390206105668880611d87565b610577906060810190604001611d6c565b6105818980611d87565b610592906080810190606001611d6c565b61059c8a80611d87565b608001356105aa8b80611d87565b6105bb9060c081019060a001611d6c565b6105c58c80611d87565b6105d69060e081019060c001611d6c565b6105e08d80611d87565b60e001356105ee8e80611d87565b6106019061012081019061010001611d6c565b61060b8f80611d87565b61061e9061014081019061012001611e3a565b60408051602081019c909c5273ffffffffffffffffffffffffffffffffffffffff9a8b16908c015260608b019890985295881660808a015293871660a089015260c0880192909252851660e0870152841661010086015261012085015290911661014083015261ffff16610160820152610180016040516020818303038152906040528051906020012090505f60405160200161072a907f5065726d6974325472616465446174612854726164654461746120747261646581527f446174612c75696e7432353620646561646c696e652c75696e74323536206e6f60208201527f6e63652900000000000000000000000000000000000000000000000000000000604082015260440190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f547261646544617461280000000000000000000000000000000000000000000060208401527f616464726573732063616c6c5461726765742c00000000000000000000000000602a8401527f62797465732063616c6c446174612c0000000000000000000000000000000000603d8401527f6164647265737320617070726f76616c416464726573732c0000000000000000604c8401527f6164647265737320746f6b656e496e2c0000000000000000000000000000000060648401527f75696e7432353620616d6f756e74496e2c00000000000000000000000000000060748401527f61646472657373206d61696e52656365697665722c000000000000000000000060858401527f6164647265737320746f6b656e4f75742c000000000000000000000000000000609a8401527f75696e7432353620616d6f756e744f75744d696e2c000000000000000000000060ab8401527f616464726573732066656552656365697665722c75696e74313620666565536860c08401527f617265290000000000000000000000000000000000000000000000000000000060e0840152815160c481850301815260e4840190925261091b9290919061010401611e72565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838201528282018590528801356060830152870135608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209091012060a08301909152915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063137c29fe908060608101806109fb8c80611d87565b610a0c906080810190606001611d6c565b73ffffffffffffffffffffffffffffffffffffffff168152602001610a318c80611d87565b60800135815250815260200189604001358152602001896020013581525060405180604001604052803073ffffffffffffffffffffffffffffffffffffffff1681526020018a805f0190610a859190611d87565b608001358152503385604051602001610b0d907f5065726d6974325472616465446174612854726164654461746120747261646581527f446174612c75696e7432353620646561646c696e652c75696e74323536206e6f60208201527f6e63652900000000000000000000000000000000000000000000000000000000604082015260440190565b604051602081830303815290604052604051602001610b75907f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7581527f696e7432353620616d6f756e74290000000000000000000000000000000000006020820152602e0190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f547261646544617461280000000000000000000000000000000000000000000060208401527f616464726573732063616c6c5461726765742c00000000000000000000000000602a8401527f62797465732063616c6c446174612c0000000000000000000000000000000000603d8401527f6164647265737320617070726f76616c416464726573732c0000000000000000604c8401527f6164647265737320746f6b656e496e2c0000000000000000000000000000000060648401527f75696e7432353620616d6f756e74496e2c00000000000000000000000000000060748401527f61646472657373206d61696e52656365697665722c000000000000000000000060858401527f6164647265737320746f6b656e4f75742c000000000000000000000000000000609a8401527f75696e7432353620616d6f756e744f75744d696e2c000000000000000000000060ab8401527f616464726573732066656552656365697665722c75696e74313620666565536860c08401527f617265290000000000000000000000000000000000000000000000000000000060e0840152815160c481850301815260e48401909252610d67939290919061010401611e86565b6040516020818303038152906040528b8b6040518863ffffffff1660e01b8152600401610d9a9796959493929190611f0f565b5f604051808303815f87803b158015610db1575f80fd5b505af1158015610dc3573d5f803e3d5ffd5b50610ddc9250610dd7915088905080611d87565b611151565b92505050610de8611586565b9392505050565b610df76115b0565b610e005f611602565b565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610e72576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b610e7b81611602565b50565b610e866115b0565b5f610e918330611633565b9050805f03610ecc576040517f669567ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ed7838383611704565b505050565b610ee46115b0565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155610f465f5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610fe4576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e0060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b906117ef565b5f6110226080830160608401611d6c565b73ffffffffffffffffffffffffffffffffffffffff16036110405750565b6110773330608084018035906110599060608701611d6c565b73ffffffffffffffffffffffffffffffffffffffff169291906117f6565b6080810180359061108b9060608401611d6c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa1580156110f5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611119919061200a565b1015610e7b576040517f9c0f8e5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61115b82611885565b5f6111696020840184611d6c565b73ffffffffffffffffffffffffffffffffffffffff1614806111af57505f61119760c0840160a08501611d6c565b73ffffffffffffffffffffffffffffffffffffffff16145b156111e6576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127106111fb61014084016101208501611e3a565b61ffff161115611237576040517fe8cdd5bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8061125261124c60e0860160c08701611d6c565b30611633565b90505f806112636020870187611d6c565b73ffffffffffffffffffffffffffffffffffffffff16346112876020890189611dc3565b604051611295929190611e2b565b5f6040518083038185875af1925050503d805f81146112cf576040519150601f19603f3d011682016040523d82523d5f602084013e6112d4565b606091505b50915091508161131257806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610e699190612021565b8261132661124c60e0890160c08a01611d6c565b6113309190612060565b93508560e00135841015611373576040517fff5f293c00000000000000000000000000000000000000000000000000000000815260048101859052602401610e69565b505f9150612710905061138e61014086016101208701611e3a565b61ffff166113a060e087013585612060565b6113aa9190612073565b6113b4919061208a565b90505f6113c18284612060565b90505f6113ec6113d760e0880160c08901611d6c565b6113e760c0890160a08a01611d6c565b611633565b905061141761140160e0880160c08901611d6c565b61141160c0890160a08a01611d6c565b84611704565b8061143b61142b60e0890160c08a01611d6c565b6113e760c08a0160a08b01611d6c565b6114459190612060565b945081851015611481576040517fe5800fae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506114af905061149760e0860160c08701611d6c565b6114a961012087016101008801611d6c565b83611704565b7f9e01b460f667c0d729562ef108a68c84fb29d6540a49efcfa2ddea5cb02f922f336114e160c0870160a08801611d6c565b6114f16080880160608901611d6c565b608088013561150660e08a0160c08b01611d6c565b6115108789612060565b6115226101208c016101008d01611d6c565b6040805173ffffffffffffffffffffffffffffffffffffffff98891681529688166020880152948716868601526060860193909352908516608085015260a084015290921660c082015260e081018490529051908190036101000190a15050919050565b610e005f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0061100b565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610e00576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610e69565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610e7b8161193e565b5f73ffffffffffffffffffffffffffffffffffffffff831661166d575073ffffffffffffffffffffffffffffffffffffffff8116316116fe565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa1580156116d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116fb919061200a565b90505b92915050565b805f0361171057505050565b73ffffffffffffffffffffffffffffffffffffffff83166117ce575f808373ffffffffffffffffffffffffffffffffffffffff16836040515f6040518083038185875af1925050503d805f8114611782576040519150601f19603f3d011682016040523d82523d5f602084013e611787565b606091505b5091509150816117c75783816040517f23340f43000000000000000000000000000000000000000000000000000000008152600401610e699291906120c2565b5050505050565b610ed773ffffffffffffffffffffffffffffffffffffffff841683836119b2565b80825d5050565b60405173ffffffffffffffffffffffffffffffffffffffff848116602483015283811660448301526064820183905261187f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506119f0565b50505050565b5f6118966080830160608401611d6c565b73ffffffffffffffffffffffffffffffffffffffff16036118b45750565b5f806118c66060840160408501611d6c565b73ffffffffffffffffffffffffffffffffffffffff16146118f6576118f16060830160408401611d6c565b611903565b6119036020830183611d6c565b905061193a816080840180359061191d9060608701611d6c565b73ffffffffffffffffffffffffffffffffffffffff169190611a8f565b5050565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff838116602483015260448201839052610ed791859182169063a9059cbb90606401611838565b5f8060205f8451602086015f885af180611a0f576040513d5f823e3d81fd5b50505f513d91508115611a26578060011415611a40565b73ffffffffffffffffffffffffffffffffffffffff84163b155b1561187f576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610e69565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052611b1b8482611b66565b61187f5760405173ffffffffffffffffffffffffffffffffffffffff84811660248301525f6044830152611b5c91869182169063095ea7b390606401611838565b61187f84826119f0565b5f805f8060205f8651602088015f8a5af192503d91505f519050828015611bb257508115611b975780600114611bb2565b5f8673ffffffffffffffffffffffffffffffffffffffff163b115b9695505050505050565b5f6101408284031215611bcd575f80fd5b50919050565b5f60208284031215611be3575f80fd5b813567ffffffffffffffff811115611bf9575f80fd5b611c0584828501611bbc565b949350505050565b5f805f805f60a08688031215611c21575f80fd5b853567ffffffffffffffff811115611c37575f80fd5b611c4388828901611bbc565b95505060208601359350604086013560ff81168114611c60575f80fd5b94979396509394606081013594506080013592915050565b5f805f60408486031215611c8a575f80fd5b833567ffffffffffffffff811115611ca0575f80fd5b840160608187031215611cb1575f80fd5b9250602084013567ffffffffffffffff811115611ccc575f80fd5b8401601f81018613611cdc575f80fd5b803567ffffffffffffffff811115611cf2575f80fd5b866020828401011115611d03575f80fd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610e7b575f80fd5b5f8060408385031215611d46575f80fd5b8235611d5181611d14565b91506020830135611d6181611d14565b809150509250929050565b5f60208284031215611d7c575f80fd5b8135610de881611d14565b5f82357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1833603018112611db9575f80fd5b9190910192915050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611df6575f80fd5b83018035915067ffffffffffffffff821115611e10575f80fd5b602001915036819003821315611e24575f80fd5b9250929050565b818382375f9101908152919050565b5f60208284031215611e4a575f80fd5b813561ffff81168114610de8575f80fd5b5f81518060208401855e5f93019283525090919050565b5f611c05611e808386611e5b565b84611e5b565b7f5065726d697432547261646544617461207769746e657373290000000000000081525f610323611e80611ebd6019850188611e5b565b86611e5b565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b611f3a818951805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b6020880151604082015260408801516060820152611f7b6080820188805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff861660c08201528460e08201526101406101008201525f611fb5610140830186611ec3565b828103610120840152838152838560208301375f6020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011682010191505098975050505050505050565b5f6020828403121561201a575f80fd5b5051919050565b602081525f6116fb6020830184611ec3565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156116fe576116fe612033565b80820281158282048414176116fe576116fe612033565b5f826120bd577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201525f611c056040830184611ec356fea164736f6c634300081a000a000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000d8655d1154a74748ac48f673264efba5c369f4bd
Deployed Bytecode
0x6080604052600436106100b0575f3560e01c806379ba509711610066578063b7e26a2e1161004c578063b7e26a2e146101b2578063e30c3978146101d1578063f2fde38b146101fb575f80fd5b806379ba5097146101755780638da5cb5b14610189575f80fd5b80632865fe14116100965780632865fe14146101395780636e13da3d1461014c578063715018a61461015f575f80fd5b806312261ee7146100bb5780631504931a14610118575f80fd5b366100b757005b5f80fd5b3480156100c6575f80fd5b506100ee7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61012b610126366004611bd3565b61021a565b60405190815260200161010f565b61012b610147366004611c0d565b610244565b61012b61015a366004611c78565b61032c565b34801561016a575f80fd5b50610173610def565b005b348015610180575f80fd5b50610173610e02565b348015610194575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166100ee565b3480156101bd575f80fd5b506101736101cc366004611d35565b610e7e565b3480156101dc575f80fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166100ee565b348015610206575f80fd5b50610173610215366004611d6c565b610edc565b5f610223610f8b565b61022c82611011565b61023582611151565b905061023f611586565b919050565b5f61024d610f8b565b61025d6080870160608801611d6c565b6040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152608088013560448201526064810187905260ff8616608482015260a4810185905260c4810184905273ffffffffffffffffffffffffffffffffffffffff919091169063d505accf9060e4015f604051808303815f87803b1580156102f1575f80fd5b505af1158015610303573d5f803e3d5ffd5b5050505061031086611011565b61031986611151565b9050610323611586565b95945050505050565b5f610335610f8b565b6040517f547261646544617461280000000000000000000000000000000000000000000060208201527f616464726573732063616c6c5461726765742c00000000000000000000000000602a8201527f62797465732063616c6c446174612c0000000000000000000000000000000000603d8201527f6164647265737320617070726f76616c416464726573732c0000000000000000604c8201527f6164647265737320746f6b656e496e2c0000000000000000000000000000000060648201527f75696e7432353620616d6f756e74496e2c00000000000000000000000000000060748201527f61646472657373206d61696e52656365697665722c000000000000000000000060858201527f6164647265737320746f6b656e4f75742c000000000000000000000000000000609a8201527f75696e7432353620616d6f756e744f75744d696e2c000000000000000000000060ab8201527f616464726573732066656552656365697665722c75696e74313620666565536860c08201527f617265290000000000000000000000000000000000000000000000000000000060e08201525f9060e401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012061051f8680611d87565b61052d906020810190611d6c565b6105378780611d87565b610545906020810190611dc3565b604051610553929190611e2b565b6040519081900390206105668880611d87565b610577906060810190604001611d6c565b6105818980611d87565b610592906080810190606001611d6c565b61059c8a80611d87565b608001356105aa8b80611d87565b6105bb9060c081019060a001611d6c565b6105c58c80611d87565b6105d69060e081019060c001611d6c565b6105e08d80611d87565b60e001356105ee8e80611d87565b6106019061012081019061010001611d6c565b61060b8f80611d87565b61061e9061014081019061012001611e3a565b60408051602081019c909c5273ffffffffffffffffffffffffffffffffffffffff9a8b16908c015260608b019890985295881660808a015293871660a089015260c0880192909252851660e0870152841661010086015261012085015290911661014083015261ffff16610160820152610180016040516020818303038152906040528051906020012090505f60405160200161072a907f5065726d6974325472616465446174612854726164654461746120747261646581527f446174612c75696e7432353620646561646c696e652c75696e74323536206e6f60208201527f6e63652900000000000000000000000000000000000000000000000000000000604082015260440190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f547261646544617461280000000000000000000000000000000000000000000060208401527f616464726573732063616c6c5461726765742c00000000000000000000000000602a8401527f62797465732063616c6c446174612c0000000000000000000000000000000000603d8401527f6164647265737320617070726f76616c416464726573732c0000000000000000604c8401527f6164647265737320746f6b656e496e2c0000000000000000000000000000000060648401527f75696e7432353620616d6f756e74496e2c00000000000000000000000000000060748401527f61646472657373206d61696e52656365697665722c000000000000000000000060858401527f6164647265737320746f6b656e4f75742c000000000000000000000000000000609a8401527f75696e7432353620616d6f756e744f75744d696e2c000000000000000000000060ab8401527f616464726573732066656552656365697665722c75696e74313620666565536860c08401527f617265290000000000000000000000000000000000000000000000000000000060e0840152815160c481850301815260e4840190925261091b9290919061010401611e72565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838201528282018590528801356060830152870135608082015260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209091012060a08301909152915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3169063137c29fe908060608101806109fb8c80611d87565b610a0c906080810190606001611d6c565b73ffffffffffffffffffffffffffffffffffffffff168152602001610a318c80611d87565b60800135815250815260200189604001358152602001896020013581525060405180604001604052803073ffffffffffffffffffffffffffffffffffffffff1681526020018a805f0190610a859190611d87565b608001358152503385604051602001610b0d907f5065726d6974325472616465446174612854726164654461746120747261646581527f446174612c75696e7432353620646561646c696e652c75696e74323536206e6f60208201527f6e63652900000000000000000000000000000000000000000000000000000000604082015260440190565b604051602081830303815290604052604051602001610b75907f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7581527f696e7432353620616d6f756e74290000000000000000000000000000000000006020820152602e0190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282527f547261646544617461280000000000000000000000000000000000000000000060208401527f616464726573732063616c6c5461726765742c00000000000000000000000000602a8401527f62797465732063616c6c446174612c0000000000000000000000000000000000603d8401527f6164647265737320617070726f76616c416464726573732c0000000000000000604c8401527f6164647265737320746f6b656e496e2c0000000000000000000000000000000060648401527f75696e7432353620616d6f756e74496e2c00000000000000000000000000000060748401527f61646472657373206d61696e52656365697665722c000000000000000000000060858401527f6164647265737320746f6b656e4f75742c000000000000000000000000000000609a8401527f75696e7432353620616d6f756e744f75744d696e2c000000000000000000000060ab8401527f616464726573732066656552656365697665722c75696e74313620666565536860c08401527f617265290000000000000000000000000000000000000000000000000000000060e0840152815160c481850301815260e48401909252610d67939290919061010401611e86565b6040516020818303038152906040528b8b6040518863ffffffff1660e01b8152600401610d9a9796959493929190611f0f565b5f604051808303815f87803b158015610db1575f80fd5b505af1158015610dc3573d5f803e3d5ffd5b50610ddc9250610dd7915088905080611d87565b611151565b92505050610de8611586565b9392505050565b610df76115b0565b610e005f611602565b565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610e72576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b610e7b81611602565b50565b610e866115b0565b5f610e918330611633565b9050805f03610ecc576040517f669567ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ed7838383611704565b505050565b610ee46115b0565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff00000000000000000000000000000000000000009091168117909155610f465f5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610fe4576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e0060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b906117ef565b5f6110226080830160608401611d6c565b73ffffffffffffffffffffffffffffffffffffffff16036110405750565b6110773330608084018035906110599060608701611d6c565b73ffffffffffffffffffffffffffffffffffffffff169291906117f6565b6080810180359061108b9060608401611d6c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff91909116906370a0823190602401602060405180830381865afa1580156110f5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611119919061200a565b1015610e7b576040517f9c0f8e5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61115b82611885565b5f6111696020840184611d6c565b73ffffffffffffffffffffffffffffffffffffffff1614806111af57505f61119760c0840160a08501611d6c565b73ffffffffffffffffffffffffffffffffffffffff16145b156111e6576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127106111fb61014084016101208501611e3a565b61ffff161115611237576040517fe8cdd5bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8061125261124c60e0860160c08701611d6c565b30611633565b90505f806112636020870187611d6c565b73ffffffffffffffffffffffffffffffffffffffff16346112876020890189611dc3565b604051611295929190611e2b565b5f6040518083038185875af1925050503d805f81146112cf576040519150601f19603f3d011682016040523d82523d5f602084013e6112d4565b606091505b50915091508161131257806040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152600401610e699190612021565b8261132661124c60e0890160c08a01611d6c565b6113309190612060565b93508560e00135841015611373576040517fff5f293c00000000000000000000000000000000000000000000000000000000815260048101859052602401610e69565b505f9150612710905061138e61014086016101208701611e3a565b61ffff166113a060e087013585612060565b6113aa9190612073565b6113b4919061208a565b90505f6113c18284612060565b90505f6113ec6113d760e0880160c08901611d6c565b6113e760c0890160a08a01611d6c565b611633565b905061141761140160e0880160c08901611d6c565b61141160c0890160a08a01611d6c565b84611704565b8061143b61142b60e0890160c08a01611d6c565b6113e760c08a0160a08b01611d6c565b6114459190612060565b945081851015611481576040517fe5800fae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506114af905061149760e0860160c08701611d6c565b6114a961012087016101008801611d6c565b83611704565b7f9e01b460f667c0d729562ef108a68c84fb29d6540a49efcfa2ddea5cb02f922f336114e160c0870160a08801611d6c565b6114f16080880160608901611d6c565b608088013561150660e08a0160c08b01611d6c565b6115108789612060565b6115226101208c016101008d01611d6c565b6040805173ffffffffffffffffffffffffffffffffffffffff98891681529688166020880152948716868601526060860193909352908516608085015260a084015290921660c082015260e081018490529051908190036101000190a15050919050565b610e005f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0061100b565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610e00576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610e69565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610e7b8161193e565b5f73ffffffffffffffffffffffffffffffffffffffff831661166d575073ffffffffffffffffffffffffffffffffffffffff8116316116fe565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa1580156116d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116fb919061200a565b90505b92915050565b805f0361171057505050565b73ffffffffffffffffffffffffffffffffffffffff83166117ce575f808373ffffffffffffffffffffffffffffffffffffffff16836040515f6040518083038185875af1925050503d805f8114611782576040519150601f19603f3d011682016040523d82523d5f602084013e611787565b606091505b5091509150816117c75783816040517f23340f43000000000000000000000000000000000000000000000000000000008152600401610e699291906120c2565b5050505050565b610ed773ffffffffffffffffffffffffffffffffffffffff841683836119b2565b80825d5050565b60405173ffffffffffffffffffffffffffffffffffffffff848116602483015283811660448301526064820183905261187f9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506119f0565b50505050565b5f6118966080830160608401611d6c565b73ffffffffffffffffffffffffffffffffffffffff16036118b45750565b5f806118c66060840160408501611d6c565b73ffffffffffffffffffffffffffffffffffffffff16146118f6576118f16060830160408401611d6c565b611903565b6119036020830183611d6c565b905061193a816080840180359061191d9060608701611d6c565b73ffffffffffffffffffffffffffffffffffffffff169190611a8f565b5050565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff838116602483015260448201839052610ed791859182169063a9059cbb90606401611838565b5f8060205f8451602086015f885af180611a0f576040513d5f823e3d81fd5b50505f513d91508115611a26578060011415611a40565b73ffffffffffffffffffffffffffffffffffffffff84163b155b1561187f576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610e69565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052611b1b8482611b66565b61187f5760405173ffffffffffffffffffffffffffffffffffffffff84811660248301525f6044830152611b5c91869182169063095ea7b390606401611838565b61187f84826119f0565b5f805f8060205f8651602088015f8a5af192503d91505f519050828015611bb257508115611b975780600114611bb2565b5f8673ffffffffffffffffffffffffffffffffffffffff163b115b9695505050505050565b5f6101408284031215611bcd575f80fd5b50919050565b5f60208284031215611be3575f80fd5b813567ffffffffffffffff811115611bf9575f80fd5b611c0584828501611bbc565b949350505050565b5f805f805f60a08688031215611c21575f80fd5b853567ffffffffffffffff811115611c37575f80fd5b611c4388828901611bbc565b95505060208601359350604086013560ff81168114611c60575f80fd5b94979396509394606081013594506080013592915050565b5f805f60408486031215611c8a575f80fd5b833567ffffffffffffffff811115611ca0575f80fd5b840160608187031215611cb1575f80fd5b9250602084013567ffffffffffffffff811115611ccc575f80fd5b8401601f81018613611cdc575f80fd5b803567ffffffffffffffff811115611cf2575f80fd5b866020828401011115611d03575f80fd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610e7b575f80fd5b5f8060408385031215611d46575f80fd5b8235611d5181611d14565b91506020830135611d6181611d14565b809150509250929050565b5f60208284031215611d7c575f80fd5b8135610de881611d14565b5f82357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1833603018112611db9575f80fd5b9190910192915050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611df6575f80fd5b83018035915067ffffffffffffffff821115611e10575f80fd5b602001915036819003821315611e24575f80fd5b9250929050565b818382375f9101908152919050565b5f60208284031215611e4a575f80fd5b813561ffff81168114610de8575f80fd5b5f81518060208401855e5f93019283525090919050565b5f611c05611e808386611e5b565b84611e5b565b7f5065726d697432547261646544617461207769746e657373290000000000000081525f610323611e80611ebd6019850188611e5b565b86611e5b565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b611f3a818951805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b6020880151604082015260408801516060820152611f7b6080820188805173ffffffffffffffffffffffffffffffffffffffff168252602090810151910152565b73ffffffffffffffffffffffffffffffffffffffff861660c08201528460e08201526101406101008201525f611fb5610140830186611ec3565b828103610120840152838152838560208301375f6020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f86011682010191505098975050505050505050565b5f6020828403121561201a575f80fd5b5051919050565b602081525f6116fb6020830184611ec3565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156116fe576116fe612033565b80820281158282048414176116fe576116fe612033565b5f826120bd577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201525f611c056040830184611ec356fea164736f6c634300081a000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000d8655d1154a74748ac48f673264efba5c369f4bd
-----Decoded View---------------
Arg [0] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [1] : initialOwner (address): 0xd8655d1154a74748ac48F673264efBA5c369F4bd
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [1] : 000000000000000000000000d8655d1154a74748ac48f673264efba5c369f4bd
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.