Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 297783283 | 369 days ago | 90.49809503 ETH | ||||
| 297783283 | 369 days ago | 90.49809503 ETH | ||||
| 297776356 | 369 days ago | 96.98143772 ETH | ||||
| 297776356 | 369 days ago | 96.98143772 ETH | ||||
| 297558862 | 370 days ago | 0.00000013 ETH | ||||
| 297558862 | 370 days ago | 32.999993 ETH | ||||
| 297558862 | 370 days ago | 32.999993 ETH | ||||
| 296081957 | 374 days ago | 0.00000039 ETH | ||||
| 296081957 | 374 days ago | 54.23764453 ETH | ||||
| 296081957 | 374 days ago | 54.23764453 ETH | ||||
| 275693467 | 433 days ago | 69.99998714 ETH | ||||
| 275693467 | 433 days ago | 69.99998714 ETH | ||||
| 263880156 | 468 days ago | 0.08527764 ETH | ||||
| 263880156 | 468 days ago | 0.08527764 ETH | ||||
| 261299410 | 475 days ago | 0.05090139 ETH | ||||
| 261299410 | 475 days ago | 0.05090139 ETH | ||||
| 257599861 | 486 days ago | 0.47163106 ETH | ||||
| 257599861 | 486 days ago | 0.47163106 ETH | ||||
| 242909153 | 529 days ago | 0.00093748 ETH | ||||
| 242909153 | 529 days ago | 0.00093748 ETH | ||||
| 242376655 | 530 days ago | 0.35539516 ETH | ||||
| 242376655 | 530 days ago | 0.35539516 ETH | ||||
| 242371206 | 530 days ago | 0.709881 ETH | ||||
| 242371206 | 530 days ago | 0.709881 ETH | ||||
| 224969228 | 581 days ago | 0.00438914 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MetaSwapHandler
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 { IMetaSwapHandler } from "./IMetaSwapHandler.sol";
import {
AlreadyInitialized,
SwapDeadlineExceeded,
InvalidDestinationSwapper
} 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 MetaSwapHandler is CoreSwapHandlerV1, IMetaSwapHandler, Ownable {
bool isInitialized;
address immutable _this;
receive() external payable {}
mapping(address => bool) public whitelistedSwapContracts;
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
* @param whitelistedContracts DEX routers to whitelist (eg 0x router)m
*/
function initialize(address owner, address[] calldata whitelistedContracts) external {
if (isInitialized) {
revert AlreadyInitialized();
}
isInitialized = true;
transferOwnership(owner);
_updateWhitelist(whitelistedContracts, true);
}
function decodeParams(bytes memory data) public pure returns (MetaSwapParams memory metaSwapParams) {
metaSwapParams = abi.decode(data, (MetaSwapParams));
}
function removeFromWhitelist(address[] calldata contracts) external onlyOwner {
_updateWhitelist(contracts, false);
}
function addToWhitelist(address[] calldata contracts) external onlyOwner {
_updateWhitelist(contracts, true);
}
function _performSwap(SwapParams memory params) internal override {
MetaSwapParams memory swapParams = abi.decode(params.data, (MetaSwapParams));
Address.functionCallWithValue(
swapParams.underlyingSwapRouterAddress,
swapParams.swapData,
params.inputAssetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS ? params.inputAmount : 0
);
}
function _getSpenderAddress(bytes memory data) internal pure override returns (address) {
MetaSwapParams memory swapParams = abi.decode(data, (MetaSwapParams));
return swapParams.underlyingSwapRouterAddress;
}
function _validatePools(SwapParams memory, bool) internal view override {}
function _validateSwap(SwapParams memory params) internal view override {
MetaSwapParams memory swapParams = abi.decode(params.data, (MetaSwapParams));
bool swapRouterIsWhitelisted = address(this) == _this
? whitelistedSwapContracts[swapParams.underlyingSwapRouterAddress]
: MetaSwapHandler(payable(_this)).whitelistedSwapContracts(swapParams.underlyingSwapRouterAddress);
if (!swapRouterIsWhitelisted) {
revert InvalidDestinationSwapper();
}
if (swapParams.deadline < block.timestamp) {
revert SwapDeadlineExceeded();
}
}
function _updateWhitelist(address[] memory contracts, bool isWhitelisted) private {
uint256 contractsLength = contracts.length;
for (uint256 i; i < contractsLength; ) {
whitelistedSwapContracts[contracts[i]] = isWhitelisted;
unchecked {
++i;
}
}
}
}// 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) {
uint256 rawInputAmount = params.inputAmount;
uint256 parsedInputAmount = rawInputAmount > 0
? rawInputAmount
: DefinitiveAssets.getBalance(params.inputAssetAddress);
if (parsedInputAmount == 0) {
revert InvalidSwapInputAmount();
}
// Update SwapParams with parsed input amount
params.inputAmount = parsedInputAmount;
_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(
address(this),
_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 {
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 owner,
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;
}
}// 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 InvalidAmount(); error InvalidAmounts(); error InvalidCalldata(); error InvalidDestinationSwapper(); error InvalidERC20Address(); error InvalidExecutedOutputAmount(); error InvalidFeePercent(); error InvalidHandler(); error InvalidInputs(); error InvalidMsgValue(); error InvalidSingleHopSwap(); 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 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 IMetaSwapHandler is ICoreSwapHandlerV1 {
struct MetaSwapParams {
uint256 deadline;
address underlyingSwapRouterAddress;
bytes swapData;
}
/// @dev Needed for core
function decodeParams(bytes memory data) external pure returns (MetaSwapParams memory);
function removeFromWhitelist(address[] memory swapContracts) external;
function addToWhitelist(address[] memory swapContracts) external;
}// 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"
]
}
},
"libraries": {}
}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":"InvalidDestinationSwapper","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":"address[]","name":"contracts","type":"address[]"}],"name":"addToWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"decodeParams","outputs":[{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"underlyingSwapRouterAddress","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"internalType":"struct IMetaSwapHandler.MetaSwapParams","name":"metaSwapParams","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address[]","name":"whitelistedContracts","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"contracts","type":"address[]"}],"name":"removeFromWhitelist","outputs":[],"stateMutability":"nonpayable","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"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedSwapContracts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a060405234801561001057600080fd5b506001600055338061003c57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6100458161004f565b50306080526100a1565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60805161158c6100c3600039600081816108a701526108ef015261158c6000f3fe6080604052600436106100b05760003560e01c80637f64978311610074578063acd082de1161004e578063acd082de146101e3578063edfd6d0014610210578063f2fde38b1461022357600080fd5b80637f6497831461017b5780638da5cb5b1461019b578063946d9204146101c357600080fd5b806340eb4409146100bc578063548db174146100f15780635ee54d80146101135780636a89cd4914610153578063715018a61461016657600080fd5b366100b757005b600080fd5b6100cf6100ca36600461106a565b610243565b604080519283526001600160a01b039091166020830152015b60405180910390f35b3480156100fd57600080fd5b5061011161010c3660046110ea565b610274565b005b34801561011f57600080fd5b5061014361012e36600461114c565b60026020526000908152604090205460ff1681565b60405190151581526020016100e8565b6100cf61016136600461106a565b6102bc565b34801561017257600080fd5b506101116102da565b34801561018757600080fd5b506101116101963660046110ea565b6102ee565b3480156101a757600080fd5b506001546040516001600160a01b0390911681526020016100e8565b3480156101cf57600080fd5b506101116101de366004611169565b610335565b3480156101ef57600080fd5b506102036101fe3660046112cf565b6103bf565b6040516100e89190611330565b6100cf61021e36600461106a565b6103f5565b34801561022f57600080fd5b5061011161023e36600461114c565b610413565b60008061024e610456565b61026161025a84611389565b6001610480565b9150915061026f6001600055565b915091565b61027c61060f565b6102b88282808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250925061063c915050565b5050565b6000806102c7610456565b6102616102d384611389565b60006106a0565b6102e261060f565b6102ec600061070b565b565b6102f661060f565b6102b88282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506001925061063c915050565b600154600160a01b900460ff161561035f5760405162dc149f60e41b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b17905561037b83610413565b6103ba8282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506001925061063c915050565b505050565b60408051606080820183526000808352602083015291810191909152818060200190518101906103ef919061142c565b92915050565b600080610400610456565b61026161040c84611389565b6000610480565b61041b61060f565b6001600160a01b03811661044a57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6104538161070b565b50565b60026000540361047957604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b8151602083015160009182916001600160a01b039190911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14908180156104ba575080155b156104d85760405163e9152f6360e01b815260040160405180910390fd5b8180156104e55750348114155b1561050357604051631841b4e160e01b815260040160405180910390fd5b8115801561051057503415155b1561052e57604051631841b4e160e01b815260040160405180910390fd5b600081116105465785516105419061076a565b610548565b805b602087015285516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461058f5761058f33602088015188516001600160a01b031691903090610826565b6105988661087e565b6105a1866109c5565b508094505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031686604001516001600160a01b0316036105e6576105e13385610ae2565b6105ff565b6105ff3360408801516001600160a01b03169086610af2565b50505060408301515b9250929050565b6001546001600160a01b031633146102ec5760405163118cdaa760e01b8152336004820152602401610441565b815160005b8181101561069a578260026000868481518110610660576106606114f1565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101610641565b50505050565b6020820151600090819081816106c05785516106bb90610b42565b6106c2565b815b9050806000036106e55760405163e9152f6360e01b815260040160405180910390fd5b602086018190526106f58661087e565b6106fe866109c5565b9350935050509250929050565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806001600160a01b03831663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156107df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108039190611507565b9050806000036103ef5760405163e9152f6360e01b815260040160405180910390fd5b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610865576040516376fe282b60e11b815260040160405180910390fd5b81156108775761087785858585610bdd565b5050505050565b60008160800151806020019051810190610898919061142c565b90506000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461096157602082015160405162bdca9b60e71b81526001600160a01b0391821660048201527f000000000000000000000000000000000000000000000000000000000000000090911690635ee54d8090602401602060405180830381865afa158015610938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095c9190611520565b610983565b6020808301516001600160a01b031660009081526002909152604090205460ff165b9050806109a357604051633dfd115d60e01b815260040160405180910390fd5b81514211156103ba57604051637617263160e01b815260040160405180910390fd5b805160009081906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610a1857610a1830610a008560800151610c44565b602086015186516001600160a01b0316929190610c66565b6000610a278460400151610b42565b9050610a3284610cb0565b80610a408560400151610b42565b610a4a9190611542565b90508360600151811015610a71576040516331cee32f60e21b815260040160405180910390fd5b604084015184516001600160a01b039182169116336001600160a01b03167f5380cf97d8f645d3c4896da60c053458dca03a3a31cec642ac80e1ddf0d8d02a876020015185604051610acd929190918252602082015260400190565b60405180910390a46040909301519293915050565b80156102b8576102b88282610d11565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610b31576040516376fe282b60e11b815260040160405180910390fd5b811561069a5761069a848484610d6c565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610b70575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610bb4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ef9190611507565b919050565b6040516001600160a01b03848116602483015283811660448301526064820183905261069a9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610d9d565b60008082806020019051810190610c5b919061142c565b602001519392505050565b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610ca5576040516376fe282b60e11b815260040160405180910390fd5b610877858484610e00565b60008160800151806020019051810190610cca919061142c565b6020810151604082015184519293506103ba926001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d07576000610e90565b8460200151610e90565b600080600080600085875af19050806103ba5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610441565b6040516001600160a01b038381166024830152604482018390526103ba91859182169063a9059cbb90606401610c12565b6000610db26001600160a01b03841683610f2f565b90508051600014158015610dd7575080806020019051810190610dd59190611520565b155b156103ba57604051635274afe760e01b81526001600160a01b0384166004820152602401610441565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e518482610f3d565b61069a576040516001600160a01b03848116602483015260006044830152610e8691869182169063095ea7b390606401610c12565b61069a8482610d9d565b606081471015610eb55760405163cd78605960e01b8152306004820152602401610441565b600080856001600160a01b03168486604051610ed19190611563565b60006040518083038185875af1925050503d8060008114610f0e576040519150601f19603f3d011682016040523d82523d6000602084013e610f13565b606091505b5091509150610f23868383610fe5565b925050505b9392505050565b6060610f2883836000610e90565b6000806000846001600160a01b031684604051610f5a9190611563565b6000604051808303816000865af19150503d8060008114610f97576040519150601f19603f3d011682016040523d82523d6000602084013e610f9c565b606091505b5091509150818015610fc6575080511580610fc6575080806020019051810190610fc69190611520565b8015610fdc57506000856001600160a01b03163b115b95945050505050565b606082610ffa57610ff582611041565b610f28565b815115801561101157506001600160a01b0384163b155b1561103a57604051639996b31560e01b81526001600160a01b0385166004820152602401610441565b5080610f28565b8051156110515780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60006020828403121561107c57600080fd5b813567ffffffffffffffff81111561109357600080fd5b820160c08185031215610f2857600080fd5b60008083601f8401126110b757600080fd5b50813567ffffffffffffffff8111156110cf57600080fd5b6020830191508360208260051b850101111561060857600080fd5b600080602083850312156110fd57600080fd5b823567ffffffffffffffff81111561111457600080fd5b611120858286016110a5565b90969095509350505050565b6001600160a01b038116811461045357600080fd5b8035610bd88161112c565b60006020828403121561115e57600080fd5b8135610f288161112c565b60008060006040848603121561117e57600080fd5b83356111898161112c565b9250602084013567ffffffffffffffff8111156111a557600080fd5b6111b1868287016110a5565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff811182821017156111f7576111f76111be565b60405290565b6040516060810167ffffffffffffffff811182821017156111f7576111f76111be565b604051601f8201601f1916810167ffffffffffffffff81118282101715611249576112496111be565b604052919050565b600067ffffffffffffffff82111561126b5761126b6111be565b50601f01601f191660200190565b600082601f83011261128a57600080fd5b813561129d61129882611251565b611220565b8181528460208386010111156112b257600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156112e157600080fd5b813567ffffffffffffffff8111156112f857600080fd5b61130484828501611279565b949350505050565b60005b8381101561132757818101518382015260200161130f565b50506000910152565b60208152815160208201526001600160a01b0360208301511660408201526000604083015160608084015280518060808501526113748160a086016020850161130c565b601f01601f19169290920160a0019392505050565b600060c0823603121561139b57600080fd5b6113a36111d4565b6113ac83611141565b8152602083013560208201526113c460408401611141565b604082015260608301356060820152608083013567ffffffffffffffff808211156113ee57600080fd5b6113fa36838701611279565b608084015260a085013591508082111561141357600080fd5b5061142036828601611279565b60a08301525092915050565b6000602080838503121561143f57600080fd5b825167ffffffffffffffff8082111561145757600080fd5b908401906060828703121561146b57600080fd5b6114736111fd565b82518152838301516114848161112c565b8185015260408301518281111561149a57600080fd5b80840193505086601f8401126114af57600080fd5b825191506114bf61129883611251565b82815287858486010111156114d357600080fd5b6114e28386830187870161130c565b60408201529695505050505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561151957600080fd5b5051919050565b60006020828403121561153257600080fd5b81518015158114610f2857600080fd5b818103818111156103ef57634e487b7160e01b600052601160045260246000fd5b6000825161157581846020870161130c565b919091019291505056fea164736f6c6343000814000a
Deployed Bytecode
0x6080604052600436106100b05760003560e01c80637f64978311610074578063acd082de1161004e578063acd082de146101e3578063edfd6d0014610210578063f2fde38b1461022357600080fd5b80637f6497831461017b5780638da5cb5b1461019b578063946d9204146101c357600080fd5b806340eb4409146100bc578063548db174146100f15780635ee54d80146101135780636a89cd4914610153578063715018a61461016657600080fd5b366100b757005b600080fd5b6100cf6100ca36600461106a565b610243565b604080519283526001600160a01b039091166020830152015b60405180910390f35b3480156100fd57600080fd5b5061011161010c3660046110ea565b610274565b005b34801561011f57600080fd5b5061014361012e36600461114c565b60026020526000908152604090205460ff1681565b60405190151581526020016100e8565b6100cf61016136600461106a565b6102bc565b34801561017257600080fd5b506101116102da565b34801561018757600080fd5b506101116101963660046110ea565b6102ee565b3480156101a757600080fd5b506001546040516001600160a01b0390911681526020016100e8565b3480156101cf57600080fd5b506101116101de366004611169565b610335565b3480156101ef57600080fd5b506102036101fe3660046112cf565b6103bf565b6040516100e89190611330565b6100cf61021e36600461106a565b6103f5565b34801561022f57600080fd5b5061011161023e36600461114c565b610413565b60008061024e610456565b61026161025a84611389565b6001610480565b9150915061026f6001600055565b915091565b61027c61060f565b6102b88282808060200260200160405190810160405280939291908181526020018383602002808284376000920182905250925061063c915050565b5050565b6000806102c7610456565b6102616102d384611389565b60006106a0565b6102e261060f565b6102ec600061070b565b565b6102f661060f565b6102b88282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506001925061063c915050565b600154600160a01b900460ff161561035f5760405162dc149f60e41b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b17905561037b83610413565b6103ba8282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506001925061063c915050565b505050565b60408051606080820183526000808352602083015291810191909152818060200190518101906103ef919061142c565b92915050565b600080610400610456565b61026161040c84611389565b6000610480565b61041b61060f565b6001600160a01b03811661044a57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6104538161070b565b50565b60026000540361047957604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b8151602083015160009182916001600160a01b039190911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14908180156104ba575080155b156104d85760405163e9152f6360e01b815260040160405180910390fd5b8180156104e55750348114155b1561050357604051631841b4e160e01b815260040160405180910390fd5b8115801561051057503415155b1561052e57604051631841b4e160e01b815260040160405180910390fd5b600081116105465785516105419061076a565b610548565b805b602087015285516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461058f5761058f33602088015188516001600160a01b031691903090610826565b6105988661087e565b6105a1866109c5565b508094505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031686604001516001600160a01b0316036105e6576105e13385610ae2565b6105ff565b6105ff3360408801516001600160a01b03169086610af2565b50505060408301515b9250929050565b6001546001600160a01b031633146102ec5760405163118cdaa760e01b8152336004820152602401610441565b815160005b8181101561069a578260026000868481518110610660576106606114f1565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101610641565b50505050565b6020820151600090819081816106c05785516106bb90610b42565b6106c2565b815b9050806000036106e55760405163e9152f6360e01b815260040160405180910390fd5b602086018190526106f58661087e565b6106fe866109c5565b9350935050509250929050565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806001600160a01b03831663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156107df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108039190611507565b9050806000036103ef5760405163e9152f6360e01b815260040160405180910390fd5b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610865576040516376fe282b60e11b815260040160405180910390fd5b81156108775761087785858585610bdd565b5050505050565b60008160800151806020019051810190610898919061142c565b90506000306001600160a01b037f000000000000000000000000b7dbdef7a6488d1ee9c9fa52f582b9f23c24d8cb161461096157602082015160405162bdca9b60e71b81526001600160a01b0391821660048201527f000000000000000000000000b7dbdef7a6488d1ee9c9fa52f582b9f23c24d8cb90911690635ee54d8090602401602060405180830381865afa158015610938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095c9190611520565b610983565b6020808301516001600160a01b031660009081526002909152604090205460ff165b9050806109a357604051633dfd115d60e01b815260040160405180910390fd5b81514211156103ba57604051637617263160e01b815260040160405180910390fd5b805160009081906001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610a1857610a1830610a008560800151610c44565b602086015186516001600160a01b0316929190610c66565b6000610a278460400151610b42565b9050610a3284610cb0565b80610a408560400151610b42565b610a4a9190611542565b90508360600151811015610a71576040516331cee32f60e21b815260040160405180910390fd5b604084015184516001600160a01b039182169116336001600160a01b03167f5380cf97d8f645d3c4896da60c053458dca03a3a31cec642ac80e1ddf0d8d02a876020015185604051610acd929190918252602082015260400190565b60405180910390a46040909301519293915050565b80156102b8576102b88282610d11565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610b31576040516376fe282b60e11b815260040160405180910390fd5b811561069a5761069a848484610d6c565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610b70575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015610bb4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ef9190611507565b919050565b6040516001600160a01b03848116602483015283811660448301526064820183905261069a9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610d9d565b60008082806020019051810190610c5b919061142c565b602001519392505050565b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601610ca5576040516376fe282b60e11b815260040160405180910390fd5b610877858484610e00565b60008160800151806020019051810190610cca919061142c565b6020810151604082015184519293506103ba926001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610d07576000610e90565b8460200151610e90565b600080600080600085875af19050806103ba5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610441565b6040516001600160a01b038381166024830152604482018390526103ba91859182169063a9059cbb90606401610c12565b6000610db26001600160a01b03841683610f2f565b90508051600014158015610dd7575080806020019051810190610dd59190611520565b155b156103ba57604051635274afe760e01b81526001600160a01b0384166004820152602401610441565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e518482610f3d565b61069a576040516001600160a01b03848116602483015260006044830152610e8691869182169063095ea7b390606401610c12565b61069a8482610d9d565b606081471015610eb55760405163cd78605960e01b8152306004820152602401610441565b600080856001600160a01b03168486604051610ed19190611563565b60006040518083038185875af1925050503d8060008114610f0e576040519150601f19603f3d011682016040523d82523d6000602084013e610f13565b606091505b5091509150610f23868383610fe5565b925050505b9392505050565b6060610f2883836000610e90565b6000806000846001600160a01b031684604051610f5a9190611563565b6000604051808303816000865af19150503d8060008114610f97576040519150601f19603f3d011682016040523d82523d6000602084013e610f9c565b606091505b5091509150818015610fc6575080511580610fc6575080806020019051810190610fc69190611520565b8015610fdc57506000856001600160a01b03163b115b95945050505050565b606082610ffa57610ff582611041565b610f28565b815115801561101157506001600160a01b0384163b155b1561103a57604051639996b31560e01b81526001600160a01b0385166004820152602401610441565b5080610f28565b8051156110515780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60006020828403121561107c57600080fd5b813567ffffffffffffffff81111561109357600080fd5b820160c08185031215610f2857600080fd5b60008083601f8401126110b757600080fd5b50813567ffffffffffffffff8111156110cf57600080fd5b6020830191508360208260051b850101111561060857600080fd5b600080602083850312156110fd57600080fd5b823567ffffffffffffffff81111561111457600080fd5b611120858286016110a5565b90969095509350505050565b6001600160a01b038116811461045357600080fd5b8035610bd88161112c565b60006020828403121561115e57600080fd5b8135610f288161112c565b60008060006040848603121561117e57600080fd5b83356111898161112c565b9250602084013567ffffffffffffffff8111156111a557600080fd5b6111b1868287016110a5565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff811182821017156111f7576111f76111be565b60405290565b6040516060810167ffffffffffffffff811182821017156111f7576111f76111be565b604051601f8201601f1916810167ffffffffffffffff81118282101715611249576112496111be565b604052919050565b600067ffffffffffffffff82111561126b5761126b6111be565b50601f01601f191660200190565b600082601f83011261128a57600080fd5b813561129d61129882611251565b611220565b8181528460208386010111156112b257600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156112e157600080fd5b813567ffffffffffffffff8111156112f857600080fd5b61130484828501611279565b949350505050565b60005b8381101561132757818101518382015260200161130f565b50506000910152565b60208152815160208201526001600160a01b0360208301511660408201526000604083015160608084015280518060808501526113748160a086016020850161130c565b601f01601f19169290920160a0019392505050565b600060c0823603121561139b57600080fd5b6113a36111d4565b6113ac83611141565b8152602083013560208201526113c460408401611141565b604082015260608301356060820152608083013567ffffffffffffffff808211156113ee57600080fd5b6113fa36838701611279565b608084015260a085013591508082111561141357600080fd5b5061142036828601611279565b60a08301525092915050565b6000602080838503121561143f57600080fd5b825167ffffffffffffffff8082111561145757600080fd5b908401906060828703121561146b57600080fd5b6114736111fd565b82518152838301516114848161112c565b8185015260408301518281111561149a57600080fd5b80840193505086601f8401126114af57600080fd5b825191506114bf61129883611251565b82815287858486010111156114d357600080fd5b6114e28386830187870161130c565b60408201529695505050505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561151957600080fd5b5051919050565b60006020828403121561153257600080fd5b81518015158114610f2857600080fd5b818103818111156103ef57634e487b7160e01b600052601160045260246000fd5b6000825161157581846020870161130c565b919091019291505056fea164736f6c6343000814000a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$2.91
Net Worth in ETH
0.001013
Token Allocations
USDT
99.59%
ETH
0.41%
Multichain Portfolio | 35 Chains
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.