Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 142695993 | 106 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MetaSwapHandlerV2
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 500 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.20;
import { CoreSwapHandlerV1 } from "../../core/CoreSwapHandler/CoreSwapHandlerV1.sol";
import { IMetaSwapHandlerV2 } from "./IMetaSwapHandlerV2.sol";
import { AlreadyInitialized, SwapDeadlineExceeded } from "../../core/libraries/DefinitiveErrors.sol";
import { DefinitiveConstants } from "../../core/libraries/DefinitiveConstants.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
/**
* @title MetaSwapHandler
* @author WardenJakx
* @notice Meta swap handler to swap anywhere
*/
contract MetaSwapHandlerV2 is CoreSwapHandlerV1, IMetaSwapHandlerV2, Ownable {
bool isInitialized;
address immutable _this;
receive() external payable {}
constructor() Ownable(msg.sender) {
_this = address(this);
}
/**
* @param owner we may not be using msgSender() so an owner address is specified to be the owner
*/
function initialize(address owner) external {
if (isInitialized) {
revert AlreadyInitialized();
}
isInitialized = true;
transferOwnership(owner);
}
function decodeParams(bytes memory data) public pure returns (MetaSwapParamsV2 memory metaSwapParams) {
metaSwapParams = abi.decode(data, (MetaSwapParamsV2));
}
function _performSwap(SwapParams memory params) internal override {
uint256 msgValue;
bool isNativeAsset = params.inputAssetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS;
if (address(this) != _this) {
// delegateCall means native amount is already in the contract so we add msg.value to the input msg.value
msgValue = msg.value + (isNativeAsset ? params.inputAmount : 0);
} else {
// swapCall means msg.value includes the original msg.value (passed into the vault's swap)
// and the msg.value associated with the native asset swap
msgValue = isNativeAsset ? params.inputAmount : msg.value;
}
MetaSwapParamsV2 memory swapParams = abi.decode(params.data, (MetaSwapParamsV2));
Address.functionCallWithValue(swapParams.underlyingSwapRouterAddress, swapParams.swapData, msgValue);
}
function _getSpenderAddress(bytes memory data) internal pure override returns (address) {
MetaSwapParamsV2 memory swapParams = abi.decode(data, (MetaSwapParamsV2));
return swapParams.underlyingSwapApprovalAddress;
}
function _validatePools(SwapParams memory, bool) internal view override {}
function _validateSwap(SwapParams memory params) internal view override {
MetaSwapParamsV2 memory swapParams = abi.decode(params.data, (MetaSwapParamsV2));
if (swapParams.deadline < block.timestamp) {
revert SwapDeadlineExceeded();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.20;
import {
InvalidExecutedOutputAmount,
InvalidMsgValue,
InvalidSwapInputAmount
} from "../libraries/DefinitiveErrors.sol";
import { DefinitiveConstants } from "../libraries/DefinitiveConstants.sol";
import { DefinitiveAssets, IERC20 } from "../libraries/DefinitiveAssets.sol";
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
import { ICoreSwapHandlerV1 } from "./ICoreSwapHandlerV1.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
abstract contract CoreSwapHandlerV1 is ICoreSwapHandlerV1, Context, ReentrancyGuard {
using DefinitiveAssets for IERC20;
function swapCall(SwapParams calldata params) external payable nonReentrant returns (uint256, address) {
return _swapCall(params, false /* enforceAllowedPools */);
}
function swapDelegate(SwapParams calldata params) external payable nonReentrant returns (uint256, address) {
return _swapDelegate(params, false /* enforceAllowedPools */);
}
function swapUsingValidatedPathCall(
SwapParams calldata params
) external payable nonReentrant returns (uint256, address) {
return _swapCall(params, true /* enforceAllowedPools */);
}
function _swapCall(
SwapParams memory params,
bool enforceAllowedPools
) private returns (uint256 amountOut, address) {
bool isInputAddressNativeAsset = params.inputAssetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS;
uint256 rawInputAmount = params.inputAmount;
// Calls to swap native assets must provide a non-zero input amount
if (isInputAddressNativeAsset && rawInputAmount == 0) {
revert InvalidSwapInputAmount();
}
// Calls to swap native assets must match the input amount and msg.value
if (isInputAddressNativeAsset && rawInputAmount != msg.value) {
revert InvalidMsgValue();
}
// Calls to swap non-native assets must have msg.value equal to 0
if (!isInputAddressNativeAsset && msg.value != 0) {
revert InvalidMsgValue();
}
// Update SwapParams with parsed input amount
params.inputAmount = rawInputAmount > 0 ? rawInputAmount : _getTokenAllowance(params.inputAssetAddress);
if (params.inputAssetAddress != DefinitiveConstants.NATIVE_ASSET_ADDRESS) {
IERC20(params.inputAssetAddress).safeTransferFrom(_msgSender(), address(this), params.inputAmount);
}
_validateSwap(params);
_validatePools(params, enforceAllowedPools);
(amountOut, ) = _swap(params);
if (params.outputAssetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS) {
DefinitiveAssets.safeTransferETH(payable(_msgSender()), amountOut);
} else {
IERC20(params.outputAssetAddress).safeTransfer(_msgSender(), amountOut);
}
return (amountOut, params.outputAssetAddress);
}
function _swapDelegate(SwapParams memory params, bool enforceAllowedPools) private returns (uint256, address) {
if (params.inputAmount == 0) {
revert InvalidSwapInputAmount();
}
_validateSwap(params);
_validatePools(params, enforceAllowedPools);
return _swap(params);
}
/**
* @notice This method holds the logic for performing the swap.
* @param params SwapParams
*/
function _performSwap(SwapParams memory params) internal virtual;
/**
* @notice Method to confirm that the swap is using valid pools based on our criteria
* @param params SwapParams
* @param enforceAllowedPools boolean to determine if we should enforce allowed pools
*/
function _validatePools(SwapParams memory params, bool enforceAllowedPools) internal virtual;
/**
* @notice Method to confirm that the swap parameters are valid for the third party
* @param params SwapParams
*/
function _validateSwap(SwapParams memory params) internal virtual;
/**
* @notice When `rawInputAmount` is 0, `swapCall` will use the allowance as the input amount
* @param inputAssetAddress asset to swap from
*/
function _getTokenAllowance(address inputAssetAddress) private view returns (uint256) {
uint256 allowance = IERC20(inputAssetAddress).allowance(_msgSender(), address(this));
if (allowance == 0) {
revert InvalidSwapInputAmount();
}
return allowance;
}
/**
* @notice Returns the address we need to approve in order to swap assets
* @param data included with the swap method invocation
*/
function _getSpenderAddress(bytes memory data) internal virtual returns (address);
/**
* @notice Internal swap logic that performs the swap and validates the output amount
* @param params SwapParams
* @return output amount and output asset address
*/
function _swap(SwapParams memory params) private returns (uint256, address) {
if (params.inputAssetAddress != DefinitiveConstants.NATIVE_ASSET_ADDRESS) {
IERC20(params.inputAssetAddress).resetAndSafeIncreaseAllowance(
_getSpenderAddress(params.data),
params.inputAmount
);
}
uint256 outputAmountDelta = DefinitiveAssets.getBalance(params.outputAssetAddress);
_performSwap(params);
outputAmountDelta = DefinitiveAssets.getBalance(params.outputAssetAddress) - outputAmountDelta;
if (outputAmountDelta < params.minOutputAmount) {
revert InvalidExecutedOutputAmount();
}
emit Swap(
_msgSender(),
params.inputAssetAddress,
params.inputAmount,
params.outputAssetAddress,
outputAmountDelta
);
return (outputAmountDelta, params.outputAssetAddress);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.20;
interface ICoreSwapHandlerV1 {
event Swap(
address indexed actor,
address indexed inputToken,
uint256 inputAmount,
address indexed outputToken,
uint256 outputAmount
);
struct SwapParams {
address inputAssetAddress;
uint256 inputAmount;
address outputAssetAddress;
uint256 minOutputAmount;
bytes data;
bytes signature;
}
function swapCall(SwapParams calldata params) external payable returns (uint256 amountOut, address outputAsset);
function swapDelegate(SwapParams calldata params) external payable returns (uint256 amountOut, address outputAsset);
function swapUsingValidatedPathCall(
SwapParams calldata params
) external payable returns (uint256 amountOut, address outputAsset);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.20;
import { IERC20, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { SafeTransferLib } from "solmate/src/utils/SafeTransferLib.sol";
import { DefinitiveConstants } from "./DefinitiveConstants.sol";
import { InsufficientBalance, InvalidAmount, InvalidAmounts, InvalidERC20Address } from "./DefinitiveErrors.sol";
/**
* @notice Contains methods used throughout the Definitive contracts
* @dev This file should only be used as an internal library.
*/
library DefinitiveAssets {
/**
* @dev Checks if an address is a valid ERC20 token
*/
modifier onlyValidERC20(address erc20Token) {
if (address(erc20Token) == DefinitiveConstants.NATIVE_ASSET_ADDRESS) {
revert InvalidERC20Address();
}
_;
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// ↓ ERC20 and Native Asset Methods ↓
//////////////////////////////////////////////////
/**
* @dev Gets the balance of an ERC20 token or native asset
*/
function getBalance(address assetAddress) internal view returns (uint256) {
if (assetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS) {
return address(this).balance;
} else if (assetAddress == address(0xdefdead)) {
return 0; // For cases we need to set an arbitrary input asset
} else {
return IERC20(assetAddress).balanceOf(address(this));
}
}
/**
* @dev internal function to validate balance is higher than a given amount for ERC20 and native assets
*/
function validateBalance(address token, uint256 amount) internal view {
if (token == DefinitiveConstants.NATIVE_ASSET_ADDRESS) {
validateNativeBalance(amount);
} else {
validateERC20Balance(token, amount);
}
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// ↓ Native Asset Methods ↓
//////////////////////////////////////////////////
/**
* @dev validates amount and balance, then uses SafeTransferLib to transfer native asset
*/
function safeTransferETH(address recipient, uint256 amount) internal {
if (amount > 0) {
SafeTransferLib.safeTransferETH(payable(recipient), amount);
}
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// ↓ ERC20 Methods ↓
//////////////////////////////////////////////////
/**
* @dev Resets and increases the allowance of a spender for an ERC20 token
*/
function resetAndSafeIncreaseAllowance(
IERC20 token,
address spender,
uint256 amount
) internal onlyValidERC20(address(token)) {
return SafeERC20.forceApprove(token, spender, amount);
}
function safeTransfer(IERC20 token, address to, uint256 amount) internal onlyValidERC20(address(token)) {
if (amount > 0) {
SafeERC20.safeTransfer(token, to, amount);
}
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal onlyValidERC20(address(token)) {
if (amount > 0) {
//slither-disable-next-line arbitrary-send-erc20
SafeERC20.safeTransferFrom(token, from, to, amount);
}
}
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// ↓ Asset Amount Helper Methods ↓
//////////////////////////////////////////////////
/**
* @dev internal function to validate that amounts contains a value greater than zero
*/
function validateAmounts(uint256[] calldata amounts) internal pure {
bool hasValidAmounts;
uint256 amountsLength = amounts.length;
for (uint256 i; i < amountsLength; ) {
if (amounts[i] > 0) {
hasValidAmounts = true;
break;
}
unchecked {
++i;
}
}
if (!hasValidAmounts) {
revert InvalidAmounts();
}
}
/**
* @dev internal function to validate if native asset balance is higher than the amount requested
*/
function validateNativeBalance(uint256 amount) internal view {
if (getBalance(DefinitiveConstants.NATIVE_ASSET_ADDRESS) < amount) {
revert InsufficientBalance();
}
}
/**
* @dev internal function to validate balance is higher than the amount requested for a token
*/
function validateERC20Balance(address token, uint256 amount) internal view onlyValidERC20(token) {
if (getBalance(token) < amount) {
revert InsufficientBalance();
}
}
function validateAmount(uint256 _amount) internal pure {
if (_amount == 0) {
revert InvalidAmount();
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.20;
/**
* @notice Contains constants used throughout the Definitive contracts
* @dev This file should only be used as an internal library.
*/
library DefinitiveConstants {
/**
* @notice Maximum fee percentage
*/
uint256 internal constant MAX_FEE_PCT = 10000;
/**
* @notice Address to signify native assets
*/
address internal constant NATIVE_ASSET_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @notice Maximum number of swaps allowed per block
*/
uint8 internal constant MAX_SWAPS_PER_BLOCK = 25;
struct Assets {
uint256[] amounts;
address[] addresses;
}
address internal constant DEFAULT_GLOBAL_TRADE_GUARDIAN = 0xE3F35754954B0B77958C72b83EC5205971463064;
address internal constant STAGING_GLOBAL_TRADE_GUARDIAN = 0xE217abF1077eC4772E4E78Ca0802046A974cba90;
address internal constant LOCAL_GLOBAL_TRADE_GUARDIAN = 0x92d4Ba061336C223f774A23f9a385B7eAdFA64A6;
address internal constant GENERIC_UUPS_PROXY_IMPLEMENTATION = 0x4aEb164998DB4eB8ab945620d4d1db59E2Ad5513;
address internal constant SEND_FEE_TO_SENDER_ALIAS = address(0xFEE);
address internal constant BLAST_NATIVE_YIELD_CONTRACT = 0x4300000000000000000000000000000000000002;
address internal constant BLAST_POINTS_ADDRESS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800;
address internal constant BLAST_DEFINITIVE_OPERATOR_PROD = 0xaba36De8208002e05a757377A76D50093233Eb51;
address internal constant BLAST_DEFINITIVE_OPERATOR_STAGING = 0xaf212671793921BCb84F04cEeEd1dec1EF742DAC;
address internal constant ENTRYPOINT_0_7 = 0x0000000071727De22E5E9d8BAf0edAc6f37da032;
}// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.20; /** * @notice Contains all errors used throughout the Definitive contracts * @dev This file should only be used as an internal library. * @dev When adding a new error, add alphabetically */ error AccountMissingRole(address _account, bytes32 _role); error AccountNotAdmin(address); error AccountNotWhitelisted(address); error AddLiquidityFailed(); error AlreadyDeployed(); error AlreadyInitialized(); error BytecodeEmpty(); error DeadlineExceeded(); error DeployInitFailed(); error DeployFailed(); error BorrowFailed(uint256 errorCode); error DecollateralizeFailed(uint256 errorCode); error DepositMoreThanMax(); error EmptyBytecode(); error EnterAllFailed(); error EnforcedSafeLTV(uint256 invalidLTV); error ExceededMaxDelta(); error ExceededMaxLTV(); error ExceededShareToAssetRatioDeltaThreshold(); error ExitAllFailed(); error ExitOneCoinFailed(); error GlobalStopGuardianEnabled(); error InitializeMarketsFailed(); error InputGreaterThanStaked(); error InsufficientBalance(); error InsufficientSwapTokenBalance(); error InvalidAddress(); error InvalidChain(); error InvalidAmount(); error InvalidAmounts(); error InvalidCalldata(); error InvalidCoreSignerPayload(); error InvalidDestinationSwapper(); error InvalidERC20Address(); error InvalidExecutedOutputAmount(); error InvalidFeePercent(); error InvalidHandler(); error InvalidInputs(); error InvalidMsgValue(); error InvalidSession(); error InvalidSingleHopSwap(); error InvalidMethod(bytes4 methodSig); error InvalidMultiHopSwap(); error InvalidOutputToken(); error InvalidRedemptionRecipient(); // Used in cross-chain redeptions error InvalidReportedOutputAmount(); error InvalidRewardsClaim(); error InvalidSignature(); error InvalidSignatureLength(); error InvalidSwapHandler(); error InvalidSwapInputAmount(); error InvalidSwapOutputToken(); error InvalidSwapPath(); error InvalidSwapPayload(); error InvalidSwapToken(); error MintMoreThanMax(); error MismatchedChainId(); error NativeAssetWrapFailed(bool wrappingToNative); error NoSignatureVerificationSignerSet(); error RedeemMoreThanMax(); error RemoveLiquidityFailed(); error RepayDebtFailed(); error SafeHarborModeEnabled(); error SafeHarborRedemptionDisabled(); error SessionExpired(); error SlippageExceeded(uint256 _outputAmount, uint256 _outputAmountMin); error StakeFailed(); error SupplyFailed(); error StopGuardianEnabled(); error TradingDisabled(); error SwapDeadlineExceeded(); error SwapLimitExceeded(); error SwapTokenIsOutputToken(); error TransfersLimitExceeded(); error UnstakeFailed(); error UnauthenticatedFlashloan(); error UntrustedFlashLoanSender(address); error WithdrawMoreThanMax(); error WithdrawalsDisabled(); error ZeroShares();
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.20;
import { ICoreSwapHandlerV1 } from "../../core/CoreSwapHandler/ICoreSwapHandlerV1.sol";
interface IMetaSwapHandlerV2 is ICoreSwapHandlerV1 {
struct MetaSwapParamsV2 {
uint256 deadline;
address underlyingSwapRouterAddress;
address underlyingSwapApprovalAddress;
bytes swapData;
}
/// @dev Needed for core
function decodeParams(bytes memory data) external pure returns (MetaSwapParamsV2 memory);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}{
"evmVersion": "paris",
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 500
},
"viaIR": false,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidERC20Address","type":"error"},{"inputs":[],"name":"InvalidExecutedOutputAmount","type":"error"},{"inputs":[],"name":"InvalidMsgValue","type":"error"},{"inputs":[],"name":"InvalidSwapInputAmount","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SwapDeadlineExceeded","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"actor","type":"address"},{"indexed":true,"internalType":"address","name":"inputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"inputAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"outputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"outputAmount","type":"uint256"}],"name":"Swap","type":"event"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"decodeParams","outputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"underlyingSwapRouterAddress","type":"address"},{"internalType":"address","name":"underlyingSwapApprovalAddress","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"internalType":"struct IMetaSwapHandlerV2.MetaSwapParamsV2","name":"metaSwapParams","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"inputAssetAddress","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputAssetAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct ICoreSwapHandlerV1.SwapParams","name":"params","type":"tuple"}],"name":"swapCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"inputAssetAddress","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputAssetAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct ICoreSwapHandlerV1.SwapParams","name":"params","type":"tuple"}],"name":"swapDelegate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"inputAssetAddress","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputAssetAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct ICoreSwapHandlerV1.SwapParams","name":"params","type":"tuple"}],"name":"swapUsingValidatedPathCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a060405234801561001057600080fd5b506001600055338061003c57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100458161004f565b50306080526100a1565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6080516112466100bc60003960006109ee01526112466000f3fe60806040526004361061007f5760003560e01c8063acd082de1161004e578063acd082de14610112578063c4d66de81461013f578063edfd6d001461015f578063f2fde38b1461017257600080fd5b806340eb44091461008b5780636a89cd49146100c0578063715018a6146100d35780638da5cb5b146100ea57600080fd5b3661008657005b600080fd5b61009e610099366004610dd8565b610192565b604080519283526001600160a01b039091166020830152015b60405180910390f35b61009e6100ce366004610dd8565b6101c3565b3480156100df57600080fd5b506100e86101e1565b005b3480156100f657600080fd5b506001546040516001600160a01b0390911681526020016100b7565b34801561011e57600080fd5b5061013261012d366004610f24565b6101f5565b6040516100b79190610f85565b34801561014b57600080fd5b506100e861015a36600461100e565b610230565b61009e61016d366004610dd8565b610279565b34801561017e57600080fd5b506100e861018d36600461100e565b610297565b60008061019d6102d7565b6101b06101a98461102b565b6001610301565b915091506101be6001600055565b915091565b6000806101ce6102d7565b6101b06101da8461102b565b600061048f565b6101e96104d4565b6101f36000610501565b565b6040805160808101825260008082526020808301829052928201526060808201528251909161022a91840181019084016110ce565b92915050565b600154600160a01b900460ff161561025a5760405162dc149f60e41b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b17905561027681610297565b50565b6000806102846102d7565b6101b06102908461102b565b6000610301565b61029f6104d4565b6001600160a01b0381166102ce57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b61027681610501565b6002600054036102fa57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b8151602083015160009182916001600160a01b039190911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee149081801561033b575080155b156103595760405163e9152f6360e01b815260040160405180910390fd5b8180156103665750348114155b1561038457604051631841b4e160e01b815260040160405180910390fd5b8115801561039157503415155b156103af57604051631841b4e160e01b815260040160405180910390fd5b600081116103c75785516103c290610560565b6103c9565b805b602087015285516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146104105761041033602088015188516001600160a01b03169190309061061c565b61041986610674565b610422866106b9565b508094505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031686604001516001600160a01b0316036104675761046233856107d4565b610480565b6104803360408801516001600160a01b031690866107e4565b50505060408301519250929050565b60008083602001516000036104b75760405163e9152f6360e01b815260040160405180910390fd5b6104c084610674565b6104c9846106b9565b915091509250929050565b6001546001600160a01b031633146101f35760405163118cdaa760e01b81523360048201526024016102c5565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806001600160a01b03831663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156105d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f991906111a6565b90508060000361022a5760405163e9152f6360e01b815260040160405180910390fd5b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161065b576040516376fe282b60e11b815260040160405180910390fd5b811561066d5761066d8585858561083a565b5050505050565b6000816080015180602001905181019061068e91906110ce565b905042816000015110156106b557604051637617263160e01b815260040160405180910390fd5b5050565b805160009081906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461070a5761070a6106f384608001516108a1565b602085015185516001600160a01b031691906108c3565b6000610719846040015161090d565b9050610724846109c5565b80610732856040015161090d565b61073c91906111d5565b90508360600151811015610763576040516331cee32f60e21b815260040160405180910390fd5b604084015184516001600160a01b039182169116336001600160a01b03167f5380cf97d8f645d3c4896da60c053458dca03a3a31cec642ac80e1ddf0d8d02a8760200151856040516107bf929190918252602082015260400190565b60405180910390a46040909301519293915050565b80156106b5576106b58282610a7a565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610823576040516376fe282b60e11b815260040160405180910390fd5b811561083457610834848484610ada565b50505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526108349186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610b0b565b600080828060200190518101906108b891906110ce565b604001519392505050565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610902576040516376fe282b60e11b815260040160405180910390fd5b610834848484610b6e565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0383160161093b575047919050565b630defdeac196001600160a01b0383160161095857506000919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561099c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022a91906111a6565b919050565b805160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0391821614907f0000000000000000000000000000000000000000000000000000000000000000163014610a375780610a20576000610a26565b82602001515b610a3090346111e8565b9150610a4b565b80610a425734610a48565b82602001515b91505b60008360800151806020019051810190610a6591906110ce565b905061066d8160200151826060015185610bfe565b600080600080600085875af1905080610ad55760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016102c5565b505050565b6040516001600160a01b03838116602483015260448201839052610ad591859182169063a9059cbb9060640161086f565b6000610b206001600160a01b03841683610c9d565b90508051600014158015610b45575080806020019051810190610b4391906111fb565b155b15610ad557604051635274afe760e01b81526001600160a01b03841660048201526024016102c5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610bbf8482610cab565b610834576040516001600160a01b03848116602483015260006044830152610bf491869182169063095ea7b39060640161086f565b6108348482610b0b565b606081471015610c235760405163cd78605960e01b81523060048201526024016102c5565b600080856001600160a01b03168486604051610c3f919061121d565b60006040518083038185875af1925050503d8060008114610c7c576040519150601f19603f3d011682016040523d82523d6000602084013e610c81565b606091505b5091509150610c91868383610d53565b925050505b9392505050565b6060610c9683836000610bfe565b6000806000846001600160a01b031684604051610cc8919061121d565b6000604051808303816000865af19150503d8060008114610d05576040519150601f19603f3d011682016040523d82523d6000602084013e610d0a565b606091505b5091509150818015610d34575080511580610d34575080806020019051810190610d3491906111fb565b8015610d4a57506000856001600160a01b03163b115b95945050505050565b606082610d6857610d6382610daf565b610c96565b8151158015610d7f57506001600160a01b0384163b155b15610da857604051639996b31560e01b81526001600160a01b03851660048201526024016102c5565b5080610c96565b805115610dbf5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215610dea57600080fd5b813567ffffffffffffffff811115610e0157600080fd5b820160c08185031215610c9657600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715610e4c57610e4c610e13565b60405290565b6040516080810167ffffffffffffffff81118282101715610e4c57610e4c610e13565b604051601f8201601f1916810167ffffffffffffffff81118282101715610e9e57610e9e610e13565b604052919050565b600067ffffffffffffffff821115610ec057610ec0610e13565b50601f01601f191660200190565b600082601f830112610edf57600080fd5b8135610ef2610eed82610ea6565b610e75565b818152846020838601011115610f0757600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215610f3657600080fd5b813567ffffffffffffffff811115610f4d57600080fd5b610f5984828501610ece565b949350505050565b60005b83811015610f7c578181015183820152602001610f64565b50506000910152565b6020815281516020820152600060208301516001600160a01b0380821660408501528060408601511660608501525050606083015160808084015280518060a0850152610fd98160c0860160208501610f61565b601f01601f19169290920160c0019392505050565b6001600160a01b038116811461027657600080fd5b80356109c081610fee565b60006020828403121561102057600080fd5b8135610c9681610fee565b600060c0823603121561103d57600080fd5b611045610e29565b61104e83611003565b81526020830135602082015261106660408401611003565b604082015260608301356060820152608083013567ffffffffffffffff8082111561109057600080fd5b61109c36838701610ece565b608084015260a08501359150808211156110b557600080fd5b506110c236828601610ece565b60a08301525092915050565b600060208083850312156110e157600080fd5b825167ffffffffffffffff808211156110f957600080fd5b908401906080828703121561110d57600080fd5b611115610e52565b825181528383015161112681610fee565b81850152604083015161113881610fee565b604082015260608301518281111561114f57600080fd5b80840193505086601f84011261116457600080fd5b82519150611174610eed83610ea6565b828152878584860101111561118857600080fd5b61119783868301878701610f61565b60608201529695505050505050565b6000602082840312156111b857600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561022a5761022a6111bf565b8082018082111561022a5761022a6111bf565b60006020828403121561120d57600080fd5b81518015158114610c9657600080fd5b6000825161122f818460208701610f61565b919091019291505056fea164736f6c6343000814000a
Deployed Bytecode
0x60806040526004361061007f5760003560e01c8063acd082de1161004e578063acd082de14610112578063c4d66de81461013f578063edfd6d001461015f578063f2fde38b1461017257600080fd5b806340eb44091461008b5780636a89cd49146100c0578063715018a6146100d35780638da5cb5b146100ea57600080fd5b3661008657005b600080fd5b61009e610099366004610dd8565b610192565b604080519283526001600160a01b039091166020830152015b60405180910390f35b61009e6100ce366004610dd8565b6101c3565b3480156100df57600080fd5b506100e86101e1565b005b3480156100f657600080fd5b506001546040516001600160a01b0390911681526020016100b7565b34801561011e57600080fd5b5061013261012d366004610f24565b6101f5565b6040516100b79190610f85565b34801561014b57600080fd5b506100e861015a36600461100e565b610230565b61009e61016d366004610dd8565b610279565b34801561017e57600080fd5b506100e861018d36600461100e565b610297565b60008061019d6102d7565b6101b06101a98461102b565b6001610301565b915091506101be6001600055565b915091565b6000806101ce6102d7565b6101b06101da8461102b565b600061048f565b6101e96104d4565b6101f36000610501565b565b6040805160808101825260008082526020808301829052928201526060808201528251909161022a91840181019084016110ce565b92915050565b600154600160a01b900460ff161561025a5760405162dc149f60e41b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b17905561027681610297565b50565b6000806102846102d7565b6101b06102908461102b565b6000610301565b61029f6104d4565b6001600160a01b0381166102ce57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b61027681610501565b6002600054036102fa57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b8151602083015160009182916001600160a01b039190911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee149081801561033b575080155b156103595760405163e9152f6360e01b815260040160405180910390fd5b8180156103665750348114155b1561038457604051631841b4e160e01b815260040160405180910390fd5b8115801561039157503415155b156103af57604051631841b4e160e01b815260040160405180910390fd5b600081116103c75785516103c290610560565b6103c9565b805b602087015285516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146104105761041033602088015188516001600160a01b03169190309061061c565b61041986610674565b610422866106b9565b508094505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031686604001516001600160a01b0316036104675761046233856107d4565b610480565b6104803360408801516001600160a01b031690866107e4565b50505060408301519250929050565b60008083602001516000036104b75760405163e9152f6360e01b815260040160405180910390fd5b6104c084610674565b6104c9846106b9565b915091509250929050565b6001546001600160a01b031633146101f35760405163118cdaa760e01b81523360048201526024016102c5565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806001600160a01b03831663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156105d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f991906111a6565b90508060000361022a5760405163e9152f6360e01b815260040160405180910390fd5b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161065b576040516376fe282b60e11b815260040160405180910390fd5b811561066d5761066d8585858561083a565b5050505050565b6000816080015180602001905181019061068e91906110ce565b905042816000015110156106b557604051637617263160e01b815260040160405180910390fd5b5050565b805160009081906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461070a5761070a6106f384608001516108a1565b602085015185516001600160a01b031691906108c3565b6000610719846040015161090d565b9050610724846109c5565b80610732856040015161090d565b61073c91906111d5565b90508360600151811015610763576040516331cee32f60e21b815260040160405180910390fd5b604084015184516001600160a01b039182169116336001600160a01b03167f5380cf97d8f645d3c4896da60c053458dca03a3a31cec642ac80e1ddf0d8d02a8760200151856040516107bf929190918252602082015260400190565b60405180910390a46040909301519293915050565b80156106b5576106b58282610a7a565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610823576040516376fe282b60e11b815260040160405180910390fd5b811561083457610834848484610ada565b50505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526108349186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610b0b565b600080828060200190518101906108b891906110ce565b604001519392505050565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610902576040516376fe282b60e11b815260040160405180910390fd5b610834848484610b6e565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0383160161093b575047919050565b630defdeac196001600160a01b0383160161095857506000919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561099c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022a91906111a6565b919050565b805160009073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b0391821614907f000000000000000000000000000000034714cd2778c7fc0f284a89d1116171ee163014610a375780610a20576000610a26565b82602001515b610a3090346111e8565b9150610a4b565b80610a425734610a48565b82602001515b91505b60008360800151806020019051810190610a6591906110ce565b905061066d8160200151826060015185610bfe565b600080600080600085875af1905080610ad55760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c45440000000000000000000000000060448201526064016102c5565b505050565b6040516001600160a01b03838116602483015260448201839052610ad591859182169063a9059cbb9060640161086f565b6000610b206001600160a01b03841683610c9d565b90508051600014158015610b45575080806020019051810190610b4391906111fb565b155b15610ad557604051635274afe760e01b81526001600160a01b03841660048201526024016102c5565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610bbf8482610cab565b610834576040516001600160a01b03848116602483015260006044830152610bf491869182169063095ea7b39060640161086f565b6108348482610b0b565b606081471015610c235760405163cd78605960e01b81523060048201526024016102c5565b600080856001600160a01b03168486604051610c3f919061121d565b60006040518083038185875af1925050503d8060008114610c7c576040519150601f19603f3d011682016040523d82523d6000602084013e610c81565b606091505b5091509150610c91868383610d53565b925050505b9392505050565b6060610c9683836000610bfe565b6000806000846001600160a01b031684604051610cc8919061121d565b6000604051808303816000865af19150503d8060008114610d05576040519150601f19603f3d011682016040523d82523d6000602084013e610d0a565b606091505b5091509150818015610d34575080511580610d34575080806020019051810190610d3491906111fb565b8015610d4a57506000856001600160a01b03163b115b95945050505050565b606082610d6857610d6382610daf565b610c96565b8151158015610d7f57506001600160a01b0384163b155b15610da857604051639996b31560e01b81526001600160a01b03851660048201526024016102c5565b5080610c96565b805115610dbf5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215610dea57600080fd5b813567ffffffffffffffff811115610e0157600080fd5b820160c08185031215610c9657600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715610e4c57610e4c610e13565b60405290565b6040516080810167ffffffffffffffff81118282101715610e4c57610e4c610e13565b604051601f8201601f1916810167ffffffffffffffff81118282101715610e9e57610e9e610e13565b604052919050565b600067ffffffffffffffff821115610ec057610ec0610e13565b50601f01601f191660200190565b600082601f830112610edf57600080fd5b8135610ef2610eed82610ea6565b610e75565b818152846020838601011115610f0757600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215610f3657600080fd5b813567ffffffffffffffff811115610f4d57600080fd5b610f5984828501610ece565b949350505050565b60005b83811015610f7c578181015183820152602001610f64565b50506000910152565b6020815281516020820152600060208301516001600160a01b0380821660408501528060408601511660608501525050606083015160808084015280518060a0850152610fd98160c0860160208501610f61565b601f01601f19169290920160c0019392505050565b6001600160a01b038116811461027657600080fd5b80356109c081610fee565b60006020828403121561102057600080fd5b8135610c9681610fee565b600060c0823603121561103d57600080fd5b611045610e29565b61104e83611003565b81526020830135602082015261106660408401611003565b604082015260608301356060820152608083013567ffffffffffffffff8082111561109057600080fd5b61109c36838701610ece565b608084015260a08501359150808211156110b557600080fd5b506110c236828601610ece565b60a08301525092915050565b600060208083850312156110e157600080fd5b825167ffffffffffffffff808211156110f957600080fd5b908401906080828703121561110d57600080fd5b611115610e52565b825181528383015161112681610fee565b81850152604083015161113881610fee565b604082015260608301518281111561114f57600080fd5b80840193505086601f84011261116457600080fd5b82519150611174610eed83610ea6565b828152878584860101111561118857600080fd5b61119783868301878701610f61565b60608201529695505050505050565b6000602082840312156111b857600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561022a5761022a6111bf565b8082018082111561022a5761022a6111bf565b60006020828403121561120d57600080fd5b81518015158114610c9657600080fd5b6000825161122f818460208701610f61565b919091019291505056fea164736f6c6343000814000a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.