Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
FeeCollector
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import { IWETH } from "@1inch/solidity-utils/contracts/interfaces/IWETH.sol"; import { ECDSA } from "@1inch/solidity-utils/contracts/libraries/ECDSA.sol"; import { BalanceManager } from "./BalanceManager.sol"; contract FeeCollector is BalanceManager { address private immutable _OWNER; address private immutable _LIMIT_ORDER_PROTOCOL; address public operator; event OperatorChanged(address newOperator); error AccessDenied(); constructor(IWETH weth, address lop, address owner) BalanceManager(weth) { if (owner == address(0) || lop == address(0)) revert ZeroAddress(); _OWNER = owner; _LIMIT_ORDER_PROTOCOL = lop; } modifier onlyOwner() override { if (msg.sender != operator) revert OnlyOwner(); _; } function setOperator(address newOperator) external { if (msg.sender != _OWNER) revert AccessDenied(); operator = newOperator; emit OperatorChanged(newOperator); } function isValidSignature(bytes32 hash, bytes calldata signature) external view override returns (bytes4 magicValue) { address signer; if (msg.sender == _LIMIT_ORDER_PROTOCOL) { signer = ECDSA.recover(hash, signature); } else { signer = ECDSA.recover(keccak256(abi.encodePacked(hash, address(this))), signature); } if (signer == operator) magicValue = this.isValidSignature.selector; } function _targetToCheck() internal view override returns(address) { return address(this); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IDaiLikePermit * @dev Interface for Dai-like permit function allowing token spending via signatures. */ interface IDaiLikePermit { /** * @notice Approves spending of tokens via off-chain signatures. * @param holder Token holder's address. * @param spender Spender's address. * @param nonce Current nonce of the holder. * @param expiry Time when the permit expires. * @param allowed True to allow, false to disallow spending. * @param v, r, s Signature components. */ function permit( address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IERC7597Permit * @dev A new extension for ERC-2612 permit, which has already been added to USDC v2.2. */ interface IERC7597Permit { /** * @notice Update allowance with a signed permit. * @dev Signature bytes can be used for both EOA wallets and contract wallets. * @param owner Token owner's address (Authorizer). * @param spender Spender's address. * @param value Amount of allowance. * @param deadline The time at which the signature expires (unixtime). * @param signature Unstructured bytes signature signed by an EOA wallet or a contract wallet. */ function permit( address owner, address spender, uint256 value, uint256 deadline, bytes memory signature ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IPermit2 * @dev Interface for a flexible permit system that extends ERC20 tokens to support permits in tokens lacking native permit functionality. */ interface IPermit2 { /** * @dev Struct for holding permit details. * @param token ERC20 token address for which the permit is issued. * @param amount The maximum amount allowed to spend. * @param expiration Timestamp until which the permit is valid. * @param nonce An incrementing value for each signature, unique per owner, token, and spender. */ struct PermitDetails { address token; uint160 amount; uint48 expiration; uint48 nonce; } /** * @dev Struct for a single token allowance permit. * @param details Permit details including token, amount, expiration, and nonce. * @param spender Address authorized to spend the tokens. * @param sigDeadline Deadline for the permit signature, ensuring timeliness of the permit. */ struct PermitSingle { PermitDetails details; address spender; uint256 sigDeadline; } /** * @dev Struct for packed allowance data to optimize storage. * @param amount Amount allowed. * @param expiration Permission expiry timestamp. * @param nonce Unique incrementing value for tracking allowances. */ struct PackedAllowance { uint160 amount; uint48 expiration; uint48 nonce; } /** * @notice Executes a token transfer from one address to another. * @param user The token owner's address. * @param spender The address authorized to spend the tokens. * @param amount The amount of tokens to transfer. * @param token The address of the token being transferred. */ function transferFrom(address user, address spender, uint160 amount, address token) external; /** * @notice Issues a permit for spending tokens via a signed authorization. * @param owner The token owner's address. * @param permitSingle Struct containing the permit details. * @param signature The signature proving the owner authorized the permit. */ function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external; /** * @notice Retrieves the allowance details between a token owner and spender. * @param user The token owner's address. * @param token The token address. * @param spender The spender's address. * @return The packed allowance details. */ function allowance(address user, address token, address spender) external view returns (PackedAllowance memory); /** * @notice Approves the spender to use up to amount of the specified token up until the expiration * @param token The token to approve * @param spender The spender address to approve * @param amount The approved amount of the token * @param expiration The timestamp at which the approval is no longer valid * @dev The packed allowance also holds a nonce, which will stay unchanged in approve * @dev Setting amount to type(uint160).max sets an unlimited approval */ function approve(address token, address spender, uint160 amount, uint48 expiration) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title IWETH * @dev Interface for wrapper as WETH-like token. */ interface IWETH is IERC20 { /** * @notice Emitted when Ether is deposited to get wrapper tokens. */ event Deposit(address indexed dst, uint256 wad); /** * @notice Emitted when wrapper tokens is withdrawn as Ether. */ event Withdrawal(address indexed src, uint256 wad); /** * @notice Deposit Ether to get wrapper tokens. */ function deposit() external payable; /** * @notice Withdraw wrapped tokens as Ether. * @param amount Amount of wrapped tokens to withdraw. */ function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/interfaces/IERC1271.sol"; /** * @title ECDSA signature operations * @notice Provides functions for recovering addresses from signatures and verifying signatures, including support for EIP-2098 compact signatures. */ library ECDSA { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. uint256 private constant _S_BOUNDARY = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 + 1; uint256 private constant _COMPACT_S_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; uint256 private constant _COMPACT_V_SHIFT = 255; /** * @notice Recovers the signer's address from the signature. * @dev Recovers the address that has signed a hash with `(v, r, s)` signature. * @param hash The keccak256 hash of the data signed. * @param v The recovery byte of the signature. * @param r The first 32 bytes of the signature. * @param s The second 32 bytes of the signature. * @return signer The address of the signer. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal view returns (address signer) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly if lt(s, _S_BOUNDARY) { let ptr := mload(0x40) mstore(ptr, hash) mstore(add(ptr, 0x20), v) mstore(add(ptr, 0x40), r) mstore(add(ptr, 0x60), s) mstore(0, 0) pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20)) signer := mload(0) } } } /** * @notice Recovers the signer's address from the signature using `r` and `vs` components. * @dev Recovers the address that has signed a hash with `r` and `vs`, where `vs` combines `v` and `s`. * @param hash The keccak256 hash of the data signed. * @param r The first 32 bytes of the signature. * @param vs The combined `v` and `s` values of the signature. * @return signer The address of the signer. */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (address signer) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let s := and(vs, _COMPACT_S_MASK) if lt(s, _S_BOUNDARY) { let ptr := mload(0x40) mstore(ptr, hash) mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs))) mstore(add(ptr, 0x40), r) mstore(add(ptr, 0x60), s) mstore(0, 0) pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20)) signer := mload(0) } } } /** * @notice Recovers the signer's address from a hash and a signature. * @param hash The keccak256 hash of the signed data. * @param signature The full signature from which the signer will be recovered. * @return signer The address of the signer. */ /// @dev WARNING!!! /// There is a known signature malleability issue with two representations of signatures! /// Even though this function is able to verify both standard 65-byte and compact 64-byte EIP-2098 signatures /// one should never use raw signatures for any kind of invalidation logic in their code. /// As the standard and compact representations are interchangeable any invalidation logic that relies on /// signature uniqueness will get rekt. /// More info: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h function recover(bytes32 hash, bytes calldata signature) internal view returns (address signer) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) // memory[ptr:ptr+0x80] = (hash, v, r, s) switch signature.length case 65 { // memory[ptr+0x20:ptr+0x80] = (v, r, s) mstore(add(ptr, 0x20), byte(0, calldataload(add(signature.offset, 0x40)))) calldatacopy(add(ptr, 0x40), signature.offset, 0x40) } case 64 { // memory[ptr+0x20:ptr+0x80] = (v, r, s) let vs := calldataload(add(signature.offset, 0x20)) mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs))) calldatacopy(add(ptr, 0x40), signature.offset, 0x20) mstore(add(ptr, 0x60), and(vs, _COMPACT_S_MASK)) } default { ptr := 0 } if ptr { if lt(mload(add(ptr, 0x60)), _S_BOUNDARY) { // memory[ptr:ptr+0x20] = (hash) mstore(ptr, hash) mstore(0, 0) pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20)) signer := mload(0) } } } } /** * @notice Verifies the signature for a hash, either by recovering the signer or using EIP-1271's `isValidSignature` function. * @dev Attempts to recover the signer's address from the signature; if the address is non-zero, checks if it's valid according to EIP-1271. * @param signer The address to validate the signature against. * @param hash The hash of the signed data. * @param signature The signature to verify. * @return success True if the signature is verified, false otherwise. */ function recoverOrIsValidSignature( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool success) { if (signer == address(0)) return false; if ((signature.length == 64 || signature.length == 65) && recover(hash, signature) == signer) { return true; } return isValidSignature(signer, hash, signature); } /** * @notice Verifies the signature for a hash, either by recovering the signer or using EIP-1271's `isValidSignature` function. * @dev Attempts to recover the signer's address from the signature; if the address is non-zero, checks if it's valid according to EIP-1271. * @param signer The address to validate the signature against. * @param hash The hash of the signed data. * @param v The recovery byte of the signature. * @param r The first 32 bytes of the signature. * @param s The second 32 bytes of the signature. * @return success True if the signature is verified, false otherwise. */ function recoverOrIsValidSignature( address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal view returns (bool success) { if (signer == address(0)) return false; if (recover(hash, v, r, s) == signer) { return true; } return isValidSignature(signer, hash, v, r, s); } /** * @notice Verifies the signature for a hash, either by recovering the signer or using EIP-1271's `isValidSignature` function. * @dev Attempts to recover the signer's address from the signature; if the address is non-zero, checks if it's valid according to EIP-1271. * @param signer The address to validate the signature against. * @param hash The hash of the signed data. * @param r The first 32 bytes of the signature. * @param vs The combined `v` and `s` values of the signature. * @return success True if the signature is verified, false otherwise. */ function recoverOrIsValidSignature( address signer, bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (bool success) { if (signer == address(0)) return false; if (recover(hash, r, vs) == signer) { return true; } return isValidSignature(signer, hash, r, vs); } /** * @notice Verifies the signature for a given hash, attempting to recover the signer's address or validates it using EIP-1271 for 65-byte signatures. * @dev Attempts to recover the signer's address from the signature. If the address is a contract, checks if the signature is valid according to EIP-1271. * @param signer The expected signer's address. * @param hash The keccak256 hash of the signed data. * @param r The first 32 bytes of the signature. * @param vs The last 32 bytes of the signature, with the last byte being the recovery id. * @return success True if the signature is valid, false otherwise. */ function recoverOrIsValidSignature65( address signer, bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (bool success) { if (signer == address(0)) return false; if (recover(hash, r, vs) == signer) { return true; } return isValidSignature65(signer, hash, r, vs); } /** * @notice Validates a signature for a hash using EIP-1271, if `signer` is a contract. * @dev Makes a static call to `signer` with `isValidSignature` function selector from EIP-1271. * @param signer The address of the signer to validate against, which could be an EOA or a contract. * @param hash The hash of the signed data. * @param signature The signature to validate. * @return success True if the signature is valid according to EIP-1271, false otherwise. */ function isValidSignature( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool success) { // (bool success, bytes memory data) = signer.staticcall(abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)); // return success && data.length == 32 && abi.decode(data, (bytes4)) == IERC1271.isValidSignature.selector; bytes4 selector = IERC1271.isValidSignature.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) mstore(ptr, selector) mstore(add(ptr, 0x04), hash) mstore(add(ptr, 0x24), 0x40) mstore(add(ptr, 0x44), signature.length) calldatacopy(add(ptr, 0x64), signature.offset, signature.length) if staticcall(gas(), signer, ptr, add(0x64, signature.length), 0, 0x20) { success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20)) } } } /** * @notice Validates a signature for a hash using EIP-1271, if `signer` is a contract. * @dev Makes a static call to `signer` with `isValidSignature` function selector from EIP-1271. * @param signer The address of the signer to validate against, which could be an EOA or a contract. * @param hash The hash of the signed data. * @param v The recovery byte of the signature. * @param r The first 32 bytes of the signature. * @param s The second 32 bytes of the signature. * @return success True if the signature is valid according to EIP-1271, false otherwise. */ function isValidSignature( address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal view returns (bool success) { bytes4 selector = IERC1271.isValidSignature.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) mstore(ptr, selector) mstore(add(ptr, 0x04), hash) mstore(add(ptr, 0x24), 0x40) mstore(add(ptr, 0x44), 65) mstore(add(ptr, 0x64), r) mstore(add(ptr, 0x84), s) mstore8(add(ptr, 0xa4), v) if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) { success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20)) } } } /** * @notice Validates a signature for a hash using EIP-1271, if `signer` is a contract. * @dev Makes a static call to `signer` with `isValidSignature` function selector from EIP-1271. * @param signer The address of the signer to validate against, which could be an EOA or a contract. * @param hash The hash of the signed data. * @param r The first 32 bytes of the signature. * @param vs The last 32 bytes of the signature, with the last byte being the recovery id. * @return success True if the signature is valid according to EIP-1271, false otherwise. */ function isValidSignature( address signer, bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (bool success) { // (bool success, bytes memory data) = signer.staticcall(abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, abi.encodePacked(r, vs))); // return success && data.length == 32 && abi.decode(data, (bytes4)) == IERC1271.isValidSignature.selector; bytes4 selector = IERC1271.isValidSignature.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) mstore(ptr, selector) mstore(add(ptr, 0x04), hash) mstore(add(ptr, 0x24), 0x40) mstore(add(ptr, 0x44), 64) mstore(add(ptr, 0x64), r) mstore(add(ptr, 0x84), vs) if staticcall(gas(), signer, ptr, 0xa4, 0, 0x20) { success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20)) } } } /** * @notice Verifies if a 65-byte signature is valid for a given hash, according to EIP-1271. * @param signer The address of the signer to validate against, which could be an EOA or a contract. * @param hash The hash of the signed data. * @param r The first 32 bytes of the signature. * @param vs The combined `v` (recovery id) and `s` component of the signature, packed into the last 32 bytes. * @return success True if the signature is valid according to EIP-1271, false otherwise. */ function isValidSignature65( address signer, bytes32 hash, bytes32 r, bytes32 vs ) internal view returns (bool success) { // (bool success, bytes memory data) = signer.staticcall(abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, abi.encodePacked(r, vs & ~uint256(1 << 255), uint8(vs >> 255)))); // return success && data.length == 32 && abi.decode(data, (bytes4)) == IERC1271.isValidSignature.selector; bytes4 selector = IERC1271.isValidSignature.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) mstore(ptr, selector) mstore(add(ptr, 0x04), hash) mstore(add(ptr, 0x24), 0x40) mstore(add(ptr, 0x44), 65) mstore(add(ptr, 0x64), r) mstore(add(ptr, 0x84), and(vs, _COMPACT_S_MASK)) mstore8(add(ptr, 0xa4), add(27, shr(_COMPACT_V_SHIFT, vs))) if staticcall(gas(), signer, ptr, 0xa5, 0, 0x20) { success := and(eq(selector, mload(0)), eq(returndatasize(), 0x20)) } } } /** * @notice Generates a hash compatible with Ethereum's signed message format. * @dev Prepends the hash with Ethereum's message prefix before hashing it. * @param hash The hash of the data to sign. * @return res The Ethereum signed message hash. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 res) { // 32 is the length in bytes of hash, enforced by the type signature above // return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0, 0x19457468657265756d205369676e6564204d6573736167653a0a333200000000) // "\x19Ethereum Signed Message:\n32" mstore(28, hash) res := keccak256(0, 60) } } /** * @notice Generates an EIP-712 compliant hash. * @dev Encodes the domain separator and the struct hash according to EIP-712. * @param domainSeparator The EIP-712 domain separator. * @param structHash The EIP-712 struct hash. * @return res The EIP-712 compliant hash. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 res) { // return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) mstore(ptr, 0x1901000000000000000000000000000000000000000000000000000000000000) // "\x19\x01" mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) res := keccak256(ptr, 66) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title RevertReasonForwarder * @notice Provides utilities for forwarding and retrieving revert reasons from failed external calls. */ library RevertReasonForwarder { /** * @dev Forwards the revert reason from the latest external call. * This method allows propagating the revert reason of a failed external call to the caller. */ function reRevert() internal pure { // bubble up revert reason from latest external call assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } /** * @dev Retrieves the revert reason from the latest external call. * This method enables capturing the revert reason of a failed external call for inspection or processing. * @return reason The latest external call revert reason. */ function reReason() internal pure returns (bytes memory reason) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly reason := mload(0x40) let length := returndatasize() mstore(reason, length) returndatacopy(add(reason, 0x20), 0, length) mstore(0x40, add(reason, add(0x20, length))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import "../interfaces/IDaiLikePermit.sol"; import "../interfaces/IPermit2.sol"; import "../interfaces/IERC7597Permit.sol"; import "../interfaces/IWETH.sol"; import "../libraries/RevertReasonForwarder.sol"; /** * @title Implements efficient safe methods for ERC20 interface. * @notice Compared to the standard ERC20, this implementation offers several enhancements: * 1. more gas-efficient, providing significant savings in transaction costs. * 2. support for different permit implementations * 3. forceApprove functionality * 4. support for WETH deposit and withdraw */ library SafeERC20 { error SafeTransferFailed(); error SafeTransferFromFailed(); error ForceApproveFailed(); error SafeIncreaseAllowanceFailed(); error SafeDecreaseAllowanceFailed(); error SafePermitBadLength(); error Permit2TransferAmountTooHigh(); // Uniswap Permit2 address address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857; // SafePermitBadLength.selector uint256 private constant _RAW_CALL_GAS_LIMIT = 5000; /** * @notice Fetches the balance of a specific ERC20 token held by an account. * Consumes less gas then regular `ERC20.balanceOf`. * @dev Note that the implementation does not perform dirty bits cleaning, so it is the * responsibility of the caller to make sure that the higher 96 bits of the `account` parameter are clean. * @param token The IERC20 token contract for which the balance will be fetched. * @param account The address of the account whose token balance will be fetched. * @return tokenBalance The balance of the specified ERC20 token held by the account. */ function safeBalanceOf( IERC20 token, address account ) internal view returns(uint256 tokenBalance) { bytes4 selector = IERC20.balanceOf.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0x00, selector) mstore(0x04, account) let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20) tokenBalance := mload(0) if or(iszero(success), lt(returndatasize(), 0x20)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } /** * @notice Attempts to safely transfer tokens from one address to another. * @dev If permit2 is true, uses the Permit2 standard; otherwise uses the standard ERC20 transferFrom. * Either requires `true` in return data, or requires target to be smart-contract and empty return data. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean. * @param token The IERC20 token contract from which the tokens will be transferred. * @param from The address from which the tokens will be transferred. * @param to The address to which the tokens will be transferred. * @param amount The amount of tokens to transfer. * @param permit2 If true, uses the Permit2 standard for the transfer; otherwise uses the standard ERC20 transferFrom. */ function safeTransferFromUniversal( IERC20 token, address from, address to, uint256 amount, bool permit2 ) internal { if (permit2) { safeTransferFromPermit2(token, from, to, amount); } else { safeTransferFrom(token, from, to, amount); } } /** * @notice Attempts to safely transfer tokens from one address to another using the ERC20 standard. * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean. * @param token The IERC20 token contract from which the tokens will be transferred. * @param from The address from which the tokens will be transferred. * @param to The address to which the tokens will be transferred. * @param amount The amount of tokens to transfer. */ function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { bytes4 selector = token.transferFrom.selector; bool success; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), from) mstore(add(data, 0x24), to) mstore(add(data, 0x44), amount) success := call(gas(), token, 0, data, 100, 0x0, 0x20) if success { switch returndatasize() case 0 { success := gt(extcodesize(token), 0) } default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) } } } if (!success) revert SafeTransferFromFailed(); } /** * @notice Attempts to safely transfer tokens from one address to another using the Permit2 standard. * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean. * @param token The IERC20 token contract from which the tokens will be transferred. * @param from The address from which the tokens will be transferred. * @param to The address to which the tokens will be transferred. * @param amount The amount of tokens to transfer. */ function safeTransferFromPermit2( IERC20 token, address from, address to, uint256 amount ) internal { if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh(); bytes4 selector = IPermit2.transferFrom.selector; bool success; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), from) mstore(add(data, 0x24), to) mstore(add(data, 0x44), amount) mstore(add(data, 0x64), token) success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0) if success { success := gt(extcodesize(_PERMIT2), 0) } } if (!success) revert SafeTransferFromFailed(); } /** * @notice Attempts to safely transfer tokens to another address. * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `to` parameter are clean. * @param token The IERC20 token contract from which the tokens will be transferred. * @param to The address to which the tokens will be transferred. * @param value The amount of tokens to transfer. */ function safeTransfer( IERC20 token, address to, uint256 value ) internal { if (!_makeCall(token, token.transfer.selector, to, value)) { revert SafeTransferFailed(); } } /** * @notice Attempts to approve a spender to spend a certain amount of tokens. * @dev If `approve(from, to, amount)` fails, it tries to set the allowance to zero, and retries the `approve` call. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `spender` parameter are clean. * @param token The IERC20 token contract on which the call will be made. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. */ function forceApprove( IERC20 token, address spender, uint256 value ) internal { if (!_makeCall(token, token.approve.selector, spender, value)) { if ( !_makeCall(token, token.approve.selector, spender, 0) || !_makeCall(token, token.approve.selector, spender, value) ) { revert ForceApproveFailed(); } } } /** * @notice Safely increases the allowance of a spender. * @dev Increases with safe math check. Checks if the increased allowance will overflow, if yes, then it reverts the transaction. * Then uses `forceApprove` to increase the allowance. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `spender` parameter are clean. * @param token The IERC20 token contract on which the call will be made. * @param spender The address which will spend the funds. * @param value The amount of tokens to increase the allowance by. */ function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 allowance = token.allowance(address(this), spender); if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed(); forceApprove(token, spender, allowance + value); } /** * @notice Safely decreases the allowance of a spender. * @dev Decreases with safe math check. Checks if the decreased allowance will underflow, if yes, then it reverts the transaction. * Then uses `forceApprove` to increase the allowance. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `spender` parameter are clean. * @param token The IERC20 token contract on which the call will be made. * @param spender The address which will spend the funds. * @param value The amount of tokens to decrease the allowance by. */ function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 allowance = token.allowance(address(this), spender); if (value > allowance) revert SafeDecreaseAllowanceFailed(); forceApprove(token, spender, allowance - value); } /** * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters. * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2). * @dev Wraps `tryPermit` function and forwards revert reason if permit fails. * @param token The IERC20 token to execute the permit function on. * @param permit The permit data to be used in the function call. */ function safePermit(IERC20 token, bytes calldata permit) internal { if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert(); } /** * @notice Attempts to execute the `permit` function on the provided token with custom owner and spender parameters. * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2). * @dev Wraps `tryPermit` function and forwards revert reason if permit fails. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean. * @param token The IERC20 token to execute the permit function on. * @param owner The owner of the tokens for which the permit is made. * @param spender The spender allowed to spend the tokens by the permit. * @param permit The permit data to be used in the function call. */ function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal { if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert(); } /** * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters. * @dev Invokes `tryPermit` with sender as owner and contract as spender. * @param token The IERC20 token to execute the permit function on. * @param permit The permit data to be used in the function call. * @return success Returns true if the permit function was successfully executed, false otherwise. */ function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) { return tryPermit(token, msg.sender, address(this), permit); } /** * @notice The function attempts to call the permit function on a given ERC20 token. * @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, IERC7597Permit and IPermit2. * It accommodates both Compact and Full formats of these permit types. * Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter * for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by * gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and * zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one * before invocation for optimized performance. * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean. * @param token The address of the ERC20 token on which to call the permit function. * @param owner The owner of the tokens. This address should have signed the off-chain permit. * @param spender The address which will be approved for transfer of tokens. * @param permit The off-chain permit data, containing different fields depending on the type of permit function. * @return success A boolean indicating whether the permit call was successful. */ function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) { // load function selectors for different permit standards bytes4 permitSelector = IERC20Permit.permit.selector; bytes4 daiPermitSelector = IDaiLikePermit.permit.selector; bytes4 permit2Selector = IPermit2.permit.selector; bytes4 erc7597PermitSelector = IERC7597Permit.permit.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let ptr := mload(0x40) // Switch case for different permit lengths, indicating different permit standards switch permit.length // Compact IERC20Permit case 100 { mstore(ptr, permitSelector) // store selector mstore(add(ptr, 0x04), owner) // store owner mstore(add(ptr, 0x24), spender) // store spender // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs) { // stack too deep let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23 let vs := calldataload(add(permit.offset, 0x44)) // loads permit.offset 0x44..0x63 calldatacopy(add(ptr, 0x44), permit.offset, 0x20) // store value = copy permit.offset 0x00..0x19 mstore(add(ptr, 0x64), sub(deadline, 1)) // store deadline = deadline - 1 mstore(add(ptr, 0x84), add(27, shr(255, vs))) // store v = most significant bit of vs + 27 (27 or 28) calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r = copy permit.offset 0x24..0x43 mstore(add(ptr, 0xc4), shr(1, shl(1, vs))) // store s = vs without most significant bit } // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0xe4, 0, 0) } // Compact IDaiLikePermit case 72 { mstore(ptr, daiPermitSelector) // store selector mstore(add(ptr, 0x04), owner) // store owner mstore(add(ptr, 0x24), spender) // store spender // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs) { // stack too deep let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07 let vs := calldataload(add(permit.offset, 0x28)) // loads permit.offset 0x28..0x47 mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce = copy permit.offset 0x00..0x03 mstore(add(ptr, 0x64), sub(expiry, 1)) // store expiry = expiry - 1 mstore(add(ptr, 0x84), true) // store allowed = true mstore(add(ptr, 0xa4), add(27, shr(255, vs))) // store v = most significant bit of vs + 27 (27 or 28) calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20) // store r = copy permit.offset 0x08..0x27 mstore(add(ptr, 0xe4), shr(1, shl(1, vs))) // store s = vs without most significant bit } // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0x104, 0, 0) } // IERC20Permit case 224 { mstore(ptr, permitSelector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0xe4, 0, 0) } // IDaiLikePermit case 256 { mstore(ptr, daiPermitSelector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) success := call(gas(), token, 0, ptr, 0x104, 0, 0) } // Compact IPermit2 case 96 { // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs) mstore(ptr, permit2Selector) // store selector mstore(add(ptr, 0x04), owner) // store owner mstore(add(ptr, 0x24), token) // store token calldatacopy(add(ptr, 0x50), permit.offset, 0x14) // store amount = copy permit.offset 0x00..0x13 // and(0xffffffffffff, ...) - conversion to uint48 mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff) mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b mstore(add(ptr, 0xa4), spender) // store spender // and(0xffffffffffff, ...) - conversion to uint48 mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff) mstore(add(ptr, 0xe4), 0x100) // store offset = 256 mstore(add(ptr, 0x104), 0x40) // store length = 64 calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r = copy permit.offset 0x20..0x3f calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs = copy permit.offset 0x40..0x5f // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature) success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0) } // IPermit2 case 352 { mstore(ptr, permit2Selector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature) success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0) } // Dynamic length default { mstore(ptr, erc7597PermitSelector) calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata // IERC7597Permit.permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) success := call(gas(), token, 0, ptr, add(permit.length, 4), 0, 0) } } } /** * @dev Executes a low level call to a token contract, making it resistant to reversion and erroneous boolean returns. * @param token The IERC20 token contract on which the call will be made. * @param selector The function signature that is to be called on the token contract. * @param to The address to which the token amount will be transferred. * @param amount The token amount to be transferred. * @return success A boolean indicating if the call was successful. Returns 'true' on success and 'false' on failure. * In case of success but no returned data, validates that the contract code exists. * In case of returned data, ensures that it's a boolean `true`. */ function _makeCall( IERC20 token, bytes4 selector, address to, uint256 amount ) private returns (bool success) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly let data := mload(0x40) mstore(data, selector) mstore(add(data, 0x04), to) mstore(add(data, 0x24), amount) success := call(gas(), token, 0, data, 0x44, 0x0, 0x20) if success { switch returndatasize() case 0 { success := gt(extcodesize(token), 0) } default { success := and(gt(returndatasize(), 31), eq(mload(0), 1)) } } } } /** * @notice Safely deposits a specified amount of Ether into the IWETH contract. Consumes less gas then regular `IWETH.deposit`. * @param weth The IWETH token contract. * @param amount The amount of Ether to deposit into the IWETH contract. */ function safeDeposit(IWETH weth, uint256 amount) internal { if (amount > 0) { bytes4 selector = IWETH.deposit.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0, selector) if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } } /** * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract. Consumes less gas then regular `IWETH.withdraw`. * @dev Uses inline assembly to interact with the IWETH contract. * @param weth The IWETH token contract. * @param amount The amount of wrapped Ether to withdraw from the IWETH contract. */ function safeWithdraw(IWETH weth, uint256 amount) internal { bytes4 selector = IWETH.withdraw.selector; assembly ("memory-safe") { // solhint-disable-line no-inline-assembly mstore(0, selector) mstore(4, amount) if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } /** * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract to a specified recipient. * Consumes less gas then regular `IWETH.withdraw`. * @param weth The IWETH token contract. * @param amount The amount of wrapped Ether to withdraw from the IWETH contract. * @param to The recipient of the withdrawn Ether. */ function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal { safeWithdraw(weth, amount); if (to != address(this)) { assembly ("memory-safe") { // solhint-disable-line no-inline-assembly if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1271.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @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.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @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 pragma solidity 0.8.23; import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IWETH } from "@1inch/solidity-utils/contracts/interfaces/IWETH.sol"; import { RevertReasonForwarder } from "@1inch/solidity-utils/contracts/libraries/RevertReasonForwarder.sol"; import { SafeERC20 } from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol"; import { IBalanceManager } from "./interfaces/IBalanceManager.sol"; /* solhint-disable avoid-low-level-calls */ abstract contract BalanceManager is IERC1271, IBalanceManager { using SafeERC20 for IERC20; using SafeERC20 for IWETH; IWETH internal immutable _WETH; constructor(IWETH weth) { if (address(weth) == address(0)) revert ZeroAddress(); _WETH = weth; } modifier onlyOwner() virtual; receive() external payable {} // solhint-disable-line no-empty-blocks; /** * @notice See {IBalanceManager-arbitraryCalls}. */ function arbitraryCalls(address[] calldata targets, bytes[] calldata arguments) public payable { uint256[] calldata values; // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { values.offset := calldatasize() values.length := arguments.length } arbitraryCalls(targets, arguments, values); } /** * @notice See {IBalanceManager-arbitraryCalls}. */ function arbitraryCalls(address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values) public payable onlyOwner { unchecked { uint256 length = targets.length; if (length != arguments.length) revert LengthMismatch(); if (length != values.length) revert LengthMismatch(); for (uint256 i = 0; i < length; ++i) { // solhint-disable-next-line avoid-low-level-calls (bool success,) = targets[i].call{value: values[i]}(arguments[i]); if (!success) RevertReasonForwarder.reRevert(); } } } /** * @notice See {IBalanceManager-arbitraryCallsWithEthCheck}. */ function arbitraryCallsWithEthCheck(address[] calldata targets, bytes[] calldata arguments, uint256 minReturn) external payable { uint256[] calldata values; // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { values.offset := calldatasize() values.length := arguments.length } arbitraryCallsWithEthCheck(targets, arguments, values, minReturn); } /** * @notice See {IBalanceManager-arbitraryCallsWithEthCheck}. */ function arbitraryCallsWithEthCheck( address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values, uint256 minReturn ) public payable { address target = _targetToCheck(); uint256 balanceBefore = target.balance; arbitraryCalls(targets, arguments, values); if (target.balance < minReturn + balanceBefore) revert NotEnoughProfit(); } /** * @notice See {IBalanceManager-arbitraryCallsWithTokenCheck}. */ function arbitraryCallsWithTokenCheck( address[] calldata targets, bytes[] calldata arguments, IERC20 token, uint256 minReturn ) external payable { uint256[] calldata values; // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { values.offset := calldatasize() values.length := arguments.length } arbitraryCallsWithTokenCheck(targets, arguments, values, token, minReturn); } /** * @notice See {IBalanceManager-arbitraryCallsWithTokenCheck}. */ function arbitraryCallsWithTokenCheck( address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values, IERC20 token, uint256 minReturn ) public payable { address target = _targetToCheck(); uint256 balanceBefore = token.balanceOf(target); arbitraryCalls(targets, arguments, values); if (token.balanceOf(target) < minReturn + balanceBefore) revert NotEnoughProfit(); } /** * @notice See {IBalanceManager-estimateArbitraryCalls}. */ function estimateArbitraryCalls(address[] calldata targets, bytes[] calldata arguments) external payable { uint256[] calldata values; // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { values.offset := calldatasize() values.length := arguments.length } estimateArbitraryCalls(targets, arguments, values); } /** * @notice See {IBalanceManager-estimateArbitraryCalls}. */ function estimateArbitraryCalls(address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values) public payable onlyOwner { unchecked { uint256 length = targets.length; if (length != arguments.length) revert LengthMismatch(); bool[] memory statuses = new bool[](length); bytes[] memory results = new bytes[](length); for (uint256 i = 0; i < length; i++) { // solhint-disable-next-line avoid-low-level-calls (statuses[i], results[i]) = targets[i].call{value: values[i]}(arguments[i]); } revert EstimationResults(statuses, results); } } /** * @notice See {IBalanceManager-approve}. */ function approve(IERC20 token, address to) external onlyOwner { token.forceApprove(to, type(uint256).max); } /** * @notice See {IBalanceManager-transfer}. */ function transfer(IERC20 token, address to, uint256 amount) external onlyOwner { token.safeTransfer(to, amount); } /** * @notice See {IBalanceManager-batchApprove}. */ function batchApprove(bytes calldata data) external onlyOwner { unchecked { uint256 length = data.length; if (length % 40 != 0) revert InvalidLength(); for (uint256 i = 0; i < length; i += 40) { IERC20(address(bytes20(data[i:i+20]))).forceApprove(address(bytes20(data[i+20:i+40])), type(uint256).max); } } } /** * @notice See {IBalanceManager-batchTransfer}. */ function batchTransfer(bytes calldata data) external onlyOwner { unchecked { uint256 length = data.length; if (length % 72 != 0) revert InvalidLength(); for (uint256 i = 0; i < length; i += 72) { IERC20 token = IERC20(address(bytes20(data[i:i+20]))); address target = address(bytes20(data[i+20:i+40])); uint256 amount = uint256(bytes32(data[i+40:i+72])); token.safeTransfer(target, amount); } } } /** * @notice See {IBalanceManager-unwrapTo}. */ function unwrapTo(address payable receiver, uint256 amount) external onlyOwner { _WETH.safeWithdrawTo(amount, receiver); } /** * @notice See {IBalanceManager-rescueEther}. */ function rescueEther() external onlyOwner { (bool success, ) = payable(msg.sender).call{value: address(this).balance}(""); if (!success) revert ETHTransferFailed(); } function _targetToCheck() internal view virtual returns (address); } /* solhint-enable avoid-low-level-calls */
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Interface to manage contract balance. */ interface IBalanceManager{ error EstimationResults(bool[] statuses, bytes[] results); error ETHTransferFailed(); error InvalidLength(); error LengthMismatch(); error NotEnoughProfit(); error OnlyOwner(); error ZeroAddress(); /** * @notice Execute arbitrary calls. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. */ function arbitraryCalls(address[] calldata targets, bytes[] calldata arguments) external payable; /** * @notice Execute arbitrary calls. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @param values Values to send to each contract. */ function arbitraryCalls(address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values) external payable; /** * @notice Execute arbitrary calls and check the ETH balance after. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @param minReturn Minimum amount of ETH balance after all calls. */ function arbitraryCallsWithEthCheck(address[] calldata targets, bytes[] calldata arguments, uint256 minReturn) external payable; /** * @notice Execute arbitrary calls and check the ETH balance after. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @param values Values to send to each contract. * @param minReturn Minimum amount of ETH balance after all calls. */ function arbitraryCallsWithEthCheck( address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values, uint256 minReturn ) external payable; /** * @notice Execute arbitrary calls and check the token balance after. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @param token Token to check the balance of. * @param minReturn Minimum amount of token balance after all calls. */ function arbitraryCallsWithTokenCheck( address[] calldata targets, bytes[] calldata arguments, IERC20 token, uint256 minReturn ) external payable; /** * @notice Execute arbitrary calls and check the token balance after. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @param values Values to send to each contract. * @param token Token to check the balance of. * @param minReturn Minimum amount of token balance after all calls. */ function arbitraryCallsWithTokenCheck( address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values, IERC20 token, uint256 minReturn ) external payable; /** * @notice Estimate the results of arbitrary calls. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @dev This function reverts results with `EstimationResults` error. */ function estimateArbitraryCalls(address[] calldata targets, bytes[] calldata arguments) external payable; /** * @notice Estimate the results of arbitrary calls. * @param targets Addresses of the contracts to call. * @param arguments Data to send to each contract. * @param values Values to send to each contract. * @dev This function reverts results with `EstimationResults` error. */ function estimateArbitraryCalls(address[] calldata targets, bytes[] calldata arguments, uint256[] calldata values) external payable; /** * @notice Approves a spender to spend an infinite amount of tokens. * @param token The IERC20 token contract on which the call will be made. * @param to The address which will spend the funds. */ function approve(IERC20 token, address to) external; /** * @notice Transfers a certain amount of tokens to a recipient. * @param token The IERC20 token contract on which the call will be made. * @param to The address which will receive the funds. * @param amount The amount of tokens to transfer. */ function transfer(IERC20 token, address to, uint256 amount) external; /** * @notice Batch approves a spender to spend an infinite amount of multiple tokens. * @param data The data containing the token addresses and the respective spender addresses. */ function batchApprove(bytes calldata data) external; /** * @notice Batch transfers multiple tokens to the respective recipients. * @param data The data containing the token addresses, recipients and amounts. */ function batchTransfer(bytes calldata data) external; /** * @notice Unwrap the contract's WETH balance to a recipient. * @param receiver The address which will receive ETH. * @param amount The amount of tokens to unwrap. */ function unwrapTo(address payable receiver, uint256 amount) external; /** * @notice Rescue all ETH from the contract. */ function rescueEther() external; } /* solhint-enable avoid-low-level-calls */
{ "optimizer": { "enabled": true, "runs": 1000000 }, "evmVersion": "shanghai", "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IWETH","name":"weth","type":"address"},{"internalType":"address","name":"lop","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[{"internalType":"bool[]","name":"statuses","type":"bool[]"},{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"name":"EstimationResults","type":"error"},{"inputs":[],"name":"ForceApproveFailed","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"NotEnoughProfit","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOperator","type":"address"}],"name":"OperatorChanged","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"}],"name":"arbitraryCalls","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"arbitraryCalls","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"},{"internalType":"uint256","name":"minReturn","type":"uint256"}],"name":"arbitraryCallsWithEthCheck","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"uint256","name":"minReturn","type":"uint256"}],"name":"arbitraryCallsWithEthCheck","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"minReturn","type":"uint256"}],"name":"arbitraryCallsWithTokenCheck","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"minReturn","type":"uint256"}],"name":"arbitraryCallsWithTokenCheck","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"batchApprove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"batchTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"estimateArbitraryCalls","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bytes[]","name":"arguments","type":"bytes[]"}],"name":"estimateArbitraryCalls","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rescueEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrapTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e034620000e057601f62001cac38819003918201601f19168301916001600160401b03831184841017620000e457808492606094604052833981010312620000e05780516001600160a01b0380821691828103620000e0576200007460406200006c60208701620000f8565b9501620000f8565b9215620000c25760805280821615908115620000d4575b50620000c25760a05260c052604051611b9e90816200010e823960805181610168015260a0518161057a015260c05181610eb10152f35b60405163d92e233d60e01b8152600490fd5b90508216155f6200008b565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620000e05756fe60406080815260048036101561001e575b5050361561001c575f80fd5b005b5f3560e01c8063038ec2ab146110ed57806310a890af14610fb15780631626ba7e14610e435780631f3177ba14610dac57806320969d0714610cfa578063295861b114610a4a578063343590a41461095e5780633a9d666f146108c75780633d006abd146108545780634cbdf31c146107c8578063570ca735146107775780637e5465ba1461070e57806385c014381461061e578063b3ab15fb14610528578063bdbb216a1461027c578063beabacc8146101e65763c12ea3ca0361001057346101e257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e257803573ffffffffffffffffffffffffffffffffffffffff918282168092036101e257602435925f541633036101bb5782907f2e1a7d4d000000000000000000000000000000000000000000000000000000005f52525f80602481807f00000000000000000000000000000000000000000000000000000000000000005af1156101b15730810361019757005b5f8080938193611388f1156101a857005b513d5f823e3d90fd5b82513d5f823e3d90fd5b83517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5f80fd5b5090346101e25760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25761021f6111ca565b90610228611304565b9073ffffffffffffffffffffffffffffffffffffffff5f541633036102545761001c60443583856118bd565b8390517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b506102863661121b565b9092919373ffffffffffffffffffffffffffffffffffffffff5f54163303610501578185036104da57949392906102bc846116aa565b956102c986519788611327565b8487526102d5856116aa565b93602092838901947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080970136873761030d886116aa565b9761031a8a51998a611327565b80895287610327826116aa565b015f5b8181106104cb5750505f5b81811061045357505050505085519687967f9cb0e09d0000000000000000000000000000000000000000000000000000000088526044880192880152518091526064860192905f5b81811061043a575050507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160248601528351908183528083019281808460051b8301019601945f915b8483106103d75788880389fd5b919395975091939582828203018752848389518051908185525f5b828110610423575050838392601f835f86809660019a010152011601019901970193019091889796959394926103ca565b8181018501518682018601528994889450016103f2565b825115158552889750938301939183019160010161037d565b805f808d9e98999a9c9d61047261046d600196888c6116c2565b6116ff565b9061047e858a366116c2565b3561048a868b8b611720565b8093519384928337810185815203925af18c6104ae836104a861164d565b92611780565b526104b98289611780565b9015159052019a99989695949a610335565b60608b8201890152870161032a565b85517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b85517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5090346101e25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e2576105616111ca565b73ffffffffffffffffffffffffffffffffffffffff92837f00000000000000000000000000000000000000000000000000000000000000001633036105f7577f4721129e0e676ed6a92909bb24e853ccdd63ad72280cc2e974e38e480e0e6e5460208486851690817fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f5551908152a1005b82517f4ca88867000000000000000000000000000000000000000000000000000000008152fd5b5061062836611284565b9573ffffffffffffffffffffffffffffffffffffffff5f969592949396541633036106e7578582036106c0578682036106c057505f5b81811061066757005b5f8061067761046d84868a6116c2565b8a610683858c8a6116c2565b3561068f868c8a611720565b8093519384928337810185815203925af16106a861164d565b50156106b65760010161065e565b87513d5f823e3d90fd5b87517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b87517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5090346101e257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e2576107466111ca565b61074e611304565b9173ffffffffffffffffffffffffffffffffffffffff5f541633036102545761001c8383611a23565b82346101e2575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25760209073ffffffffffffffffffffffffffffffffffffffff5f54169051908152f35b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e2576108129036908401611199565b6024929192358281116101e25761082c9036908601611199565b90926044359081116101e25761001c9561084891369101611199565b93909260643595611794565b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e25761089e9036908401611199565b916024359081116101e25761001c936108b991369101611199565b809291604435943693611794565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e2576109119036908401611199565b9190926024359182116101e25761092a91369101611199565b6044939193359173ffffffffffffffffffffffffffffffffffffffff831683036101e2578161001c956064359536936113cf565b50346101e25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e257803567ffffffffffffffff81116101e2576109ac90369083016111ed565b9173ffffffffffffffffffffffffffffffffffffffff5f541633036101bb5760289360288406610a245750505f5b8281106109e357005b80610a1e6014869301610a016109fb828589896115f1565b90611609565b610a156109fb606093878701908a8a6115f1565b821c911c611a23565b016109da565b517f947d5a84000000000000000000000000000000000000000000000000000000008152fd5b50610a5436611284565b9473ffffffffffffffffffffffffffffffffffffffff5f979394959754163303610cd257838703610caa57610a8e879694939298976116aa565b97610a9b8851998a611327565b868952610aa7876116aa565b95602094858b01967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0809901368937610adf8a6116aa565b99610aec8c519b8c611327565b808b5289610af9826116aa565b015f5b818110610c9b5750505f5b818110610c27575050505050505085519687967f9cb0e09d0000000000000000000000000000000000000000000000000000000088526044880192880152518091526064860192905f5b818110610c0e575050507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160248601528351908183528083019281808460051b8301019601945f915b848310610bab5788880389fd5b919395975091939582828203018752848389518051908185525f5b828110610bf7575050838392601f835f86809660019a01015201160101990197019301909188979695939492610b9e565b818101850151868201860152899488945001610bc6565b8251151585528897509383019391830191600101610b51565b808c8e9f999a9b9d9e5f8981928a610c60878f610c59828f928f908f60019f61046d91610c53936116c2565b986116c2565b3593611720565b8093519384928337810185815203925af190610c7e836104a861164d565b52610c89828b611780565b9015159052019c9b9a9897969c610b07565b60608d82018b01528901610afc565b8288517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8288517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5090346101e2575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25773ffffffffffffffffffffffffffffffffffffffff5f54163303610d86575f80808047335af1610d5861164d565b5015610d6057005b517fb12d13eb000000000000000000000000000000000000000000000000000000008152fd5b517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b50610db63661121b565b909373ffffffffffffffffffffffffffffffffffffffff5f54163303610501578183036104da57505f5b828110610de957005b5f80610df961046d8487896116c2565b610e048486366116c2565b35610e1085878b611720565b9190828c519384928337810185815203925af1610e2b61164d565b5015610e3957600101610de0565b85513d5f823e3d90fd5b50346101e257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25780359167ffffffffffffffff6024358181116101e257610e9590369085016111ed565b945f9473ffffffffffffffffffffffffffffffffffffffff93337f0000000000000000000000000000000000000000000000000000000000000000861603610f4557505094610ee691602096611955565b905b805f5416911614610f1d575b7fffffffff00000000000000000000000000000000000000000000000000000000905191168152f35b7f1626ba7e000000000000000000000000000000000000000000000000000000009150610ef4565b855191602083019384523060601b8784015260348352606083019183831090831117610f8557508552519020602095610f7f929091611955565b90610ee8565b6041907f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b50346101e25760209060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e257803567ffffffffffffffff81116101e25761100290369083016111ed565b92909173ffffffffffffffffffffffffffffffffffffffff5f541633036110c65760489460488506610a245750505f5b83811061103b57005b8061108e60148793016110536109fb82858a8a6115f1565b9060609161107b61106d6109fb6028880180958d8d6115f1565b841c92878701908b8b6115f1565b93903593888110611094575b501c6118bd565b01611032565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90890360031b1b909316925f611087565b84517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e2576111379036908401611199565b9290916024358181116101e2576111519036908401611199565b9190926044359182116101e25761116a91369101611199565b916064359373ffffffffffffffffffffffffffffffffffffffff851685036101e25761001c96608435966113cf565b9181601f840112156101e25782359167ffffffffffffffff83116101e2576020808501948460051b0101116101e257565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101e257565b9181601f840112156101e25782359167ffffffffffffffff83116101e257602083818601950101116101e257565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101e25767ffffffffffffffff916004358381116101e2578261126691600401611199565b939093926024359182116101e25761128091600401611199565b9091565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126101e25767ffffffffffffffff6004358181116101e257836112cf91600401611199565b939093926024358381116101e257826112ea91600401611199565b939093926044359182116101e25761128091600401611199565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101e257565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761136857604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b919082018092116113a257565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b969490969593919573ffffffffffffffffffffffffffffffffffffffff809516926040978851957f70a08231000000000000000000000000000000000000000000000000000000009485885260049b308d8a01526020998a8a6024818c5afa998a156115e7575f9a6115b8575b505f5416330361159057828103611568578181036115685790899695949392915f5b8d8282106114fa57955050505050506024915051809481938252308b8301525afa928315610e39575f936114c8575b50506114999192611395565b116114a2575050565b517f3b5c3088000000000000000000000000000000000000000000000000000000008152fd5b90809350813d83116114f3575b6114df8183611327565b810103126101e2576114999151915f61148d565b503d6114d5565b879899505f919293949596979061151661046d858786956116c2565b9061152285888c6116c2565b3561152e868a8c611720565b8093519384928337810185815203925af161154761164d565b501561155e57600101908a9796959493929161145e565b8c513d5f823e3d90fd5b8c8c517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8c8c517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b9099508a81813d83116115e0575b6115d08183611327565b810103126101e25751985f61143c565b503d6115c6565b8d513d5f823e3d90fd5b909392938483116101e25784116101e2578101920390565b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000903581811693926014811061163e57505050565b60140360031b82901b16169150565b3d156116a5573d9067ffffffffffffffff8211611368576040519161169a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611327565b82523d5f602084013e565b606090565b67ffffffffffffffff81116113685760051b60200190565b91908110156116d25760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b3573ffffffffffffffffffffffffffffffffffffffff811681036101e25790565b91908110156116d25760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101e257019081359167ffffffffffffffff83116101e25760200182360381136101e2579190565b80518210156116d25760209160051b010190565b929094939193479573ffffffffffffffffffffffffffffffffffffffff5f541633036118935782810361186957818103611869575f5b81811061181457505050505050506117e3904792611395565b116117ea57565b60046040517f3b5c3088000000000000000000000000000000000000000000000000000000008152fd5b61182261046d8284896116c2565b5f8061182f84878a6116c2565b359261183c85898d611720565b90946040958287519384928337810185815203925af161185a61164d565b50156101a857506001016117ca565b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b9160446020925f92604051917fa9059cbb0000000000000000000000000000000000000000000000000000000083526004830152602482015282855af19081611933575b501561190957565b60046040517ffb7f5079000000000000000000000000000000000000000000000000000000008152fd5b90503d1561194d575060015f5114601f3d11165b5f611901565b3b1515611947565b6040515f94939092908360418214611a0a57506040146119c557505f9150815b61197d575050565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16060830151106119ac575050565b6020929350816080915f935282805260015afa505f5190565b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160208086940135918260ff1c601b01828601526040850137166060820152611975565b9160408092508101355f1a602084015281830137611975565b90611a2e8183611ae4565b15611a37575050565b60205f60446040517f095ea7b300000000000000000000000000000000000000000000000000000000815284600482015282602482015282865af180611ac5575b15918215611ab3575b5050611a8957565b60046040517f19be9a90000000000000000000000000000000000000000000000000000000008152fd5b611abd9250611ae4565b155f80611a81565b503d15611adb5760015f5114601f3d1116611a78565b813b1515611a78565b91905f6044602092604051907f095ea7b300000000000000000000000000000000000000000000000000000000825260048201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602482015282865af19182611b4b5750565b9091503d15611b62575060015f5114601f3d111690565b3b15159056fea26469706673582212204cbb3dfe31505132acc9a669238f9a8ba44b9beb10c8dc4b4b7c8eb00f5ba5fc64736f6c634300081700330000000000000000000000004200000000000000000000000000000000000006000000000000000000000000111111125421ca6dc452d289314280a0f8842a65000000000000000000000000a4659995dc39d891c1ba9131aaf5f000e5b57224
Deployed Bytecode
0x60406080815260048036101561001e575b5050361561001c575f80fd5b005b5f3560e01c8063038ec2ab146110ed57806310a890af14610fb15780631626ba7e14610e435780631f3177ba14610dac57806320969d0714610cfa578063295861b114610a4a578063343590a41461095e5780633a9d666f146108c75780633d006abd146108545780634cbdf31c146107c8578063570ca735146107775780637e5465ba1461070e57806385c014381461061e578063b3ab15fb14610528578063bdbb216a1461027c578063beabacc8146101e65763c12ea3ca0361001057346101e257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e257803573ffffffffffffffffffffffffffffffffffffffff918282168092036101e257602435925f541633036101bb5782907f2e1a7d4d000000000000000000000000000000000000000000000000000000005f52525f80602481807f00000000000000000000000042000000000000000000000000000000000000065af1156101b15730810361019757005b5f8080938193611388f1156101a857005b513d5f823e3d90fd5b82513d5f823e3d90fd5b83517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5f80fd5b5090346101e25760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25761021f6111ca565b90610228611304565b9073ffffffffffffffffffffffffffffffffffffffff5f541633036102545761001c60443583856118bd565b8390517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b506102863661121b565b9092919373ffffffffffffffffffffffffffffffffffffffff5f54163303610501578185036104da57949392906102bc846116aa565b956102c986519788611327565b8487526102d5856116aa565b93602092838901947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe080970136873761030d886116aa565b9761031a8a51998a611327565b80895287610327826116aa565b015f5b8181106104cb5750505f5b81811061045357505050505085519687967f9cb0e09d0000000000000000000000000000000000000000000000000000000088526044880192880152518091526064860192905f5b81811061043a575050507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160248601528351908183528083019281808460051b8301019601945f915b8483106103d75788880389fd5b919395975091939582828203018752848389518051908185525f5b828110610423575050838392601f835f86809660019a010152011601019901970193019091889796959394926103ca565b8181018501518682018601528994889450016103f2565b825115158552889750938301939183019160010161037d565b805f808d9e98999a9c9d61047261046d600196888c6116c2565b6116ff565b9061047e858a366116c2565b3561048a868b8b611720565b8093519384928337810185815203925af18c6104ae836104a861164d565b92611780565b526104b98289611780565b9015159052019a99989695949a610335565b60608b8201890152870161032a565b85517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b85517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5090346101e25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e2576105616111ca565b73ffffffffffffffffffffffffffffffffffffffff92837f000000000000000000000000a4659995dc39d891c1ba9131aaf5f000e5b572241633036105f7577f4721129e0e676ed6a92909bb24e853ccdd63ad72280cc2e974e38e480e0e6e5460208486851690817fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f5551908152a1005b82517f4ca88867000000000000000000000000000000000000000000000000000000008152fd5b5061062836611284565b9573ffffffffffffffffffffffffffffffffffffffff5f969592949396541633036106e7578582036106c0578682036106c057505f5b81811061066757005b5f8061067761046d84868a6116c2565b8a610683858c8a6116c2565b3561068f868c8a611720565b8093519384928337810185815203925af16106a861164d565b50156106b65760010161065e565b87513d5f823e3d90fd5b87517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b87517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5090346101e257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e2576107466111ca565b61074e611304565b9173ffffffffffffffffffffffffffffffffffffffff5f541633036102545761001c8383611a23565b82346101e2575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25760209073ffffffffffffffffffffffffffffffffffffffff5f54169051908152f35b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e2576108129036908401611199565b6024929192358281116101e25761082c9036908601611199565b90926044359081116101e25761001c9561084891369101611199565b93909260643595611794565b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e25761089e9036908401611199565b916024359081116101e25761001c936108b991369101611199565b809291604435943693611794565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e2576109119036908401611199565b9190926024359182116101e25761092a91369101611199565b6044939193359173ffffffffffffffffffffffffffffffffffffffff831683036101e2578161001c956064359536936113cf565b50346101e25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e257803567ffffffffffffffff81116101e2576109ac90369083016111ed565b9173ffffffffffffffffffffffffffffffffffffffff5f541633036101bb5760289360288406610a245750505f5b8281106109e357005b80610a1e6014869301610a016109fb828589896115f1565b90611609565b610a156109fb606093878701908a8a6115f1565b821c911c611a23565b016109da565b517f947d5a84000000000000000000000000000000000000000000000000000000008152fd5b50610a5436611284565b9473ffffffffffffffffffffffffffffffffffffffff5f979394959754163303610cd257838703610caa57610a8e879694939298976116aa565b97610a9b8851998a611327565b868952610aa7876116aa565b95602094858b01967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0809901368937610adf8a6116aa565b99610aec8c519b8c611327565b808b5289610af9826116aa565b015f5b818110610c9b5750505f5b818110610c27575050505050505085519687967f9cb0e09d0000000000000000000000000000000000000000000000000000000088526044880192880152518091526064860192905f5b818110610c0e575050507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8583030160248601528351908183528083019281808460051b8301019601945f915b848310610bab5788880389fd5b919395975091939582828203018752848389518051908185525f5b828110610bf7575050838392601f835f86809660019a01015201160101990197019301909188979695939492610b9e565b818101850151868201860152899488945001610bc6565b8251151585528897509383019391830191600101610b51565b808c8e9f999a9b9d9e5f8981928a610c60878f610c59828f928f908f60019f61046d91610c53936116c2565b986116c2565b3593611720565b8093519384928337810185815203925af190610c7e836104a861164d565b52610c89828b611780565b9015159052019c9b9a9897969c610b07565b60608d82018b01528901610afc565b8288517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8288517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5090346101e2575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25773ffffffffffffffffffffffffffffffffffffffff5f54163303610d86575f80808047335af1610d5861164d565b5015610d6057005b517fb12d13eb000000000000000000000000000000000000000000000000000000008152fd5b517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b50610db63661121b565b909373ffffffffffffffffffffffffffffffffffffffff5f54163303610501578183036104da57505f5b828110610de957005b5f80610df961046d8487896116c2565b610e048486366116c2565b35610e1085878b611720565b9190828c519384928337810185815203925af1610e2b61164d565b5015610e3957600101610de0565b85513d5f823e3d90fd5b50346101e257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25780359167ffffffffffffffff6024358181116101e257610e9590369085016111ed565b945f9473ffffffffffffffffffffffffffffffffffffffff93337f000000000000000000000000111111125421ca6dc452d289314280a0f8842a65861603610f4557505094610ee691602096611955565b905b805f5416911614610f1d575b7fffffffff00000000000000000000000000000000000000000000000000000000905191168152f35b7f1626ba7e000000000000000000000000000000000000000000000000000000009150610ef4565b855191602083019384523060601b8784015260348352606083019183831090831117610f8557508552519020602095610f7f929091611955565b90610ee8565b6041907f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b50346101e25760209060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e257803567ffffffffffffffff81116101e25761100290369083016111ed565b92909173ffffffffffffffffffffffffffffffffffffffff5f541633036110c65760489460488506610a245750505f5b83811061103b57005b8061108e60148793016110536109fb82858a8a6115f1565b9060609161107b61106d6109fb6028880180958d8d6115f1565b841c92878701908b8b6115f1565b93903593888110611094575b501c6118bd565b01611032565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90890360031b1b909316925f611087565b84517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101e25767ffffffffffffffff81358181116101e2576111379036908401611199565b9290916024358181116101e2576111519036908401611199565b9190926044359182116101e25761116a91369101611199565b916064359373ffffffffffffffffffffffffffffffffffffffff851685036101e25761001c96608435966113cf565b9181601f840112156101e25782359167ffffffffffffffff83116101e2576020808501948460051b0101116101e257565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101e257565b9181601f840112156101e25782359167ffffffffffffffff83116101e257602083818601950101116101e257565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101e25767ffffffffffffffff916004358381116101e2578261126691600401611199565b939093926024359182116101e25761128091600401611199565b9091565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126101e25767ffffffffffffffff6004358181116101e257836112cf91600401611199565b939093926024358381116101e257826112ea91600401611199565b939093926044359182116101e25761128091600401611199565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101e257565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761136857604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b919082018092116113a257565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b969490969593919573ffffffffffffffffffffffffffffffffffffffff809516926040978851957f70a08231000000000000000000000000000000000000000000000000000000009485885260049b308d8a01526020998a8a6024818c5afa998a156115e7575f9a6115b8575b505f5416330361159057828103611568578181036115685790899695949392915f5b8d8282106114fa57955050505050506024915051809481938252308b8301525afa928315610e39575f936114c8575b50506114999192611395565b116114a2575050565b517f3b5c3088000000000000000000000000000000000000000000000000000000008152fd5b90809350813d83116114f3575b6114df8183611327565b810103126101e2576114999151915f61148d565b503d6114d5565b879899505f919293949596979061151661046d858786956116c2565b9061152285888c6116c2565b3561152e868a8c611720565b8093519384928337810185815203925af161154761164d565b501561155e57600101908a9796959493929161145e565b8c513d5f823e3d90fd5b8c8c517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b8c8c517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b9099508a81813d83116115e0575b6115d08183611327565b810103126101e25751985f61143c565b503d6115c6565b8d513d5f823e3d90fd5b909392938483116101e25784116101e2578101920390565b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000903581811693926014811061163e57505050565b60140360031b82901b16169150565b3d156116a5573d9067ffffffffffffffff8211611368576040519161169a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611327565b82523d5f602084013e565b606090565b67ffffffffffffffff81116113685760051b60200190565b91908110156116d25760051b0190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b3573ffffffffffffffffffffffffffffffffffffffff811681036101e25790565b91908110156116d25760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156101e257019081359167ffffffffffffffff83116101e25760200182360381136101e2579190565b80518210156116d25760209160051b010190565b929094939193479573ffffffffffffffffffffffffffffffffffffffff5f541633036118935782810361186957818103611869575f5b81811061181457505050505050506117e3904792611395565b116117ea57565b60046040517f3b5c3088000000000000000000000000000000000000000000000000000000008152fd5b61182261046d8284896116c2565b5f8061182f84878a6116c2565b359261183c85898d611720565b90946040958287519384928337810185815203925af161185a61164d565b50156101a857506001016117ca565b60046040517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5fc483c5000000000000000000000000000000000000000000000000000000008152fd5b9160446020925f92604051917fa9059cbb0000000000000000000000000000000000000000000000000000000083526004830152602482015282855af19081611933575b501561190957565b60046040517ffb7f5079000000000000000000000000000000000000000000000000000000008152fd5b90503d1561194d575060015f5114601f3d11165b5f611901565b3b1515611947565b6040515f94939092908360418214611a0a57506040146119c557505f9150815b61197d575050565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16060830151106119ac575050565b6020929350816080915f935282805260015afa505f5190565b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160208086940135918260ff1c601b01828601526040850137166060820152611975565b9160408092508101355f1a602084015281830137611975565b90611a2e8183611ae4565b15611a37575050565b60205f60446040517f095ea7b300000000000000000000000000000000000000000000000000000000815284600482015282602482015282865af180611ac5575b15918215611ab3575b5050611a8957565b60046040517f19be9a90000000000000000000000000000000000000000000000000000000008152fd5b611abd9250611ae4565b155f80611a81565b503d15611adb5760015f5114601f3d1116611a78565b813b1515611a78565b91905f6044602092604051907f095ea7b300000000000000000000000000000000000000000000000000000000825260048201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602482015282865af19182611b4b5750565b9091503d15611b62575060015f5114601f3d111690565b3b15159056fea26469706673582212204cbb3dfe31505132acc9a669238f9a8ba44b9beb10c8dc4b4b7c8eb00f5ba5fc64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004200000000000000000000000000000000000006000000000000000000000000111111125421ca6dc452d289314280a0f8842a65000000000000000000000000a4659995dc39d891c1ba9131aaf5f000e5b57224
-----Decoded View---------------
Arg [0] : weth (address): 0x4200000000000000000000000000000000000006
Arg [1] : lop (address): 0x111111125421cA6dc452d289314280a0f8842A65
Arg [2] : owner (address): 0xa4659995DC39d891C1bA9131Aaf5F000E5B57224
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [1] : 000000000000000000000000111111125421ca6dc452d289314280a0f8842a65
Arg [2] : 000000000000000000000000a4659995dc39d891c1ba9131aaf5f000e5b57224
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.