More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 68 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Init Flash | 21933915 | 54 days ago | IN | 0 ETH | 0.00033881 | ||||
Init Flash | 21237651 | 151 days ago | IN | 0 ETH | 0.00392444 | ||||
Init Flash | 21185404 | 158 days ago | IN | 0 ETH | 0.00933176 | ||||
Init Flash | 21132787 | 166 days ago | IN | 0 ETH | 0.00470733 | ||||
Init Flash | 21042916 | 178 days ago | IN | 0 ETH | 0.00201754 | ||||
Init Flash | 20762964 | 217 days ago | IN | 0 ETH | 0.00172355 | ||||
Init Flash | 20695534 | 227 days ago | IN | 0 ETH | 0.00019075 | ||||
Init Flash | 20556272 | 246 days ago | IN | 0 ETH | 0.00044821 | ||||
Init Flash | 20551339 | 247 days ago | IN | 0 ETH | 0.00040803 | ||||
Init Flash | 19883737 | 340 days ago | IN | 0 ETH | 0.00172531 | ||||
Init Flash | 19776431 | 355 days ago | IN | 0 ETH | 0.00106916 | ||||
Init Flash | 19776064 | 355 days ago | IN | 0 ETH | 0.00342888 | ||||
Init Flash | 19689833 | 367 days ago | IN | 0 ETH | 0.00486562 | ||||
Init Flash | 19640385 | 374 days ago | IN | 0 ETH | 0.00786929 | ||||
Init Flash | 19640382 | 374 days ago | IN | 0 ETH | 0.00852842 | ||||
Init Flash | 19598297 | 380 days ago | IN | 0 ETH | 0.00409938 | ||||
Init Flash | 19568661 | 384 days ago | IN | 0 ETH | 0.0074092 | ||||
Init Flash | 19568651 | 384 days ago | IN | 0 ETH | 0.01663571 | ||||
Init Flash | 19539700 | 388 days ago | IN | 0 ETH | 0.00700764 | ||||
Init Flash | 19530085 | 390 days ago | IN | 0 ETH | 0.00734376 | ||||
Init Flash | 19493449 | 395 days ago | IN | 0 ETH | 0.00594082 | ||||
Init Flash | 19443124 | 402 days ago | IN | 0 ETH | 0.00904538 | ||||
Init Flash | 19415278 | 406 days ago | IN | 0 ETH | 0.01885989 | ||||
Init Flash | 19390775 | 409 days ago | IN | 0 ETH | 0.01642802 | ||||
Init Flash | 19380349 | 411 days ago | IN | 0 ETH | 0.01536127 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 22319569 | 12 hrs ago | 0.00025721 ETH | ||||
Payback | 22319569 | 12 hrs ago | 0.02546386 ETH | ||||
Transfer | 22319569 | 12 hrs ago | 0.02572107 ETH | ||||
Transfer | 22312518 | 36 hrs ago | 0.00026044 ETH | ||||
Payback | 22312518 | 36 hrs ago | 0.03335768 ETH | ||||
Transfer | 22312518 | 36 hrs ago | 0.03361812 ETH | ||||
Transfer | 22312342 | 36 hrs ago | 0.00027916 ETH | ||||
Payback | 22312342 | 36 hrs ago | 0.03211519 ETH | ||||
Transfer | 22312342 | 36 hrs ago | 0.03239436 ETH | ||||
Transfer | 22290550 | 4 days ago | 0.00017993 ETH | ||||
Payback | 22290550 | 4 days ago | 0.01781376 ETH | ||||
Transfer | 22290550 | 4 days ago | 0.0179937 ETH | ||||
Transfer | 22285564 | 5 days ago | 0.00026189 ETH | ||||
Payback | 22285564 | 5 days ago | 0.03714971 ETH | ||||
Transfer | 22285564 | 5 days ago | 0.0374116 ETH | ||||
Transfer | 22279299 | 6 days ago | 0.0002808 ETH | ||||
Payback | 22279299 | 6 days ago | 0.03355494 ETH | ||||
Transfer | 22279299 | 6 days ago | 0.03383575 ETH | ||||
Transfer | 22277402 | 6 days ago | 0.00039739 ETH | ||||
Payback | 22277402 | 6 days ago | 0.04110708 ETH | ||||
Transfer | 22277402 | 6 days ago | 0.04150448 ETH | ||||
Transfer | 22277265 | 6 days ago | 0.00023503 ETH | ||||
Payback | 22277265 | 6 days ago | 0.02326867 ETH | ||||
Transfer | 22277265 | 6 days ago | 0.0235037 ETH | ||||
Transfer | 22273123 | 7 days ago | 0.00054965 ETH |
Loading...
Loading
Contract Name:
UniV3Swap
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IOracle} from "splits-oracle/interfaces/IOracle.sol"; import {ISwapRouter} from "v3-periphery/interfaces/ISwapRouter.sol"; import {IWETH9} from "splits-utils/interfaces/external/IWETH9.sol"; import {QuoteParams} from "splits-utils/LibQuotes.sol"; import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; import {TokenUtils} from "splits-utils/TokenUtils.sol"; import {ISwapperFlashCallback} from "../interfaces/ISwapperFlashCallback.sol"; import {SwapperImpl} from "../SwapperImpl.sol"; import {SwapperFactory} from "../SwapperFactory.sol"; /// @title Uniswap V3 Swapper Integration /// @author 0xSplits /// @notice Used by EOAs & simple bots to execute `Swapper#flash` with uniswap v3 /// @dev This contract uses token = address(0) to refer to ETH. contract UniV3Swap is ISwapperFlashCallback { using SafeTransferLib for address; using TokenUtils for address; error Unauthorized(); error InsufficientFunds(); struct InitFlashParams { QuoteParams[] quoteParams; FlashCallbackData flashCallbackData; } struct FlashCallbackData { ISwapRouter.ExactInputParams[] exactInputParams; address excessRecipient; } SwapperFactory public immutable swapperFactory; ISwapRouter public immutable swapRouter; IWETH9 public immutable weth9; constructor(SwapperFactory swapperFactory_, ISwapRouter swapRouter_, IWETH9 weth9_) { swapperFactory = swapperFactory_; swapRouter = swapRouter_; weth9 = weth9_; } /// receive from weth9 receive() external payable {} /// begin `Swapper#flash` /// @dev trader may pay ETH & include the extra WETH in `params_.exactInputParams` to make up /// for `Swapper#oracle` shortfall. If swapper incentives are insufficient and they still want to push /// funds to `beneficiary`. Recipient in `params_.exactInputParams` should always be _this_ contract /// so it can handle the approval / payback for Swapper function initFlash(SwapperImpl swapper, InitFlashParams calldata params_) external payable { swapper.flash(params_.quoteParams, abi.encode(params_.flashCallbackData)); } /// `Swapper#flash` callback /// @dev by end of function if `tokenToBeneficiary_` is ETH, must have sent `amountToBeneficiary_` /// to `Swapper#payback`. Otherwise, must approve Swapper to transfer `amountToBeneficiary_` /// DO NOT HOLD FUNDS IN THIS CONTRACT WITHOUT ADDING PROPER VERIFICATION OF MSG.SENDER function swapperFlashCallback(address tokenToBeneficiary_, uint256 amountToBeneficiary_, bytes calldata data_) external { FlashCallbackData memory flashCallbackData = abi.decode(data_, (FlashCallbackData)); ISwapRouter.ExactInputParams[] memory exactInputParams = flashCallbackData.exactInputParams; uint256 ethBalance = address(this).balance; if (ethBalance != 0) { weth9.deposit{value: ethBalance}(); } uint256 totalOut = (tokenToBeneficiary_._isETH()) ? weth9.balanceOf(address(this)) : tokenToBeneficiary_.balanceOf(address(this)); uint256 length = exactInputParams.length; for (uint256 i; i < length;) { ISwapRouter.ExactInputParams memory eip = exactInputParams[i]; address token = _getStartTokenFromPath(eip.path); token.safeApprove(address(swapRouter), eip.amountIn); totalOut += swapRouter.exactInput(eip); unchecked { ++i; } } if (totalOut < amountToBeneficiary_) revert InsufficientFunds(); address excessRecipient = flashCallbackData.excessRecipient; if (tokenToBeneficiary_._isETH()) { // withdraw WETH from uni swaps to ETH uint256 weth9Balance = weth9.balanceOf(address(this)); weth9.withdraw(weth9Balance); // send req'd amt to swapper#payback SwapperImpl(msg.sender).payback{value: amountToBeneficiary_}(); // xfr excess out ethBalance = address(this).balance; if (ethBalance != 0) { excessRecipient.safeTransferETH(ethBalance); } } else { // approve swapper to xfr req'd amt out tokenToBeneficiary_.safeApprove(msg.sender, amountToBeneficiary_); // xfr excess out uint256 excessBalance = ERC20(tokenToBeneficiary_).balanceOf(address(this)) - amountToBeneficiary_; if (excessBalance > 0) { tokenToBeneficiary_.safeTransfer(excessRecipient, excessBalance); } } } function _getStartTokenFromPath(bytes memory path) internal pure returns (address token) { assembly { token := mload(add(path, 0x14)) } } }
// 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: GPL-3.0-or-later pragma solidity ^0.8.17; import {QuoteParams} from "splits-utils/LibQuotes.sol"; /// @title Oracle Interface /// @author 0xSplits interface IOracle { function getQuoteAmounts(QuoteParams[] calldata quoteParams_) external view returns (uint256[] memory); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.5; pragma abicoder v2; import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol'; /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; /// @title Interface for WETH9 interface IWETH9 { /// @notice Deposit ether to get wrapped ether function deposit() external payable; /// @notice Withdraw wrapped ether to get ether function withdraw(uint256) external; function balanceOf(address) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {ConvertedQuotePair, SortedConvertedQuotePair} from "./ConvertedQuotePair.sol"; using {_sort, _convert, _convertAndSort} for QuotePair global; struct QuoteParams { QuotePair quotePair; uint128 baseAmount; bytes data; } struct QuotePair { address base; address quote; } struct SortedQuotePair { address token0; address token1; } function _sort(QuotePair memory qp) pure returns (SortedQuotePair memory) { return (qp.base > qp.quote) ? SortedQuotePair({token0: qp.quote, token1: qp.base}) : SortedQuotePair({token0: qp.base, token1: qp.quote}); } function _convert(QuotePair calldata qp, function (address) internal view returns (address) convert) view returns (ConvertedQuotePair memory) { return ConvertedQuotePair({cBase: convert(qp.base), cQuote: convert(qp.quote)}); } function _convertAndSort(QuotePair calldata qp, function (address) internal view returns (address) convert) view returns (SortedConvertedQuotePair memory) { return _convert(qp, convert)._sort(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH /// that disallows any storage writes. uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. /// Multiply by a small constant (e.g. 2), if needed. uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` (in wei) ETH to `to`. /// Reverts upon failure. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. if iszero(call(gas(), to, amount, 0, 0, 0, 0)) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 if iszero(create(amount, 0x0b, 0x16)) { // For better gas estimation. if iszero(gt(gas(), 1000000)) { revert(0, 0) } } } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default /// for 99% of cases and can be overriden with the three-argument version of this /// function if necessary. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount) internal { // Manually inlined because the compiler doesn't inline functions with branches. /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 if iszero(create(amount, 0x0b, 0x16)) { // For better gas estimation. if iszero(gt(gas(), 1000000)) { revert(0, 0) } } } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend. /// /// Note: Does NOT revert upon failure. /// Returns whether the transfer of ETH is successful instead. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. success := call(gasStipend, to, amount, 0, 0, 0, 0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x0c, 0x23b872dd000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // 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(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. // Store the function selector of `balanceOf(address)`. mstore(0x0c, 0x70a08231000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) // The `amount` argument is already written to the memory word at 0x6c. amount := mload(0x60) if iszero( and( // The arguments of `and` are evaluated from right to left. // 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(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `transfer(address,uint256)`. mstore(0x00, 0xa9059cbb000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // 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(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x34. amount := mload(0x34) // Store the function selector of `transfer(address,uint256)`. mstore(0x00, 0xa9059cbb000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // 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(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`. mstore(0x00, 0x095ea7b3000000000000000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // 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(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten. mstore(0x34, 0) } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. // Store the function selector of `balanceOf(address)`. mstore(0x00, 0x70a08231000000000000000000000000) amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; /// Library to handle basic token functions for ERC20s & ETH (represented by 0x0) library TokenUtils { using SafeTransferLib for address; address internal constant ETH_ADDRESS = address(0); function _isETH(address token) internal pure returns (bool) { return (token == ETH_ADDRESS); } function _decimals(address token) internal view returns (uint8) { return _isETH(token) ? 18 : ERC20(token).decimals(); } function _balanceOf(address token, address addr) internal view returns (uint256) { return _isETH(token) ? addr.balance : ERC20(token).balanceOf(addr); } function _safeTransfer(address token, address addr, uint256 amount) internal { if (_isETH(token)) addr.safeTransferETH(amount); else token.safeTransfer(addr, amount); } } interface ERC20 { function decimals() external view returns (uint8); function balanceOf(address addr) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; /// @title Swapper Flash Callback /// @author 0xSplits /// @notice Callback for `Swapper#flash` /// @dev any contract that calls `Swapper#flash` must implement this interface. /// Inspired by IUniswapV3FlashCallback interface ISwapperFlashCallback { /// Called to `msg.sender` in `Swapper#flash` after transferring `quoteParams`. /// @dev In the implementation you must complete the flash swap. /// If `tokenToBeneficiary` is ETH, you must deposit `amountToBeneficiary` via `Swapper#payback`. /// If `tokenToBeneficiary` is an ERC20, you must use approve Swapper to transfer `amountToBeneficiary`. /// The caller of this method will use token = address(0) to refer to ETH. /// @param tokenToBeneficiary The token due to the `beneficiary` by the end of `#flash` /// @param amountToBeneficiary The amount of `tokenToBeneficiary` due to the `beneficiary` by the end of `#flash` /// @param data Any `data` passed through by `msg.sender` of `Swapper#flash` function swapperFlashCallback(address tokenToBeneficiary, uint256 amountToBeneficiary, bytes calldata data) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {ERC20} from "solmate/tokens/ERC20.sol"; import {IOracle} from "splits-oracle/interfaces/IOracle.sol"; import {PausableImpl} from "splits-utils/PausableImpl.sol"; import {QuotePair, QuoteParams, SortedQuotePair} from "splits-utils/LibQuotes.sol"; import {SafeCastLib} from "solady/utils/SafeCastLib.sol"; import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol"; import {TokenUtils} from "splits-utils/TokenUtils.sol"; import {WalletImpl} from "splits-utils/WalletImpl.sol"; import {ISwapperFlashCallback} from "./interfaces/ISwapperFlashCallback.sol"; import {PairScaledOfferFactors} from "./libraries/PairScaledOfferFactors.sol"; /// @title Swapper Implementation /// @author 0xSplits /// @notice A contract to trustlessly & automatically convert multi-token /// onchain revenue into a particular output token. /// Please be aware, owner has _FULL CONTROL_ of the deployment. /// @dev This contract uses a modular oracle. Be very careful to use a secure /// oracle with sensible settings for the desired behavior. Insecure oracles /// will result in catastrophic loss of funds. /// This contract uses token = address(0) to refer to ETH. contract SwapperImpl is WalletImpl, PausableImpl { /// ----------------------------------------------------------------------- /// libraries /// ----------------------------------------------------------------------- using SafeTransferLib for address; using SafeCastLib for uint256; using TokenUtils for address; using PairScaledOfferFactors for mapping(address => mapping(address => uint32)); /// ----------------------------------------------------------------------- /// errors /// ----------------------------------------------------------------------- error Invalid_AmountsToBeneficiary(); error Invalid_QuoteToken(); error InsufficientFunds_InContract(); error InsufficientFunds_FromTrader(); /// ----------------------------------------------------------------------- /// structs /// ----------------------------------------------------------------------- struct InitParams { address owner; bool paused; address beneficiary; address tokenToBeneficiary; IOracle oracle; uint32 defaultScaledOfferFactor; SetPairScaledOfferFactorParams[] pairScaledOfferFactors; } struct SetPairScaledOfferFactorParams { QuotePair quotePair; uint32 scaledOfferFactor; } /// ----------------------------------------------------------------------- /// events /// ----------------------------------------------------------------------- event SetBeneficiary(address beneficiary); event SetTokenToBeneficiary(address tokenToBeneficiary); event SetOracle(IOracle oracle); event SetDefaultScaledOfferFactor(uint32 defaultScaledOfferFactor); event SetPairScaledOfferFactors(SetPairScaledOfferFactorParams[] params); event ReceiveETH(uint256 amount); event Payback(address indexed payer, uint256 amount); event Flash( address indexed beneficiary, address indexed trader, QuoteParams[] quoteParams, address tokenToBeneficiary, uint256[] amountsToBeneficiary, uint256 excessToBeneficiary ); /// ----------------------------------------------------------------------- /// storage /// ----------------------------------------------------------------------- /// ----------------------------------------------------------------------- /// storage - constants & immutables /// ----------------------------------------------------------------------- address public immutable swapperFactory; /// @dev percentages measured in hundredths of basis points uint32 internal constant PERCENTAGE_SCALE = 100_00_00; // = 100% /// ----------------------------------------------------------------------- /// storage - mutables /// ----------------------------------------------------------------------- /// slot 0 - 11 bytes free /// OwnableImpl storage /// address internal $owner; /// 20 bytes /// PausableImpl storage /// bool internal $paused; /// 1 byte /// slot 1 - 0 bytes free /// address to receive post-swap tokens address internal $beneficiary; /// 20 bytes /// used to track ETH payback in flash uint96 internal $_payback; /// 12 bytes /// slot 2 - 8 bytes free /// token type to send beneficiary /// @dev 0x0 used for ETH address internal $tokenToBeneficiary; /// 20 bytes /// default oracle price scaling factor /// @dev PERCENTAGE_SCALE = 1e6 = 100_00_00 = 100% = no discount or premium /// 99_00_00 = 99% = 1% discount to oracle; 101_00_00 = 101% = 1% premium to oracle /// 4 bytes uint32 internal $defaultScaledOfferFactor; /// slot 3 - 12 bytes free /// price oracle for `#flash` IOracle internal $oracle; /// 20 bytes /// slot 4 - 0 bytes free /// scaledOfferFactors for specific quote pairs /// 32 bytes mapping(address => mapping(address => uint32)) internal $_pairScaledOfferFactors; /// ----------------------------------------------------------------------- /// constructor & initializer /// ----------------------------------------------------------------------- constructor() { swapperFactory = msg.sender; } function initializer(InitParams calldata params_) external { // only swapperFactory may call `initializer` if (msg.sender != swapperFactory) revert Unauthorized(); // don't need to init wallet separately __initPausable({owner_: params_.owner, paused_: params_.paused}); $beneficiary = params_.beneficiary; $tokenToBeneficiary = params_.tokenToBeneficiary; $oracle = params_.oracle; $defaultScaledOfferFactor = params_.defaultScaledOfferFactor; $_pairScaledOfferFactors._set(params_.pairScaledOfferFactors); } /// ----------------------------------------------------------------------- /// functions /// ----------------------------------------------------------------------- /// ----------------------------------------------------------------------- /// functions - public & external /// ----------------------------------------------------------------------- /// ----------------------------------------------------------------------- /// functions - public & external - onlyOwner /// ----------------------------------------------------------------------- /// set beneficiary function setBeneficiary(address beneficiary_) external onlyOwner { $beneficiary = beneficiary_; emit SetBeneficiary(beneficiary_); } /// set tokenToBeneficiary function setTokenToBeneficiary(address tokenToBeneficiary_) external onlyOwner { $tokenToBeneficiary = tokenToBeneficiary_; emit SetTokenToBeneficiary(tokenToBeneficiary_); } /// set oracle function setOracle(IOracle oracle_) external onlyOwner { $oracle = oracle_; emit SetOracle(oracle_); } /// set defaultScaledOfferFactor function setDefaultScaledOfferFactor(uint32 defaultScaledOfferFactor_) external onlyOwner { $defaultScaledOfferFactor = defaultScaledOfferFactor_; emit SetDefaultScaledOfferFactor(defaultScaledOfferFactor_); } /// set pair scaled offer factors function setPairScaledOfferFactors(SetPairScaledOfferFactorParams[] calldata params_) external onlyOwner { $_pairScaledOfferFactors._set(params_); emit SetPairScaledOfferFactors(params_); } /// ----------------------------------------------------------------------- /// functions - public & external - view /// ----------------------------------------------------------------------- function beneficiary() external view returns (address) { return $beneficiary; } function tokenToBeneficiary() external view returns (address) { return $tokenToBeneficiary; } function oracle() external view returns (IOracle) { return $oracle; } function defaultScaledOfferFactor() external view returns (uint32) { return $defaultScaledOfferFactor; } /// get pair scaled offer factors for an array of quote pairs function getPairScaledOfferFactors(QuotePair[] calldata quotePairs_) external view returns (uint32[] memory pairScaledOfferFactors) { uint256 length = quotePairs_.length; pairScaledOfferFactors = new uint32[](length); for (uint256 i; i < length;) { pairScaledOfferFactors[i] = $_pairScaledOfferFactors._get(quotePairs_[i]); unchecked { ++i; } } } /// ----------------------------------------------------------------------- /// functions - public & external - permissionless /// ----------------------------------------------------------------------- /// emit event when receiving ETH /// @dev implemented w/i clone bytecode /* receive() external payable { */ /* emit ReceiveETH(msg.value); */ /* } */ /// allows `#flash` to track ETH payback to `beneficiary` /// @dev if used outside `#swapperFlashCallback`, msg.sender may lose funds. /// Accumulates until next flash call function payback() external payable { $_payback += msg.value.toUint96(); emit Payback(msg.sender, msg.value); } /// allow third parties to withdraw tokens in return for sending `tokenToBeneficiary` to `beneficiary` function flash(QuoteParams[] calldata quoteParams_, bytes calldata callbackData_) external pausable returns (uint256) { address _tokenToBeneficiary = $tokenToBeneficiary; (uint256 amountToBeneficiary, uint256[] memory amountsToBeneficiary) = _transferToTrader(_tokenToBeneficiary, quoteParams_); ISwapperFlashCallback(msg.sender).swapperFlashCallback({ tokenToBeneficiary: _tokenToBeneficiary, amountToBeneficiary: amountToBeneficiary, data: callbackData_ }); address _beneficiary = $beneficiary; uint256 excessToBeneficiary = _transferToBeneficiary(_beneficiary, _tokenToBeneficiary, amountToBeneficiary); emit Flash( _beneficiary, msg.sender, quoteParams_, _tokenToBeneficiary, amountsToBeneficiary, excessToBeneficiary ); return amountToBeneficiary + excessToBeneficiary; } /// ----------------------------------------------------------------------- /// functions - private & internal /// ----------------------------------------------------------------------- function _transferToTrader(address tokenToBeneficiary_, QuoteParams[] calldata quoteParams_) internal returns (uint256 amountToBeneficiary, uint256[] memory amountsToBeneficiary) { uint256[] memory unscaledAmountsToBeneficiary = $oracle.getQuoteAmounts(quoteParams_); uint256 length = quoteParams_.length; if (unscaledAmountsToBeneficiary.length != length) revert Invalid_AmountsToBeneficiary(); amountsToBeneficiary = new uint256[](length); uint256 scaledAmountToBeneficiary; uint128 amountToTrader; address tokenToTrader; for (uint256 i; i < length;) { QuoteParams calldata qp = quoteParams_[i]; if (tokenToBeneficiary_ != qp.quotePair.quote) revert Invalid_QuoteToken(); tokenToTrader = qp.quotePair.base; amountToTrader = qp.baseAmount; if (amountToTrader > tokenToTrader._balanceOf(address(this))) { revert InsufficientFunds_InContract(); } uint32 scaledOfferFactor = $_pairScaledOfferFactors._get(qp.quotePair._sort()); if (scaledOfferFactor == 0) { scaledOfferFactor = $defaultScaledOfferFactor; } scaledAmountToBeneficiary = unscaledAmountsToBeneficiary[i] * scaledOfferFactor / PERCENTAGE_SCALE; amountsToBeneficiary[i] = scaledAmountToBeneficiary; amountToBeneficiary += scaledAmountToBeneficiary; tokenToTrader._safeTransfer(msg.sender, amountToTrader); unchecked { ++i; } } } function _transferToBeneficiary(address beneficiary_, address tokenToBeneficiary_, uint256 amountToBeneficiary_) internal returns (uint256 excessToBeneficiary) { if (tokenToBeneficiary_._isETH()) { if ($_payback < amountToBeneficiary_) { revert InsufficientFunds_FromTrader(); } $_payback = 0; // send ETH to `beneficiary` uint256 ethBalance = address(this).balance; excessToBeneficiary = ethBalance - amountToBeneficiary_; beneficiary_.safeTransferETH(ethBalance); } else { tokenToBeneficiary_.safeTransferFrom(msg.sender, beneficiary_, amountToBeneficiary_); // flush excess `tokenToBeneficiary` to `beneficiary` excessToBeneficiary = ERC20(tokenToBeneficiary_).balanceOf(address(this)); if (excessToBeneficiary > 0) { tokenToBeneficiary_.safeTransfer(beneficiary_, excessToBeneficiary); } } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {IOracle} from "splits-oracle/interfaces/IOracle.sol"; import {OracleParams} from "splits-oracle/peripherals/OracleParams.sol"; import {LibClone} from "splits-utils/LibClone.sol"; import {SwapperImpl} from "./SwapperImpl.sol"; /// @title Swapper Factory /// @author 0xSplits /// @notice Factory for creating Swappers /// @dev This contract uses token = address(0) to refer to ETH. contract SwapperFactory { using LibClone for address; event CreateSwapper(SwapperImpl indexed swapper, SwapperImpl.InitParams params); struct CreateSwapperParams { address owner; bool paused; address beneficiary; address tokenToBeneficiary; OracleParams oracleParams; uint32 defaultScaledOfferFactor; SwapperImpl.SetPairScaledOfferFactorParams[] pairScaledOfferFactors; } SwapperImpl public immutable swapperImpl; constructor() { swapperImpl = new SwapperImpl(); } /// ----------------------------------------------------------------------- /// functions - public & external /// ----------------------------------------------------------------------- function createSwapper(CreateSwapperParams calldata params_) external returns (SwapperImpl swapper) { IOracle oracle = params_.oracleParams._parseIntoOracle(); swapper = SwapperImpl(payable(address(swapperImpl).clone())); SwapperImpl.InitParams memory swapperInitParams = SwapperImpl.InitParams({ owner: params_.owner, paused: params_.paused, beneficiary: params_.beneficiary, tokenToBeneficiary: params_.tokenToBeneficiary, oracle: oracle, defaultScaledOfferFactor: params_.defaultScaledOfferFactor, pairScaledOfferFactors: params_.pairScaledOfferFactors }); swapper.initializer(swapperInitParams); emit CreateSwapper({swapper: swapper, params: swapperInitParams}); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; using {_sort} for ConvertedQuotePair global; struct ConvertedQuotePair { address cBase; address cQuote; } struct SortedConvertedQuotePair { address cToken0; address cToken1; } function _sort(ConvertedQuotePair memory cqp) pure returns (SortedConvertedQuotePair memory) { return (cqp.cBase > cqp.cQuote) ? SortedConvertedQuotePair({cToken0: cqp.cQuote, cToken1: cqp.cBase}) : SortedConvertedQuotePair({cToken0: cqp.cBase, cToken1: cqp.cQuote}); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {OwnableImpl} from "./OwnableImpl.sol"; /// @title Pausable Implementation /// @author 0xSplits /// @notice Pausable clone-implementation abstract contract PausableImpl is OwnableImpl { error Paused(); event SetPaused(bool paused); /// ----------------------------------------------------------------------- /// storage - mutables /// ----------------------------------------------------------------------- /// slot 0 - 11 bytes free /// OwnableImpl storage /// address internal $owner; /// 20 bytes bool internal $paused; /// 1 byte /// ----------------------------------------------------------------------- /// constructor & initializer /// ----------------------------------------------------------------------- constructor() {} function __initPausable(address owner_, bool paused_) internal virtual { OwnableImpl.__initOwnable(owner_); $paused = paused_; } /// ----------------------------------------------------------------------- /// modifiers /// ----------------------------------------------------------------------- modifier pausable() virtual { if (paused()) revert Paused(); _; } /// ----------------------------------------------------------------------- /// functions - public & external - onlyOwner /// ----------------------------------------------------------------------- function setPaused(bool paused_) public virtual onlyOwner { $paused = paused_; emit SetPaused(paused_); } /// ----------------------------------------------------------------------- /// functions - public & external - view /// ----------------------------------------------------------------------- function paused() public view virtual returns (bool) { return $paused; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe integer casting library that reverts on overflow. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error Overflow(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UNSIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toUint8(uint256 x) internal pure returns (uint8) { if (x >= 1 << 8) _revertOverflow(); return uint8(x); } function toUint16(uint256 x) internal pure returns (uint16) { if (x >= 1 << 16) _revertOverflow(); return uint16(x); } function toUint24(uint256 x) internal pure returns (uint24) { if (x >= 1 << 24) _revertOverflow(); return uint24(x); } function toUint32(uint256 x) internal pure returns (uint32) { if (x >= 1 << 32) _revertOverflow(); return uint32(x); } function toUint40(uint256 x) internal pure returns (uint40) { if (x >= 1 << 40) _revertOverflow(); return uint40(x); } function toUint48(uint256 x) internal pure returns (uint48) { if (x >= 1 << 48) _revertOverflow(); return uint48(x); } function toUint56(uint256 x) internal pure returns (uint56) { if (x >= 1 << 56) _revertOverflow(); return uint56(x); } function toUint64(uint256 x) internal pure returns (uint64) { if (x >= 1 << 64) _revertOverflow(); return uint64(x); } function toUint72(uint256 x) internal pure returns (uint72) { if (x >= 1 << 72) _revertOverflow(); return uint72(x); } function toUint80(uint256 x) internal pure returns (uint80) { if (x >= 1 << 80) _revertOverflow(); return uint80(x); } function toUint88(uint256 x) internal pure returns (uint88) { if (x >= 1 << 88) _revertOverflow(); return uint88(x); } function toUint96(uint256 x) internal pure returns (uint96) { if (x >= 1 << 96) _revertOverflow(); return uint96(x); } function toUint104(uint256 x) internal pure returns (uint104) { if (x >= 1 << 104) _revertOverflow(); return uint104(x); } function toUint112(uint256 x) internal pure returns (uint112) { if (x >= 1 << 112) _revertOverflow(); return uint112(x); } function toUint120(uint256 x) internal pure returns (uint120) { if (x >= 1 << 120) _revertOverflow(); return uint120(x); } function toUint128(uint256 x) internal pure returns (uint128) { if (x >= 1 << 128) _revertOverflow(); return uint128(x); } function toUint136(uint256 x) internal pure returns (uint136) { if (x >= 1 << 136) _revertOverflow(); return uint136(x); } function toUint144(uint256 x) internal pure returns (uint144) { if (x >= 1 << 144) _revertOverflow(); return uint144(x); } function toUint152(uint256 x) internal pure returns (uint152) { if (x >= 1 << 152) _revertOverflow(); return uint152(x); } function toUint160(uint256 x) internal pure returns (uint160) { if (x >= 1 << 160) _revertOverflow(); return uint160(x); } function toUint168(uint256 x) internal pure returns (uint168) { if (x >= 1 << 168) _revertOverflow(); return uint168(x); } function toUint176(uint256 x) internal pure returns (uint176) { if (x >= 1 << 176) _revertOverflow(); return uint176(x); } function toUint184(uint256 x) internal pure returns (uint184) { if (x >= 1 << 184) _revertOverflow(); return uint184(x); } function toUint192(uint256 x) internal pure returns (uint192) { if (x >= 1 << 192) _revertOverflow(); return uint192(x); } function toUint200(uint256 x) internal pure returns (uint200) { if (x >= 1 << 200) _revertOverflow(); return uint200(x); } function toUint208(uint256 x) internal pure returns (uint208) { if (x >= 1 << 208) _revertOverflow(); return uint208(x); } function toUint216(uint256 x) internal pure returns (uint216) { if (x >= 1 << 216) _revertOverflow(); return uint216(x); } function toUint224(uint256 x) internal pure returns (uint224) { if (x >= 1 << 224) _revertOverflow(); return uint224(x); } function toUint232(uint256 x) internal pure returns (uint232) { if (x >= 1 << 232) _revertOverflow(); return uint232(x); } function toUint240(uint256 x) internal pure returns (uint240) { if (x >= 1 << 240) _revertOverflow(); return uint240(x); } function toUint248(uint256 x) internal pure returns (uint248) { if (x >= 1 << 248) _revertOverflow(); return uint248(x); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toInt8(int256 x) internal pure returns (int8) { int8 y = int8(x); if (x != y) _revertOverflow(); return y; } function toInt16(int256 x) internal pure returns (int16) { int16 y = int16(x); if (x != y) _revertOverflow(); return y; } function toInt24(int256 x) internal pure returns (int24) { int24 y = int24(x); if (x != y) _revertOverflow(); return y; } function toInt32(int256 x) internal pure returns (int32) { int32 y = int32(x); if (x != y) _revertOverflow(); return y; } function toInt40(int256 x) internal pure returns (int40) { int40 y = int40(x); if (x != y) _revertOverflow(); return y; } function toInt48(int256 x) internal pure returns (int48) { int48 y = int48(x); if (x != y) _revertOverflow(); return y; } function toInt56(int256 x) internal pure returns (int56) { int56 y = int56(x); if (x != y) _revertOverflow(); return y; } function toInt64(int256 x) internal pure returns (int64) { int64 y = int64(x); if (x != y) _revertOverflow(); return y; } function toInt72(int256 x) internal pure returns (int72) { int72 y = int72(x); if (x != y) _revertOverflow(); return y; } function toInt80(int256 x) internal pure returns (int80) { int80 y = int80(x); if (x != y) _revertOverflow(); return y; } function toInt88(int256 x) internal pure returns (int88) { int88 y = int88(x); if (x != y) _revertOverflow(); return y; } function toInt96(int256 x) internal pure returns (int96) { int96 y = int96(x); if (x != y) _revertOverflow(); return y; } function toInt104(int256 x) internal pure returns (int104) { int104 y = int104(x); if (x != y) _revertOverflow(); return y; } function toInt112(int256 x) internal pure returns (int112) { int112 y = int112(x); if (x != y) _revertOverflow(); return y; } function toInt120(int256 x) internal pure returns (int120) { int120 y = int120(x); if (x != y) _revertOverflow(); return y; } function toInt128(int256 x) internal pure returns (int128) { int128 y = int128(x); if (x != y) _revertOverflow(); return y; } function toInt136(int256 x) internal pure returns (int136) { int136 y = int136(x); if (x != y) _revertOverflow(); return y; } function toInt144(int256 x) internal pure returns (int144) { int144 y = int144(x); if (x != y) _revertOverflow(); return y; } function toInt152(int256 x) internal pure returns (int152) { int152 y = int152(x); if (x != y) _revertOverflow(); return y; } function toInt160(int256 x) internal pure returns (int160) { int160 y = int160(x); if (x != y) _revertOverflow(); return y; } function toInt168(int256 x) internal pure returns (int168) { int168 y = int168(x); if (x != y) _revertOverflow(); return y; } function toInt176(int256 x) internal pure returns (int176) { int176 y = int176(x); if (x != y) _revertOverflow(); return y; } function toInt184(int256 x) internal pure returns (int184) { int184 y = int184(x); if (x != y) _revertOverflow(); return y; } function toInt192(int256 x) internal pure returns (int192) { int192 y = int192(x); if (x != y) _revertOverflow(); return y; } function toInt200(int256 x) internal pure returns (int200) { int200 y = int200(x); if (x != y) _revertOverflow(); return y; } function toInt208(int256 x) internal pure returns (int208) { int208 y = int208(x); if (x != y) _revertOverflow(); return y; } function toInt216(int256 x) internal pure returns (int216) { int216 y = int216(x); if (x != y) _revertOverflow(); return y; } function toInt224(int256 x) internal pure returns (int224) { int224 y = int224(x); if (x != y) _revertOverflow(); return y; } function toInt232(int256 x) internal pure returns (int232) { int232 y = int232(x); if (x != y) _revertOverflow(); return y; } function toInt240(int256 x) internal pure returns (int240) { int240 y = int240(x); if (x != y) _revertOverflow(); return y; } function toInt248(int256 x) internal pure returns (int248) { int248 y = int248(x); if (x != y) _revertOverflow(); return y; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UNSIGNED TO SIGNED SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function toInt256(uint256 x) internal pure returns (int256) { if (x >= 1 << 255) _revertOverflow(); return int256(x); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function _revertOverflow() private pure { /// @solidity memory-safe-assembly assembly { // Store the function selector of `Overflow()`. mstore(0x00, 0x35278d12) // Revert with (offset, size). revert(0x1c, 0x04) } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {ERC1155TokenReceiver} from "solmate/tokens/ERC1155.sol"; import {ERC721TokenReceiver} from "solmate/tokens/ERC721.sol"; import {OwnableImpl} from "./OwnableImpl.sol"; /// @title Wallet Implementation /// @author 0xSplits /// @notice Minimal smart wallet clone-implementation abstract contract WalletImpl is OwnableImpl, ERC721TokenReceiver, ERC1155TokenReceiver { struct Call { address to; uint256 value; bytes data; } event ExecCalls(Call[] calls); /// ----------------------------------------------------------------------- /// storage - mutables /// ----------------------------------------------------------------------- /// slot 0 - 12 bytes free /// OwnableImpl storage /// address internal $owner; /// 20 bytes /// ----------------------------------------------------------------------- /// constructor & initializer /// ----------------------------------------------------------------------- constructor() {} function __initWallet(address owner_) internal { OwnableImpl.__initOwnable(owner_); } /// ----------------------------------------------------------------------- /// functions - external & public - onlyOwner /// ----------------------------------------------------------------------- /// allow owner to execute arbitrary calls function execCalls(Call[] calldata calls_) external payable onlyOwner returns (uint256 blockNumber, bytes[] memory returnData) { blockNumber = block.number; uint256 length = calls_.length; returnData = new bytes[](length); bool success; for (uint256 i; i < length;) { Call calldata calli = calls_[i]; (success, returnData[i]) = calli.to.call{value: calli.value}(calli.data); require(success, string(returnData[i])); unchecked { ++i; } } emit ExecCalls(calls_); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {QuotePair, SortedQuotePair} from "splits-utils/LibQuotes.sol"; import {SwapperImpl} from "../SwapperImpl.sol"; /// @title PairScaledOfferFactors Library /// @author 0xSplits /// @notice Setters & getters for quote pairs' scaledOfferFactors library PairScaledOfferFactors { /// set pairs' scaled offer factors function _set( mapping(address => mapping(address => uint32)) storage self, SwapperImpl.SetPairScaledOfferFactorParams[] calldata params_ ) internal { uint256 length = params_.length; for (uint256 i; i < length;) { _set(self, params_[i]); unchecked { ++i; } } } /// set pair's scaled offer factor function _set( mapping(address => mapping(address => uint32)) storage self, SwapperImpl.SetPairScaledOfferFactorParams calldata params_ ) internal { SortedQuotePair memory sqp = params_.quotePair._sort(); self[sqp.token0][sqp.token1] = params_.scaledOfferFactor; } /// get pair's scaled offer factor function _get(mapping(address => mapping(address => uint32)) storage self, QuotePair calldata quotePair_) internal view returns (uint32) { return _get(self, quotePair_._sort()); } /// get pair's scaled offer factor function _get(mapping(address => mapping(address => uint32)) storage self, SortedQuotePair memory sqp_) internal view returns (uint32) { return self[sqp_.token0][sqp_.token1]; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {AddressUtils} from "splits-utils/AddressUtils.sol"; import {IOracle} from "../interfaces/IOracle.sol"; import {IOracleFactory} from "../interfaces/IOracleFactory.sol"; using {_parseIntoOracle} for OracleParams global; using AddressUtils for address; struct OracleParams { IOracle oracle; CreateOracleParams createOracleParams; } struct CreateOracleParams { IOracleFactory factory; bytes data; } function _parseIntoOracle(OracleParams calldata oracleParams_) returns (IOracle) { if (address(oracleParams_.oracle)._isNotEmpty()) { return oracleParams_.oracle; } else { // if oracle not provided, create one with provided params CreateOracleParams calldata createOracleParams = oracleParams_.createOracleParams; return createOracleParams.factory.createOracle(createOracleParams.data); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; /// @title Modified minimal proxy /// @author 0xSplits /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol) /// @dev Modified minimal proxy includes a `receive()` method that emits the /// `ReceiveETH(uint256)` event to skip `DELEGATECALL` when there is no calldata. /// Enables us to accept hard gas-capped `sends` & `transfers` for maximum backwards /// composability. library LibClone { error DeploymentFailed(); uint256 private constant FREE_PTR = 0x40; uint256 private constant ZERO_PTR = 0x60; /// @dev Deploys a modified minimal proxy of `implementation` function clone(address implementation) internal returns (address instance) { assembly ("memory-safe") { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes - 0x09) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (89 bytes - 0x59) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * 36 | CALLDATASIZE | cds | | * 60 0x2c | PUSH1 0x2c | 0x2c cds | | * 57 | JUMPI | | | * 34 | CALLVALUE | cv | | * 3d | RETURNDATASIZE | 0 cv | | * 52 | MSTORE | | [0..0x20): callvalue | * 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue | * 59 | MSIZE | 0x20 sig | [0..0x20): callvalue | * 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue | * a1 | LOG1 | | [0..0x20): callvalue | * 00 | STOP | | [0..0x20): callvalue | * 5b | JUMPDEST | | | * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | | * 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x57 | PUSH1 0x57 | 0x57 success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ * TOTAL INIT (98 bytes - 0x62) | * --------------------------------------------------------------------------| */ // save free pointer let fp := mload(FREE_PTR) mstore(0x51, 0x5af43d3d93803e605757fd5bf3) // 13 bytes mstore(0x44, implementation) // 20 bytes mstore(0x30, 0x593da1005b3d3d3d3d363d3d37363d73) // 16 bytes // `keccak256("ReceiveETH(uint256)")` mstore(0x20, 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff) // 32 bytes mstore(0x00, 0x60593d8160093d39f336602c57343d527f) // 17 bytes // total: 113 bytes = 0x71 // offset: 15 bytes = 0x0f // data: 98 bytes = 0x62 instance := create(0, 0x0f, 0x71) // restore free pointer, zero slot mstore(FREE_PTR, fp) mstore(ZERO_PTR, 0) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; /// @title Ownable Implementation /// @author 0xSplits /// @notice Ownable clone-implementation abstract contract OwnableImpl { error Unauthorized(); event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// ----------------------------------------------------------------------- /// storage - mutables /// ----------------------------------------------------------------------- /// slot 0 - 12 bytes free address internal $owner; /// 20 bytes /// ----------------------------------------------------------------------- /// constructor & initializer /// ----------------------------------------------------------------------- constructor() {} function __initOwnable(address owner_) internal virtual { emit OwnershipTransferred(address(0), owner_); $owner = owner_; } /// ----------------------------------------------------------------------- /// modifiers /// ----------------------------------------------------------------------- modifier onlyOwner() virtual { if (msg.sender != owner()) revert Unauthorized(); _; } /// ----------------------------------------------------------------------- /// functions - public & external - onlyOwner /// ----------------------------------------------------------------------- function transferOwnership(address owner_) public virtual onlyOwner { $owner = owner_; emit OwnershipTransferred(msg.sender, owner_); } /// ----------------------------------------------------------------------- /// functions - public & external - view /// ----------------------------------------------------------------------- function owner() public view virtual returns (address) { return $owner; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Minimalist and gas efficient standard ERC1155 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) abstract contract ERC1155 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event URI(string value, uint256 indexed id); /*////////////////////////////////////////////////////////////// ERC1155 STORAGE //////////////////////////////////////////////////////////////*/ mapping(address => mapping(uint256 => uint256)) public balanceOf; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// METADATA LOGIC //////////////////////////////////////////////////////////////*/ function uri(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC1155 LOGIC //////////////////////////////////////////////////////////////*/ function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); balanceOf[from][id] -= amount; balanceOf[to][id] += amount; emit TransferSingle(msg.sender, from, to, id, amount); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) == ERC1155TokenReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { require(ids.length == amounts.length, "LENGTH_MISMATCH"); require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); // Storing these outside the loop saves ~15 gas per iteration. uint256 id; uint256 amount; for (uint256 i = 0; i < ids.length; ) { id = ids[i]; amount = amounts[i]; balanceOf[from][id] -= amount; balanceOf[to][id] += amount; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, from, to, ids, amounts); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) == ERC1155TokenReceiver.onERC1155BatchReceived.selector, "UNSAFE_RECIPIENT" ); } function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { require(owners.length == ids.length, "LENGTH_MISMATCH"); balances = new uint256[](owners.length); // Unchecked because the only math done is incrementing // the array index counter which cannot possibly overflow. unchecked { for (uint256 i = 0; i < owners.length; ++i) { balances[i] = balanceOf[owners[i]][ids[i]]; } } } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155 interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { balanceOf[to][id] += amount; emit TransferSingle(msg.sender, address(0), to, id, amount); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) == ERC1155TokenReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { uint256 idsLength = ids.length; // Saves MLOADs. require(idsLength == amounts.length, "LENGTH_MISMATCH"); for (uint256 i = 0; i < idsLength; ) { balanceOf[to][ids[i]] += amounts[i]; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, address(0), to, ids, amounts); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) == ERC1155TokenReceiver.onERC1155BatchReceived.selector, "UNSAFE_RECIPIENT" ); } function _batchBurn( address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual { uint256 idsLength = ids.length; // Saves MLOADs. require(idsLength == amounts.length, "LENGTH_MISMATCH"); for (uint256 i = 0; i < idsLength; ) { balanceOf[from][ids[i]] -= amounts[i]; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, from, address(0), ids, amounts); } function _burn( address from, uint256 id, uint256 amount ) internal virtual { balanceOf[from][id] -= amount; emit TransferSingle(msg.sender, from, address(0), id, amount); } } /// @notice A generic interface for a contract which properly accepts ERC1155 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) abstract contract ERC1155TokenReceiver { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC1155TokenReceiver.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external virtual returns (bytes4) { return ERC1155TokenReceiver.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern, minimalist, and gas efficient ERC-721 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 indexed id); event Approval(address indexed owner, address indexed spender, uint256 indexed id); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /*////////////////////////////////////////////////////////////// METADATA STORAGE/LOGIC //////////////////////////////////////////////////////////////*/ string public name; string public symbol; function tokenURI(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; function ownerOf(uint256 id) public view virtual returns (address owner) { require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); } function balanceOf(address owner) public view virtual returns (uint256) { require(owner != address(0), "ZERO_ADDRESS"); return _balanceOf[owner]; } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 id) public virtual { address owner = _ownerOf[id]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); getApproved[id] = spender; emit Approval(owner, spender, id); } function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function transferFrom( address from, address to, uint256 id ) public virtual { require(from == _ownerOf[id], "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" ); // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. unchecked { _balanceOf[from]--; _balanceOf[to]++; } _ownerOf[id] = to; delete getApproved[id]; emit Transfer(from, to, id); } function safeTransferFrom( address from, address to, uint256 id ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function safeTransferFrom( address from, address to, uint256 id, bytes calldata data ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 id) internal virtual { require(to != address(0), "INVALID_RECIPIENT"); require(_ownerOf[id] == address(0), "ALREADY_MINTED"); // Counter overflow is incredibly unrealistic. unchecked { _balanceOf[to]++; } _ownerOf[id] = to; emit Transfer(address(0), to, id); } function _burn(uint256 id) internal virtual { address owner = _ownerOf[id]; require(owner != address(0), "NOT_MINTED"); // Ownership check above ensures no underflow. unchecked { _balanceOf[owner]--; } delete _ownerOf[id]; delete getApproved[id]; emit Transfer(owner, address(0), id); } /*////////////////////////////////////////////////////////////// INTERNAL SAFE MINT LOGIC //////////////////////////////////////////////////////////////*/ function _safeMint(address to, uint256 id) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function _safeMint( address to, uint256 id, bytes memory data ) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } } /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; address constant ADDRESS_ZERO = address(0); library AddressUtils { function _isEmpty(address addr) internal pure returns (bool) { return (addr == ADDRESS_ZERO); } function _isNotEmpty(address addr) internal pure returns (bool) { return (addr != ADDRESS_ZERO); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.17; import {IOracle} from "./IOracle.sol"; /// @title Oracle factory interface interface IOracleFactory { function createOracle(bytes calldata data_) external returns (IOracle); }
{ "remappings": [ "@uniswap/v3-core/=lib/splits-oracle/lib/v3-core/", "@uniswap/v3-periphery/=lib/v3-periphery/", "chainlink/=lib/splits-oracle/lib/chainlink/contracts/src/v0.8/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solady/=lib/solady/src/", "solmate/=lib/solmate/src/", "splits-oracle/=lib/splits-oracle/src/", "splits-tests/=lib/splits-utils/test/", "splits-utils/=lib/splits-utils/src/", "v3-core/=lib/splits-oracle/lib/v3-core/contracts/", "v3-periphery/=lib/v3-periphery/contracts/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract SwapperFactory","name":"swapperFactory_","type":"address"},{"internalType":"contract ISwapRouter","name":"swapRouter_","type":"address"},{"internalType":"contract IWETH9","name":"weth9_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"contract SwapperImpl","name":"swapper","type":"address"},{"components":[{"components":[{"components":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"}],"internalType":"struct QuotePair","name":"quotePair","type":"tuple"},{"internalType":"uint128","name":"baseAmount","type":"uint128"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct QuoteParams[]","name":"quoteParams","type":"tuple[]"},{"components":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactInputParams[]","name":"exactInputParams","type":"tuple[]"},{"internalType":"address","name":"excessRecipient","type":"address"}],"internalType":"struct UniV3Swap.FlashCallbackData","name":"flashCallbackData","type":"tuple"}],"internalType":"struct UniV3Swap.InitFlashParams","name":"params_","type":"tuple"}],"name":"initFlash","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapperFactory","outputs":[{"internalType":"contract SwapperFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenToBeneficiary_","type":"address"},{"internalType":"uint256","name":"amountToBeneficiary_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"swapperFlashCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth9","outputs":[{"internalType":"contract IWETH9","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e060405234801561001057600080fd5b50604051620013cc380380620013cc83398101604081905261003191610066565b6001600160a01b0392831660805290821660a0521660c0526100b3565b6001600160a01b038116811461006357600080fd5b50565b60008060006060848603121561007b57600080fd5b83516100868161004e565b60208501519093506100978161004e565b60408501519092506100a88161004e565b809150509250925092565b60805160a05160c0516112c06200010c6000396000818160b1015281816102380152818161032901528181610593015261064501526000818161010e015281816103ef01526104760152600061014201526112c06000f3fe60806040526004361061005e5760003560e01c806350879c1c1161004357806350879c1c1461009f578063c31c9c07146100fc578063d122d54a1461013057600080fd5b80631faf83c31461006a5780632602cbb71461007f57600080fd5b3661006557005b600080fd5b61007d61007836600461094b565b610164565b005b34801561008b57600080fd5b5061007d61009a3660046109b2565b61021c565b3480156100ab57600080fd5b506100d37f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b34801561010857600080fd5b506100d37f000000000000000000000000000000000000000000000000000000000000000081565b34801561013c57600080fd5b506100d37f000000000000000000000000000000000000000000000000000000000000000081565b73ffffffffffffffffffffffffffffffffffffffff82166392987f8561018a8380610a3b565b6101976020860186610aaa565b6040516020016101a79190610b95565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016101d493929190610d98565b6020604051808303816000875af11580156101f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102179190610ed5565b505050565b600061022a82840184610fb8565b80519091504780156102b8577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561029e57600080fd5b505af11580156102b2573d6000803e3d6000fd5b50505050505b600073ffffffffffffffffffffffffffffffffffffffff8816156102fb576102f673ffffffffffffffffffffffffffffffffffffffff89163061083d565b6103a9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a99190610ed5565b835190915060005b818110156105075760008582815181106103cd576103cd61119a565b6020026020010151905060006103e882600001516014015190565b90506104397f000000000000000000000000000000000000000000000000000000000000000083606001518373ffffffffffffffffffffffffffffffffffffffff166108729092919063ffffffff16565b6040517fc04b8d5900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c04b8d59906104ab9085906004016111c9565b6020604051808303816000875af11580156104ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ee9190610ed5565b6104f8908661125e565b945082600101925050506103b1565b5087821015610542576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602085015173ffffffffffffffffffffffffffffffffffffffff8a16610748576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156105ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106139190610ed5565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561069e57600080fd5b505af11580156106b2573d6000803e3d6000fd5b505050503373ffffffffffffffffffffffffffffffffffffffff1663854bec878b6040518263ffffffff1660e01b81526004016000604051808303818588803b1580156106fe57600080fd5b505af1158015610712573d6000803e3d6000fd5b5050505050479450846000146107425761074273ffffffffffffffffffffffffffffffffffffffff8316866108c1565b50610831565b61076973ffffffffffffffffffffffffffffffffffffffff8b16338b610872565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000908a9073ffffffffffffffffffffffffffffffffffffffff8d16906370a0823190602401602060405180830381865afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc9190610ed5565b6108069190611277565b9050801561082f5761082f73ffffffffffffffffffffffffffffffffffffffff8c1683836108e1565b505b50505050505050505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af13d1560016000511417166108b757633e3f8f736000526004601cfd5b6000603452505050565b60008060008084865af16108dd5763b12d13eb6000526004601cfd5b5050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d1560016000511417166108b7576390b8ec186000526004601cfd5b73ffffffffffffffffffffffffffffffffffffffff8116811461094857600080fd5b50565b6000806040838503121561095e57600080fd5b823561096981610926565b9150602083013567ffffffffffffffff81111561098557600080fd5b83016040818603121561099757600080fd5b809150509250929050565b80356109ad81610926565b919050565b600080600080606085870312156109c857600080fd5b84356109d381610926565b935060208501359250604085013567ffffffffffffffff808211156109f757600080fd5b818701915087601f830112610a0b57600080fd5b813581811115610a1a57600080fd5b886020828501011115610a2c57600080fd5b95989497505060200194505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610a7057600080fd5b83018035915067ffffffffffffffff821115610a8b57600080fd5b6020019150600581901b3603821315610aa357600080fd5b9250929050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610ade57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b1d57600080fd5b830160208101925035905067ffffffffffffffff811115610b3d57600080fd5b803603821315610aa357600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600060208083526060830184357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112610bd257600080fd5b8501803583820167ffffffffffffffff821115610bee57600080fd5b8160051b803603821315610c0157600080fd5b604088870181905294839052608094908801850190858901600080368890037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41015b87821015610cfd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808d87030184528635818112610c7f578384fd5b89018b810160a0610c908280610ae8565b9250818a52610ca2828b018483610b4c565b92505087830135610cb281610926565b73ffffffffffffffffffffffffffffffffffffffff16898f0152606083810135898b01528d840135908a015290910135968b0196909652958a0195928a019260019190910190610c43565b50505050610d0c878b016109a2565b73ffffffffffffffffffffffffffffffffffffffff1698019790975250949695505050505050565b6000815180845260005b81811015610d5a57602081850181015186830182015201610d3e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60408082528181018490526000906060808401600587901b8501820188855b89811015610eb4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088840301845281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff818c3603018112610e1857600080fd5b8b0160808135610e2781610926565b73ffffffffffffffffffffffffffffffffffffffff908116865260209083820135610e5181610926565b1686820152828901356fffffffffffffffffffffffffffffffff8116808214610e7957600080fd5b878b015250610e8a83890184610ae8565b93508289880152610e9e8388018583610b4c565b9782019796505093909301925050600101610db7565b50508581036020870152610ec88188610d34565b9998505050505050505050565b600060208284031215610ee757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610f4057610f40610eee565b60405290565b60405160a0810167ffffffffffffffff81118282101715610f4057610f40610eee565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610fb057610fb0610eee565b604052919050565b600060208284031215610fca57600080fd5b67ffffffffffffffff8083351115610fe157600080fd5b8235830160408186031215610ff557600080fd5b610ffd610f1d565b828235111561100b57600080fd5b8135820186601f82011261101e57600080fd5b838135111561102f5761102f610eee565b61103f6020823560051b01610f69565b81358082526020808301929160051b8401018981111561105e57600080fd5b602084015b8181101561117957878135111561107957600080fd5b803585017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060a081838f030112156110b057600080fd5b6110b8610f46565b8a602084013511156110c957600080fd5b602083013583018e603f8201126110df57600080fd5b60208101358c8111156110f4576110f4610eee565b611105602085601f84011601610f69565b93508084528f604082840101111561111c57600080fd5b806040830160208601376000908401602001525081815261113f604084016109a2565b6020820152606083013560408201526080830135606082015260a08301356080820152808752505050602084019350602081019050611063565b505083525061118c9050602083016109a2565b602082015295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081526000825160a060208401526111e560c0840182610d34565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156112715761127161122f565b92915050565b818103818111156112715761127161122f56fea26469706673582212200df864d4350734e1256b03291e5051b42eb906200a224a11f6ee54907e4331ab64736f6c63430008110033000000000000000000000000a244bbe019cf1ba177ee5a532250be2663fb55ca000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x60806040526004361061005e5760003560e01c806350879c1c1161004357806350879c1c1461009f578063c31c9c07146100fc578063d122d54a1461013057600080fd5b80631faf83c31461006a5780632602cbb71461007f57600080fd5b3661006557005b600080fd5b61007d61007836600461094b565b610164565b005b34801561008b57600080fd5b5061007d61009a3660046109b2565b61021c565b3480156100ab57600080fd5b506100d37f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b34801561010857600080fd5b506100d37f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156481565b34801561013c57600080fd5b506100d37f000000000000000000000000a244bbe019cf1ba177ee5a532250be2663fb55ca81565b73ffffffffffffffffffffffffffffffffffffffff82166392987f8561018a8380610a3b565b6101976020860186610aaa565b6040516020016101a79190610b95565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016101d493929190610d98565b6020604051808303816000875af11580156101f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102179190610ed5565b505050565b600061022a82840184610fb8565b80519091504780156102b8577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561029e57600080fd5b505af11580156102b2573d6000803e3d6000fd5b50505050505b600073ffffffffffffffffffffffffffffffffffffffff8816156102fb576102f673ffffffffffffffffffffffffffffffffffffffff89163061083d565b6103a9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a99190610ed5565b835190915060005b818110156105075760008582815181106103cd576103cd61119a565b6020026020010151905060006103e882600001516014015190565b90506104397f000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156483606001518373ffffffffffffffffffffffffffffffffffffffff166108729092919063ffffffff16565b6040517fc04b8d5900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564169063c04b8d59906104ab9085906004016111c9565b6020604051808303816000875af11580156104ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ee9190610ed5565b6104f8908661125e565b945082600101925050506103b1565b5087821015610542576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602085015173ffffffffffffffffffffffffffffffffffffffff8a16610748576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156105ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106139190610ed5565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561069e57600080fd5b505af11580156106b2573d6000803e3d6000fd5b505050503373ffffffffffffffffffffffffffffffffffffffff1663854bec878b6040518263ffffffff1660e01b81526004016000604051808303818588803b1580156106fe57600080fd5b505af1158015610712573d6000803e3d6000fd5b5050505050479450846000146107425761074273ffffffffffffffffffffffffffffffffffffffff8316866108c1565b50610831565b61076973ffffffffffffffffffffffffffffffffffffffff8b16338b610872565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000908a9073ffffffffffffffffffffffffffffffffffffffff8d16906370a0823190602401602060405180830381865afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc9190610ed5565b6108069190611277565b9050801561082f5761082f73ffffffffffffffffffffffffffffffffffffffff8c1683836108e1565b505b50505050505050505050565b6000816014526f70a0823100000000000000000000000060005260208060246010865afa601f3d111660205102905092915050565b81601452806034526f095ea7b300000000000000000000000060005260206000604460106000875af13d1560016000511417166108b757633e3f8f736000526004601cfd5b6000603452505050565b60008060008084865af16108dd5763b12d13eb6000526004601cfd5b5050565b81601452806034526fa9059cbb00000000000000000000000060005260206000604460106000875af13d1560016000511417166108b7576390b8ec186000526004601cfd5b73ffffffffffffffffffffffffffffffffffffffff8116811461094857600080fd5b50565b6000806040838503121561095e57600080fd5b823561096981610926565b9150602083013567ffffffffffffffff81111561098557600080fd5b83016040818603121561099757600080fd5b809150509250929050565b80356109ad81610926565b919050565b600080600080606085870312156109c857600080fd5b84356109d381610926565b935060208501359250604085013567ffffffffffffffff808211156109f757600080fd5b818701915087601f830112610a0b57600080fd5b813581811115610a1a57600080fd5b886020828501011115610a2c57600080fd5b95989497505060200194505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610a7057600080fd5b83018035915067ffffffffffffffff821115610a8b57600080fd5b6020019150600581901b3603821315610aa357600080fd5b9250929050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610ade57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610b1d57600080fd5b830160208101925035905067ffffffffffffffff811115610b3d57600080fd5b803603821315610aa357600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600060208083526060830184357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112610bd257600080fd5b8501803583820167ffffffffffffffff821115610bee57600080fd5b8160051b803603821315610c0157600080fd5b604088870181905294839052608094908801850190858901600080368890037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41015b87821015610cfd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808d87030184528635818112610c7f578384fd5b89018b810160a0610c908280610ae8565b9250818a52610ca2828b018483610b4c565b92505087830135610cb281610926565b73ffffffffffffffffffffffffffffffffffffffff16898f0152606083810135898b01528d840135908a015290910135968b0196909652958a0195928a019260019190910190610c43565b50505050610d0c878b016109a2565b73ffffffffffffffffffffffffffffffffffffffff1698019790975250949695505050505050565b6000815180845260005b81811015610d5a57602081850181015186830182015201610d3e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60408082528181018490526000906060808401600587901b8501820188855b89811015610eb4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088840301845281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff818c3603018112610e1857600080fd5b8b0160808135610e2781610926565b73ffffffffffffffffffffffffffffffffffffffff908116865260209083820135610e5181610926565b1686820152828901356fffffffffffffffffffffffffffffffff8116808214610e7957600080fd5b878b015250610e8a83890184610ae8565b93508289880152610e9e8388018583610b4c565b9782019796505093909301925050600101610db7565b50508581036020870152610ec88188610d34565b9998505050505050505050565b600060208284031215610ee757600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610f4057610f40610eee565b60405290565b60405160a0810167ffffffffffffffff81118282101715610f4057610f40610eee565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610fb057610fb0610eee565b604052919050565b600060208284031215610fca57600080fd5b67ffffffffffffffff8083351115610fe157600080fd5b8235830160408186031215610ff557600080fd5b610ffd610f1d565b828235111561100b57600080fd5b8135820186601f82011261101e57600080fd5b838135111561102f5761102f610eee565b61103f6020823560051b01610f69565b81358082526020808301929160051b8401018981111561105e57600080fd5b602084015b8181101561117957878135111561107957600080fd5b803585017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060a081838f030112156110b057600080fd5b6110b8610f46565b8a602084013511156110c957600080fd5b602083013583018e603f8201126110df57600080fd5b60208101358c8111156110f4576110f4610eee565b611105602085601f84011601610f69565b93508084528f604082840101111561111c57600080fd5b806040830160208601376000908401602001525081815261113f604084016109a2565b6020820152606083013560408201526080830135606082015260a08301356080820152808752505050602084019350602081019050611063565b505083525061118c9050602083016109a2565b602082015295945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081526000825160a060208401526111e560c0840182610d34565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156112715761127161122f565b92915050565b818103818111156112715761127161122f56fea26469706673582212200df864d4350734e1256b03291e5051b42eb906200a224a11f6ee54907e4331ab64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a244bbe019cf1ba177ee5a532250be2663fb55ca000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : swapperFactory_ (address): 0xa244bbe019cf1BA177EE5A532250be2663Fb55cA
Arg [1] : swapRouter_ (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
Arg [2] : weth9_ (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000a244bbe019cf1ba177ee5a532250be2663fb55ca
Arg [1] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.