Contract 0x6a1431bb23e08e3209dae3130b441863855fc14b 1

 
Txn Hash Method
Block
From
To
Value
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892Swap132304472024-04-16 6:50:415 mins ago0x473f2d4c0e3d598a444d67cd400434b7dac34e5c IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000346712150.020550246
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6Swap132304232024-04-16 6:49:535 mins ago0x7cf4ea3d0f42ba67e7c3b7cf8e9bfbba120d47a8 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.195 ETH0.0000340342180.019660087
0x5694060332b0833c23bf9c97f8e2e302f42ae79fc27f69d392d5cc82266b6b87Swap132301752024-04-16 6:41:3714 mins ago0xd51f3f73b00928668e4e69e744562f63a92a4980 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000355838030.020055656
0x1e1e8f3baba93c5ff024712f4c592d2c2d1cf234f2c0087dc96ccbaac74120a7Swap132301092024-04-16 6:39:2516 mins ago0x9dea1fa0d66833081268041fcd9a8c40cb71bf90 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000069276280.020456846
0x15242827c154a855e9551172fd0fa8a2ffdaca5bca805b41d505105499837d74Swap132300852024-04-16 6:38:3717 mins ago0x9dea1fa0d66833081268041fcd9a8c40cb71bf90 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000130529390.020818747
0xa2b9ff0679171c785d8eb4e6f9b4dc10c81e94d4647fb634255f1af5e9daacf3Swap132300662024-04-16 6:37:5917 mins ago0x9dea1fa0d66833081268041fcd9a8c40cb71bf90 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.000004080910.020962691
0x604c97a0235dc0473e0dcdacd2692ecb2f606b6665fcb9479b025aa3682b6f98Swap132300602024-04-16 6:37:4718 mins ago0xb8442d905536796186b91b569f24d7448014e084 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000091732520.0232
0xf1c9bf9143894c421a01a47b0ca9e16fe429b47d9761098513f5174383c24320Swap132299992024-04-16 6:35:4520 mins ago0x473f2d4c0e3d598a444d67cd400434b7dac34e5c IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000144998510.02222678
0xbb71a5c3ce7e2a33e2fba883f27c8f62704c69e233806fd4fa0965c4de1199edSwap132299232024-04-16 6:33:1322 mins ago0x473f2d4c0e3d598a444d67cd400434b7dac34e5c IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000123510260.022509361
0x402bcf49e445bb32ecbb54f8ca659a6aa5912578f38c12d9a1d9d0c61fff602eSwap132275372024-04-16 5:13:411 hr 42 mins ago0x5497f22ddb3911358700e5551bbbac6b2bb19d5e IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000081577470.0402
0x84aa889639854be72d0d6f63d413302afd511402ebebbe2d80856626bdf22770Swap132274412024-04-16 5:10:291 hr 45 mins ago0x5497f22ddb3911358700e5551bbbac6b2bb19d5e IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.000022397320.0405
0x7bc0f0e9a2e7b01919f6e7a7b6e75b20bfebde490411e2416408ef7172768ed3Swap132270442024-04-16 4:57:151 hr 58 mins ago0xb288b598da14b69e62b418f353b6cbde1c3d0610 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000038587870.046026807
0x1234db77e81a31cd69308d172663860aedb6597b0183d102dd96558c8cb013f7Swap132270282024-04-16 4:56:431 hr 59 mins ago0xb288b598da14b69e62b418f353b6cbde1c3d0610 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.01 ETH0.0000035194150.046026807
0xd08982e02e1dae665e44fadea536b9ec1c98c827315525375c23e5c3fa1002d5Swap132268592024-04-16 4:51:052 hrs 4 mins ago0x5a38f942b5a593652ec1eb844cae8865cdf99412 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000029556650.0351
0x80a108d5d616a13c2fa43e8685d588e7de42f5288e264df0157f3ff3fa2b605bSwap132265532024-04-16 4:40:532 hrs 14 mins ago0xf143c02efcb622c6f5a136c96e00846ed3658cfc IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000234360820.0293
0x8e66220af96bb9d77a6eca233476fa5447cfb4645025d6e11f2f6c75ac3c8224Swap132262082024-04-16 4:29:232 hrs 26 mins ago0x75493a42970056bd233a0eb7fa8e5c996e6c1733 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000363845280.027463737
0x5f38431ebc5765d26934238daf959847d5313c949901e90dcd180fb263201aa8Swap132245182024-04-16 3:33:033 hrs 22 mins ago0x7911fa8d5bfce62ef68b714d5b51a65a5732b101 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000097191530.0258
0x061487571a5358b975319021dfb105457381fa77d8a5aad46321568542196f93Swap132241972024-04-16 3:22:213 hrs 33 mins ago0x156480827880da4aa6aea3df9b0a670623287211 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.142 ETH0.0000311143040.028351455
0x8927da0e93c79598fa22c13cb7e21e2448b1a2c07f05739021489b0bc8d8d2edSwap132238832024-04-16 3:11:533 hrs 43 mins ago0xcadbc3ca2136a9e4f1d8ef062982bc889acb8b88 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000282127950.031479985
0x7a78cec5df60983cc34dbf3a05fa7c7c31dd5c5c194f39c5277f34eb534f49e8Swap132238352024-04-16 3:10:173 hrs 45 mins ago0xcadbc3ca2136a9e4f1d8ef062982bc889acb8b88 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.618392783427929 ETH0.0000480300650.032583049
0x04d5e5a7b732e88f7a5146fb525894c4ff7526a660c7867643de2164774adee6Swap132238002024-04-16 3:09:073 hrs 46 mins ago0xcadbc3ca2136a9e4f1d8ef062982bc889acb8b88 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000343543950.033380036
0x2fb1a27db69a373b441e19fecd2ea45174c2998291088db07d48c6d5ef7a6704Swap132237782024-04-16 3:08:233 hrs 47 mins ago0xcadbc3ca2136a9e4f1d8ef062982bc889acb8b88 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.619 ETH0.000047351070.033418999
0xcdd487b7c3c02c02f3255de2a9008c63bcff98b41562037ffe4e2dc8afc802fdSwap132233562024-04-16 2:54:194 hrs 1 min ago0x8b685636237536a987410c2f82c7db16e3c6f17d IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0 ETH0.0000173516820.040207356
0x0e819719a9d2f2218f3247bf1081591d6daf22bcebc6b96d8bb70462a207db5dSwap132231172024-04-16 2:46:214 hrs 9 mins ago0xca78e5e06c2ad7b3d7f8648c4e6920440b6b81c4 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.00001 ETH0.0000144483030.040293931
0xc3c1f908a2b2a28e54b3da6693cfe09618b98184f173f6919b98358616720ab6Swap132224872024-04-16 2:25:214 hrs 30 mins ago0x6718e9ca1376fe54e9493bfca0188cd08c396db4 IN  0x6a1431bb23e08e3209dae3130b441863855fc14b0.001 ETH0.0000277061860.034644934
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.000637911361086336 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.000637911361086336 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.001278093787121367 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.001278093787121367 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.00191425938748362 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.00191425938748362 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.002551868103168176 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.002551868103168176 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.011475963675765642 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.011475963675765642 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.002551175873648923 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.002551175873648923 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14b0x473f2d4c0e3d598a444d67cd400434b7dac34e5c0.043371882504041344 ETH
0x03f61ad421a4e56b5bd3bb9886ad5e62a08e095f49e1c0bddf70a86569910892132304472024-04-16 6:50:415 mins ago Wrapped Ether 0x6a1431bb23e08e3209dae3130b441863855fc14b0.043371882504041344 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.00585 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.00195 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.00585 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.00195 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.04875 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.0507 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.06825 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.0039 ETH
0xa43b228448295fde38784928039da73df0d7499b5bdbf18a1096717c48fda0e6132304232024-04-16 6:49:535 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.0078 ETH
0xa5c3167068fb63d98bc6ede398fc35660ed30bca36d668c393d8aaec13b20b2b132304012024-04-16 6:49:096 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.0004 ETH
0xa5c3167068fb63d98bc6ede398fc35660ed30bca36d668c393d8aaec13b20b2b132304012024-04-16 6:49:096 mins ago 0x6a1431bb23e08e3209dae3130b441863855fc14bWrapped Ether0.0284 ETH
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xec2B65FB77C38825391C2Ea6f732d10405BC1D2D
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
MagpieRouterV2

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, MIT license
File 1 of 14 : MagpieRouterV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

import {Ownable2Step} from "openzeppelin-solidity/contracts/access/Ownable2Step.sol";
import {Multicall} from "openzeppelin-solidity/contracts/utils/Multicall.sol";
import {IMagpieRouterV2} from "./interfaces/IMagpieRouterV2.sol";
import {LibAsset} from "./libraries/LibAsset.sol";
import {AppStorage, LibMagpieRouterV2} from "./libraries/LibMagpieRouterV2.sol";
import {LibSwap, SwapData} from "./libraries/LibSwap.sol";
import {LibCommand, CommandAction, CommandData} from "./router/LibCommand.sol";
import {LibUniswapV3} from "./router/LibUniswapV3.sol";

error ExpiredTransaction();
error InsufficientAmountOut();
error InvalidCall();
error InvalidCommand();

contract MagpieRouterV2 is IMagpieRouterV2, Ownable2Step, Multicall {
    using LibAsset for address;

    /// @dev See {IMagpieRouterV2-updateSelector}
    function updateSelector(uint16 commandType, bytes4 selector) external onlyOwner {
        AppStorage storage s = LibMagpieRouterV2.getStorage();

        s.selectors[commandType] = selector;
    }

    /// @dev Enforces time constraints on certain operations within a smart contract.
    /// @param deadline The timestamp in epochs beyond which the transaction will get expired.
    function enforceDeadline(uint256 deadline) private view {
        if (deadline < block.timestamp) {
            revert ExpiredTransaction();
        }
    }

    /// @dev Handle uniswapV3SwapCallback requests from any protocol that is based on UniswapV3. We dont check for factory since this contract is not supposed to store tokens. We protect the user by handling amountOutMin check at the end of execution by comparing starting and final balance at the destination address.
    fallback() external {
        int256 amount0Delta;
        int256 amount1Delta;
        address assetIn;
        uint256 callDataSize;
        assembly {
            amount0Delta := calldataload(4)
            amount1Delta := calldataload(36)
            assetIn := shr(96, calldataload(132))
            callDataSize := calldatasize()
        }

        if (callDataSize != 164) {
            revert InvalidCall();
        }

        LibUniswapV3.uniswapV3SwapCallback(amount0Delta, amount1Delta, assetIn);
    }

    /// @dev Determinines whether a specific command action within a swap sequence involves moving tokens.
    function isTokenMovement(CommandAction commandAction) private pure returns (bool) {
        return
            commandAction == CommandAction.Approval ||
            commandAction == CommandAction.TransferFrom ||
            commandAction == CommandAction.Transfer ||
            commandAction == CommandAction.Wrap ||
            commandAction == CommandAction.Unwrap;
    }

    /// @dev See {IMagpieRouterV2-estimateSwapGas}
    function estimateSwapGas(bytes calldata) external payable returns (uint256 amountOut, uint256 gasUsed) {
        (amountOut, gasUsed) = execute(true);
    }

    /// @dev See {IMagpieRouterV2-swap}
    function swap(bytes calldata) external payable returns (uint256 amountOut) {
        (amountOut, ) = execute(true);
    }

    /// @dev See {IMagpieRouterV2-silentSwap}
    function silentSwap(bytes calldata) external payable returns (uint256 amountOut) {
        (amountOut, ) = execute(false);
    }

    /// @dev Handles the execution of a sequence of commands for the swap operation.
    /// @param triggerEvent An indicator if the function needs to trigger the swap event.
    /// @return amountOut The amount received after swapping.
    /// @return gasUsed The gas utilised during swapping.
    function execute(bool triggerEvent) private returns (uint256 amountOut, uint256 gasUsed) {
        SwapData memory swapData = LibSwap.getData(LibSwap.SWAP_ARGS_OFFSET);

        enforceDeadline(swapData.deadline);

        amountOut = swapData.toAssetAddress.getBalanceOf(swapData.toAddress);

        bytes memory commandOutput = new bytes(swapData.outputsLength);
        uint16 i;
        CommandData memory commandData;
        uint256 nativeAmount;
        uint256 tmpAmount;
        bytes memory input;

        uint256 commandOutputOffset;
        assembly {
            commandOutputOffset := add(commandOutput, 32)
        }

        for (i = swapData.commandsOffset; i < swapData.commandsOffsetEnd; ) {
            commandData = LibCommand.getData(i);

            (nativeAmount, input) = LibCommand.getInput(commandOutput, commandData);

            if (commandData.commandAction == CommandAction.Call) {
                assembly {
                    let outputLength := mload(add(commandData, 64))
                    if iszero(
                        call(
                            gas(),
                            mload(add(commandData, 160)),
                            nativeAmount,
                            add(input, 32),
                            mload(input),
                            commandOutputOffset,
                            outputLength
                        )
                    ) {
                        returndatacopy(0, 0, returndatasize())
                        revert(0, returndatasize())
                    }
                    commandOutputOffset := add(commandOutputOffset, outputLength)
                }
            } else if (commandData.commandAction == CommandAction.Approval) {
                LibCommand.approve(input);
            } else if (commandData.commandAction == CommandAction.TransferFrom) {
                LibCommand.transferFrom(input);
            } else if (commandData.commandAction == CommandAction.Transfer) {
                LibCommand.transfer(input);
            } else if (commandData.commandAction == CommandAction.Wrap) {
                LibCommand.wrap(input);
            } else if (commandData.commandAction == CommandAction.Unwrap) {
                LibCommand.unwrap(input);
            } else if (commandData.commandAction == CommandAction.Balance) {
                tmpAmount = LibCommand.balance(input);
                assembly {
                    mstore(commandOutputOffset, tmpAmount)
                    commandOutputOffset := add(commandOutputOffset, 32)
                }
            } else if (commandData.commandAction == CommandAction.Math) {
                tmpAmount = LibCommand.math(input);
                assembly {
                    mstore(commandOutputOffset, tmpAmount)
                    commandOutputOffset := add(commandOutputOffset, 32)
                }
            } else if (commandData.commandAction == CommandAction.EstimateGasStart) {
                gasUsed = gasleft();
            } else if (commandData.commandAction == CommandAction.EstimateGasEnd) {
                gasUsed -= gasleft();
            } else {
                revert InvalidCommand();
            }

            assembly {
                if gt(commandOutputOffset, add(add(commandOutput, 32), mload(commandOutput))) {
                    revert(0, 0)
                }
            }

            unchecked {
                i += 11;
            }
        }

        amountOut = swapData.toAssetAddress.getBalanceOf(swapData.toAddress) - amountOut;

        if (amountOut < swapData.amountOutMin) {
            revert InsufficientAmountOut();
        }

        if (triggerEvent) {
            emit Swap(
                msg.sender,
                swapData.toAddress,
                swapData.fromAssetAddress,
                swapData.toAssetAddress,
                swapData.amountIn,
                amountOut
            );
        }
    }

    /// @dev Used to receive ethers
    receive() external payable {}
}

File 2 of 14 : IMagpieRouterV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

interface IMagpieRouterV2 {
    /// @dev Allows the owner to update the mapping of command types to function selectors.
    /// @param commandId Identifier for each command. We have one selector / command.
    /// @param selector The function selector for each of these commands.
    function updateSelector(uint16 commandId, bytes4 selector) external;

    event Swap(
        address indexed fromAddress,
        address indexed toAddress,
        address fromAssetAddress,
        address toAssetAddress,
        uint256 amountIn,
        uint256 amountOut
    );

    /// @dev Provides an external interface to estimate the gas cost of the last hop in a route.
    /// @return amountOut The amount received after swapping.
    /// @return gasUsed The cost of gas while performing the swap.
    function estimateSwapGas(bytes calldata swapArgs) external payable returns (uint256 amountOut, uint256 gasUsed);

    /// @dev Performs token swap.
    /// @return amountOut The amount received after swapping.
    function swap(bytes calldata swapArgs) external payable returns (uint256 amountOut);

    /// @dev Performs token swap without triggering event.
    /// @return amountOut The amount received after swapping.
    function silentSwap(bytes calldata swapArgs) external payable returns (uint256 amountOut);
}

File 3 of 14 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

interface IWETH {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}

File 4 of 14 : LibAsset.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IWETH.sol";

error AssetNotReceived();
error ApprovalFailed();
error TransferFromFailed();
error TransferFailed();

library LibAsset {
    using LibAsset for address;

    address constant NATIVE_ASSETID = address(0);

    /// @dev Checks if the given address (self) represents a native asset (Ether).
    /// @param self The asset that will be checked for a native token.
    /// @return Flag to identify if the asset is native or not.
    function isNative(address self) internal pure returns (bool) {
        return self == NATIVE_ASSETID;
    }

    /// @dev Retrieves the balance of the current contract for a given asset (self).
    /// @param self Asset whose balance needs to be found.
    /// @return Balance of the specific asset.
    function getBalance(address self) internal view returns (uint256) {
        return self.isNative() ? address(this).balance : IERC20(self).balanceOf(address(this));
    }

    /// @dev Retrieves the balance of the target address for a given asset (self).
    /// @param self Asset whose balance needs to be found.
    /// @param targetAddress The address where the balance is checked from.
    /// @return Balance of the specific asset.
    function getBalanceOf(address self, address targetAddress) internal view returns (uint256) {
        return self.isNative() ? targetAddress.balance : IERC20(self).balanceOf(targetAddress);
    }

    /// @dev Performs a safe transferFrom operation for a given asset (self) from one address (from) to another address (to).
    /// @param self Asset that will be transferred.
    /// @param from Address that will send the asset.
    /// @param to Address that will receive the asset.
    /// @param amount Transferred amount.
    function transferFrom(address self, address from, address to, uint256 amount) internal {
        IERC20 token = IERC20(self);

        bool success = execute(self, abi.encodeWithSelector(token.transferFrom.selector, from, to, amount));

        if (!success) revert TransferFromFailed();
    }

    /// @dev Transfers a given amount of an asset (self) to a recipient address (recipient).
    /// @param self Asset that will be transferred.
    /// @param recipient Address that will receive the transferred asset.
    /// @param amount Transferred amount.
    function transfer(address self, address recipient, uint256 amount) internal {
        IERC20 token = IERC20(self);
        bool success;

        if (self.isNative()) {
            (success, ) = payable(recipient).call{value: amount}("");
        } else {
            success = execute(self, abi.encodeWithSelector(token.transfer.selector, recipient, amount));
        }

        if (!success) {
            revert TransferFailed();
        }
    }

    /// @dev Approves a spender address (spender) to spend a specified amount of an asset (self).
    /// @param self The asset that will be approved.
    /// @param spender Address of a contract that will spend the owners asset.
    /// @param amount Asset amount that can be spent.
    function approve(address self, address spender, uint256 amount) internal {
        IERC20 token = IERC20(self);

        if (!execute(self, abi.encodeWithSelector(token.approve.selector, spender, amount))) {
            if (
                !execute(self, abi.encodeWithSelector(token.approve.selector, spender, 0)) ||
                !(execute(self, abi.encodeWithSelector(token.approve.selector, spender, amount)))
            ) {
                revert ApprovalFailed();
            }
        }
    }

    /// @dev Determines if a call was successful.
    /// @param target Address of the target contract.
    /// @param success To check if the call to the contract was successful or not.
    /// @param data The data was sent while calling the target contract.
    /// @return result The success of the call.
    function isSuccessful(address target, bool success, bytes memory data) private view returns (bool result) {
        if (success) {
            if (data.length == 0) {
                // isContract
                if (target.code.length > 0) {
                    result = true;
                }
            } else {
                assembly {
                    result := mload(add(data, 32))
                }
            }
        }
    }

    /// @dev Executes a low level call.
    /// @param self The address of the contract to which the call is being made.
    /// @param params The parameters or data to be sent in the call.
    /// @return result The success of the call.
    function execute(address self, bytes memory params) private returns (bool) {
        (bool success, bytes memory data) = self.call(params);

        return isSuccessful(self, success, data);
    }

    /// @dev Deposit of a specified amount of an asset (self).
    /// @param self Address of the asset that will be deposited.
    /// @param weth Address of the Wrapped Ether (WETH) contract.
    /// @param amount Amount that needs to be deposited.
    function deposit(address self, address weth, uint256 amount) internal {
        if (self.isNative()) {
            if (msg.value < amount) {
                revert AssetNotReceived();
            }
            IWETH(weth).deposit{value: amount}();
        } else {
            self.transferFrom(msg.sender, address(this), amount);
        }
    }

    /// @dev Withdrawal of a specified amount of an asset (self) to a designated address (to).
    /// @param self The asset that will be withdrawn.
    /// @param weth Address of the Wrapped Ether (WETH) contract.
    /// @param to Address that will receive withdrawn token.
    /// @param amount Amount that needs to be withdrawn
    function withdraw(address self, address weth, address to, uint256 amount) internal {
        if (self.isNative()) {
            IWETH(weth).withdraw(amount);
        }
        self.transfer(payable(to), amount);
    }

    /// @dev Retrieves the decimal precision of an ERC20 token.
    /// @param self The asset address whose decimals we are retrieving.
    /// @return tokenDecimals The decimals of the asset.
    function getDecimals(address self) internal view returns (uint8 tokenDecimals) {
        tokenDecimals = 18;

        if (!self.isNative()) {
            (, bytes memory queriedDecimals) = self.staticcall(abi.encodeWithSignature("decimals()"));
            tokenDecimals = abi.decode(queriedDecimals, (uint8));
        }
    }
}

File 5 of 14 : LibMagpieRouterV2.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

struct AppStorage {
    mapping(uint16 => bytes4) selectors; // Mapping of command to its corresponding function selector.
}

library LibMagpieRouterV2 {
    function getStorage() internal pure returns (AppStorage storage s) {
        assembly {
            s.slot := 0
        }
    }
}

File 6 of 14 : LibSwap.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

import {LibAsset} from "../libraries/LibAsset.sol";

struct SwapData {
    uint16 amountsOffset; // Represents the offset for the amounts section in the transaction calldata
    uint16 dataOffset; // Represents the offset for reusable data section in the calldata.
    uint16 commandsOffset; // Represents the starting point of the commands section in the calldata.
    uint16 commandsOffsetEnd; // Represents the end of the commands section in the calldata.
    uint16 outputsLength; // Represents the length of all of the commands
    uint256 amountIn; // Representing the amount of the asset being provided in the swap.
    address toAddress; // This is the address to which the output of the swap (the swapped asset) will be sent.
    address fromAssetAddress; // The address of the source asset being swapped from.
    address toAssetAddress; // The address of the final asset being swapped to.
    uint256 deadline; // Represents the deadline by which the swap must be completed.
    uint256 amountOutMin; // The minimum amount of the output asset that must be received for the swap to be considered successful.
}

library LibSwap {
    using LibAsset for address;

    uint16 constant SWAP_ARGS_OFFSET = 68;

    /// @dev Extracts and sums up the amounts of the source asset.
    /// @param startOffset Relative starting position.
    /// @param endOffset Ending position.
    /// @param positionOffset Absolute starting position.
    /// @return amountIn Sum of amounts.
    function getAmountIn(
        uint16 startOffset,
        uint16 endOffset,
        uint16 positionOffset
    ) internal pure returns (uint256 amountIn) {
        for (uint16 i = startOffset; i < endOffset; ) {
            uint256 currentAmountIn;
            assembly {
                let p := shr(240, calldataload(i))
                currentAmountIn := calldataload(add(p, positionOffset))
            }
            amountIn += currentAmountIn;

            unchecked {
                i += 2;
            }
        }
    }

    /// @dev Extract the first amount.
    /// @param swapArgsOffset Starting position of swapArgs in calldata.
    /// @return amountIn First amount in.
    function getFirstAmountIn(uint16 swapArgsOffset) internal pure returns (uint256 amountIn) {
        uint16 position = swapArgsOffset + 4;
        assembly {
            amountIn := calldataload(position)
        }
    }

    /// @dev Extracts SwapData from calldata.
    /// @param swapArgsOffset Starting position of swapArgs in calldata.
    /// @return swapData Essential data for the swap.
    function getData(uint16 swapArgsOffset) internal pure returns (SwapData memory swapData) {
        uint16 dataLength;
        uint16 amountsLength;
        uint16 dataOffset;
        uint16 swapArgsLength;
        assembly {
            dataLength := shr(240, calldataload(swapArgsOffset))
            amountsLength := shr(240, calldataload(add(swapArgsOffset, 2)))
            swapArgsLength := calldataload(sub(swapArgsOffset, 32))
        }
        dataOffset = swapArgsOffset + 4;
        swapData.dataOffset = dataOffset;
        swapData.amountsOffset = swapData.dataOffset + dataLength;
        swapData.commandsOffset = swapData.amountsOffset + amountsLength;
        swapData.commandsOffsetEnd = swapArgsLength + swapArgsOffset;
        // Depends on the context we have shift the position addSelector
        // By default the position is adjusted to the router's offset
        uint256 amountIn = getAmountIn(
            swapData.amountsOffset,
            swapData.commandsOffset,
            swapArgsOffset - SWAP_ARGS_OFFSET
        );

        assembly {
            mstore(add(swapData, 128), shr(240, calldataload(add(dataOffset, 32))))
            mstore(add(swapData, 160), amountIn)
            mstore(add(swapData, 192), shr(96, calldataload(add(dataOffset, 34))))
            mstore(add(swapData, 224), shr(96, calldataload(add(dataOffset, 54))))
            mstore(add(swapData, 256), shr(96, calldataload(add(dataOffset, 74))))
            mstore(add(swapData, 288), calldataload(add(dataOffset, 94)))
            mstore(add(swapData, 320), calldataload(add(dataOffset, 126)))
        }
    }
}

File 7 of 14 : LibCommand.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

import "../interfaces/IWETH.sol";
import {LibAsset} from "../libraries/LibAsset.sol";
import {AppStorage, LibMagpieRouterV2} from "../libraries/LibMagpieRouterV2.sol";
import {LibSwap, SwapData} from "../libraries/LibSwap.sol";

enum MathOperation {
    None,
    Add,
    Sub,
    Mul,
    Div,
    Pow,
    Abs128,
    Abs256,
    Shr,
    Shl
}

enum CommandAction {
    Call, // Represents a generic call to a function within a contract.
    Approval, // Represents an approval operation.
    TransferFrom, // Indicates a transfer-from operation.
    Transfer, // Represents a direct transfer operation.
    Wrap, // This action is used for wrapping native tokens.
    Unwrap, // This action is used for unwrapping native tokens.
    Balance, // Checks the balance of an account or contract for a specific asset.
    Math,
    EstimateGasStart,
    EstimateGasEnd
}

enum SequenceType {
    NativeAmount,
    Selector,
    Address,
    Amount,
    Data, // Parameter represented in bytes.
    CommandOutput, // Parameter using the output of an other command.
    RouterAddress, // The address of this contract.
    SenderAddress // The address of the caller.
}

struct CommandData {
    CommandAction commandAction;
    uint16 inputLength; // Specifies the length of the input data for this command.
    uint16 outputLength; // Specifies the length of the output data for this command.
    uint16 sequencesPosition; // Specifies the starting position of a sequence of data related to this command.
    uint16 sequencesPositionEnd; // Marks the end position of the sequence of data.
    address targetAddress; // The address of the contract that is the target of this command.
}

error CommandFailed(bytes data);
error InvalidAmountOut();
error InvalidSequenceType();
error InvalidSelector();
error InvalidSequencesLength();
error InvalidTransferFrom();

library LibCommand {
    using LibAsset for address;

    /// @dev Extracts and assembles a CommandData structure from transaction calldata.
    /// @param i The starting position in the calldata from where data extraction should begin.
    /// @return commandData Describes the specific command.
    function getData(uint16 i) internal pure returns (CommandData memory commandData) {
        assembly {
            mstore(commandData, shr(248, calldataload(i)))
            mstore(add(commandData, 32), shr(240, calldataload(add(i, 1))))
            mstore(add(commandData, 64), shr(240, calldataload(add(i, 3))))
            mstore(add(commandData, 96), shr(240, calldataload(add(i, 5))))
            mstore(add(commandData, 128), shr(240, calldataload(add(i, 7))))
            let targetPosition := shr(240, calldataload(add(i, 9)))
            mstore(add(commandData, 160), shr(96, calldataload(targetPosition)))
        }
    }

    /// @dev Extracts data that is required for the next command's execution.
    /// @param commandOutput Summarized byte code received / calculated after each command execution.
    /// @param commandData Describes the specific command.
    /// @return nativeAmount Amount in native tokens.
    /// @return input The calldata that has to be executed by the next command.
    function getInput(
        bytes memory commandOutput,
        CommandData memory commandData
    ) internal view returns (uint256 nativeAmount, bytes memory input) {
        AppStorage storage s = LibMagpieRouterV2.getStorage();
        input = new bytes(commandData.inputLength);

        SequenceType sequenceType;
        uint16 p;
        uint16 l;
        uint16 inputOffset = 32;
        bytes4 selector;
        for (uint16 i = commandData.sequencesPosition; i < commandData.sequencesPositionEnd; ) {
            assembly {
                sequenceType := shr(248, calldataload(i))
            }

            if (sequenceType == SequenceType.NativeAmount) {
                assembly {
                    p := shr(240, calldataload(add(i, 1)))
                    l := shr(240, calldataload(add(i, 3)))
                    switch l
                    case 1 {
                        nativeAmount := mload(add(add(commandOutput, 32), p))
                    }
                    default {
                        nativeAmount := calldataload(p)
                    }
                }
                unchecked {
                    i += 5;
                }
            } else if (sequenceType == SequenceType.Selector) {
                assembly {
                    p := shr(240, calldataload(add(i, 1)))
                }
                selector = s.selectors[p];
                assembly {
                    mstore(add(input, inputOffset), selector)
                }
                inputOffset += 4;
                unchecked {
                    i += 3;
                }
            } else if (sequenceType == SequenceType.Address) {
                assembly {
                    p := shr(240, calldataload(add(i, 1)))
                    mstore(add(input, inputOffset), shr(96, calldataload(p)))
                }
                inputOffset += 32;
                unchecked {
                    i += 3;
                }
            } else if (sequenceType == SequenceType.Amount) {
                assembly {
                    p := shr(240, calldataload(add(i, 1)))
                    mstore(add(input, inputOffset), calldataload(p))
                }
                inputOffset += 32;
                unchecked {
                    i += 3;
                }
            } else if (sequenceType == SequenceType.Data) {
                assembly {
                    p := shr(240, calldataload(add(i, 1)))
                    l := shr(240, calldataload(add(i, 3)))
                    calldatacopy(add(input, inputOffset), p, l)
                }
                inputOffset += l;
                unchecked {
                    i += 5;
                }
            } else if (sequenceType == SequenceType.CommandOutput) {
                assembly {
                    p := shr(240, calldataload(add(i, 1)))
                    mstore(add(input, inputOffset), mload(add(add(commandOutput, 32), p)))
                }
                inputOffset += 32;
                unchecked {
                    i += 3;
                }
            } else if (sequenceType == SequenceType.RouterAddress) {
                assembly {
                    mstore(add(input, inputOffset), address())
                }
                inputOffset += 32;
                unchecked {
                    i += 1;
                }
            } else if (sequenceType == SequenceType.SenderAddress) {
                assembly {
                    mstore(add(input, inputOffset), caller())
                }
                inputOffset += 32;
                unchecked {
                    i += 1;
                }
            } else {
                revert InvalidSequenceType();
            }
        }

        if (inputOffset - 32 != commandData.inputLength) {
            revert InvalidSequencesLength();
        }

        if (commandData.commandAction == CommandAction.Call) {
            if (selector == 0) {
                revert InvalidSelector();
            } else if (selector == 0x23b872dd) {
                // Blacklist transferFrom in custom calls
                revert InvalidTransferFrom();
            }
        }
    }

    /// @dev Math operations.
    function math(bytes memory input) internal pure returns (uint256) {
        uint256[] memory localOutputs = new uint256[](10);
        bytes32 amount0;
        bytes32 amount1;
        MathOperation operation;

        for (uint8 i = 0; i <= 10; ) {
            assembly {
                let pos := add(add(input, 32), mul(i, 3))
                let amount0Index := shr(248, mload(add(pos, 1)))
                if lt(amount0Index, 10) {
                    amount0 := mload(add(add(localOutputs, 32), mul(amount0Index, 32)))
                }
                if gt(amount0Index, 9) {
                    amount0Index := sub(amount0Index, 10)
                    amount0 := mload(add(add(input, 64), mul(amount0Index, 32)))
                }
                let amount1Index := shr(248, mload(add(pos, 2)))
                if lt(amount1Index, 10) {
                    amount1 := mload(add(add(localOutputs, 32), mul(amount1Index, 32)))
                }
                if gt(amount1Index, 9) {
                    amount1Index := sub(amount1Index, 10)
                    amount1 := mload(add(add(input, 64), mul(amount1Index, 32)))
                }
                operation := shr(248, mload(pos))
            }

            if (operation == MathOperation.None) {
                return localOutputs[i - 1];
            } else if (operation == MathOperation.Add) {
                localOutputs[i] = uint256(amount0) + uint256(amount1);
            } else if (operation == MathOperation.Sub) {
                localOutputs[i] = uint256(amount0) - uint256(amount1);
            } else if (operation == MathOperation.Mul) {
                localOutputs[i] = uint256(amount0) * uint256(amount1);
            } else if (operation == MathOperation.Div) {
                localOutputs[i] = uint256(amount0) / uint256(amount1);
            } else if (operation == MathOperation.Pow) {
                localOutputs[i] = uint256(amount0) ** uint256(amount1);
            } else if (operation == MathOperation.Abs128) {
                int128 amount;
                assembly {
                    amount := amount0
                }

                if (amount < 0) {
                    localOutputs[i] = uint256(uint128(-(amount)));
                } else {
                    localOutputs[i] = uint256(uint128(amount));
                }
            } else if (operation == MathOperation.Abs256) {
                int256 amount;
                assembly {
                    amount := amount0
                }

                if (amount < 0) {
                    localOutputs[i] = uint256(-(amount));
                } else {
                    localOutputs[i] = uint256(amount);
                }
            } else if (operation == MathOperation.Shr) {
                assembly {
                    mstore(add(add(localOutputs, 32), mul(i, 32)), shr(amount0, amount1))
                }
            } else if (operation == MathOperation.Shl) {
                assembly {
                    mstore(add(add(localOutputs, 32), mul(i, 32)), shl(amount0, amount1))
                }
            }

            unchecked {
                i++;
            }
        }

        return localOutputs[9];
    }

    /// @dev Perform an ERC-20 token approval operation.
    /// @param input Parameters required by approve.
    function approve(bytes memory input) internal {
        address assetAddress;
        address spenderAddress;
        uint256 amount;
        assembly {
            assetAddress := mload(add(input, 32))
            spenderAddress := mload(add(input, 64))
            amount := mload(add(input, 96))
        }

        if (amount == 0) {
            return;
        }

        assetAddress.approve(spenderAddress, amount);
    }

    /// @dev Perform an ERC-20 token transfer from one address to another.
    /// @param input Parameters required by transferFrom.
    function transferFrom(bytes memory input) internal {
        address assetAddress;
        address fromAddress;
        address toAddress;
        uint256 amount;
        assembly {
            assetAddress := mload(add(input, 32))
            fromAddress := mload(add(input, 64))
            toAddress := mload(add(input, 96))
            amount := mload(add(input, 128))
        }

        if (fromAddress != msg.sender) {
            revert InvalidTransferFrom();
        }

        if (amount == 0) {
            return;
        }

        assetAddress.transferFrom(fromAddress, toAddress, amount);
    }

    /// @dev Perform an ERC-20 token transfer to a specified address.
    /// @param input Parameters required by transfer.
    function transfer(bytes memory input) internal {
        address assetAddress;
        address toAddress;
        uint256 amount;
        assembly {
            assetAddress := mload(add(input, 32))
            toAddress := mload(add(input, 64))
            amount := mload(add(input, 96))
        }

        if (amount == 0) {
            return;
        }

        assetAddress.transfer(toAddress, amount);
    }

    /// @dev Convert native token into wrapped native token.
    /// @param input Parameters required by wrap.
    function wrap(bytes memory input) internal {
        address assetAddress;
        uint256 amount;
        assembly {
            assetAddress := mload(add(input, 32))
            amount := mload(add(input, 64))
        }

        IWETH(assetAddress).deposit{value: amount}();
    }

    /// @dev Convert wrapped native token into native token.
    /// @param input Parameters required by unwrap.
    function unwrap(bytes memory input) internal {
        address assetAddress;
        uint256 amount;
        assembly {
            assetAddress := mload(add(input, 32))
            amount := mload(add(input, 64))
        }

        IWETH(assetAddress).withdraw(amount);
    }

    /// @dev Query the balance of a specific asset.
    /// @param input Parameters required by balance.
    /// @return Balance of the specific asset
    function balance(bytes memory input) internal view returns (uint256) {
        address assetAddress;
        assembly {
            assetAddress := mload(add(input, 32))
        }

        return assetAddress.getBalanceOf(address(this));
    }
}

File 8 of 14 : LibUniswapV3.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

import {LibAsset} from "../libraries/LibAsset.sol";

error UniswapV3InvalidAmount();

library LibUniswapV3 {
    using LibAsset for address;

    /// @dev Callback function used in Uniswap V3 swaps, typically called by the Uniswap V3 pool contract during a swap operation.
    /// @param amount0Delta Changes in the amount of the first token involved in the swap.
    /// @param amount1Delta Changes in the amount of the second token involved in the swap.
    /// @param assetIn Asset that has to be transfered to the UniswapV3 pool.
    function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, address assetIn) internal {
        if (amount0Delta <= 0 && amount1Delta <= 0) {
            revert UniswapV3InvalidAmount();
        }

        assetIn.transfer(msg.sender, amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta));
    }
}

File 9 of 14 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 10 of 14 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;

import "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}

File 11 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 12 of 14 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 13 of 14 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 14 of 14 : Multicall.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)

pragma solidity ^0.8.0;

import "./Address.sol";

/**
 * @dev Provides a function to batch together multiple calls in a single external call.
 *
 * _Available since v4.1._
 */
abstract contract Multicall {
    /**
     * @dev Receives and executes a batch of function calls on this contract.
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     */
    function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            results[i] = Address.functionDelegateCall(address(this), data[i]);
        }
        return results;
    }
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"ApprovalFailed","type":"error"},{"inputs":[],"name":"ExpiredTransaction","type":"error"},{"inputs":[],"name":"InsufficientAmountOut","type":"error"},{"inputs":[],"name":"InvalidCall","type":"error"},{"inputs":[],"name":"InvalidCommand","type":"error"},{"inputs":[],"name":"InvalidSelector","type":"error"},{"inputs":[],"name":"InvalidSequenceType","type":"error"},{"inputs":[],"name":"InvalidSequencesLength","type":"error"},{"inputs":[],"name":"InvalidTransferFrom","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferFromFailed","type":"error"},{"inputs":[],"name":"UniswapV3InvalidAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"address","name":"fromAssetAddress","type":"address"},{"indexed":false,"internalType":"address","name":"toAssetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swap","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"estimateSwapGas","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"silentSwap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"commandType","type":"uint16"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"updateSelector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6080604052600436106100955760003560e01c8063ac9650d811610059578063ac9650d81461018e578063dc13bc7c146101bb578063e30c3978146101ce578063e423ad64146101ec578063f2fde38b1461020c5761009c565b8063627dd56a146100e4578063715018a61461010a57806379ba50971461011f57806383bf2321146101345780638da5cb5b1461015c5761009c565b3661009c57005b3480156100a857600080fd5b5060043560243560843560601c3660a481146100d75760405163574b16a760e11b815260040160405180910390fd5b6100e284848461022c565b005b6100f76100f2366004611818565b610286565b6040519081526020015b60405180910390f35b34801561011657600080fd5b506100e261029a565b34801561012b57600080fd5b506100e26102ae565b610147610142366004611818565b61032d565b60408051928352602083019190915201610101565b34801561016857600080fd5b506000546001600160a01b03165b6040516001600160a01b039091168152602001610101565b34801561019a57600080fd5b506101ae6101a936600461188a565b610345565b604051610101919061193d565b6100f76101c9366004611818565b610430565b3480156101da57600080fd5b506001546001600160a01b0316610176565b3480156101f857600080fd5b506100e26102073660046119a1565b61043c565b34801561021857600080fd5b506100e26102273660046119ee565b610470565b6000831315801561023e575060008213155b1561025c57604051637ed0826d60e11b815260040160405180910390fd5b610281336000851361026e5783610270565b845b6001600160a01b03841691906104e1565b505050565b600061029260016105d6565b509392505050565b6102a26109d5565b6102ac6000610a2f565b565b60015433906001600160a01b031681146103215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b61032a81610a2f565b50565b60008061033a60016105d6565b909590945092505050565b60608167ffffffffffffffff81111561036057610360611a17565b60405190808252806020026020018201604052801561039357816020015b606081526020019060019003908161037e5790505b50905060005b8281101561042857610403308585848181106103b7576103b7611a2d565b90506020028101906103c99190611a43565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a4892505050565b82828151811061041557610415611a2d565b6020908102919091010152600101610399565b505b92915050565b600061029260006105d6565b6104446109d5565b61ffff919091166000908152602081905260409020805463ffffffff191660e09290921c919091179055565b6104786109d5565b600180546001600160a01b0383166001600160a01b031990911681179091556104a96000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b8260006001600160a01b03821661054b576040516001600160a01b038516908490600081818185875af1925050503d806000811461053b576040519150601f19603f3d011682016040523d82523d6000602084013e610540565b606091505b5050809150506105b1565b6040516001600160a01b0385166024820152604481018490526105ae90869063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610a74565b90505b806105cf576040516312171d8360e31b815260040160405180910390fd5b5050505050565b60008060006105e56044610aec565b90506105f5816101200151610c26565b61061a8160c001518261010001516001600160a01b0316610c4790919063ffffffff16565b92506000816080015161ffff1667ffffffffffffffff81111561063f5761063f611a17565b6040519080825280601f01601f191660200182016040528015610669576020820181803683370190505b506040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905291925090604084015191506000806060602086015b876060015161ffff168661ffff1610156108ff576040805160c081018252873560f81c8152600188013560f090811c60208301526003890135811c928201929092526005880135821c6060808301919091526007890135831c6080830152600989013590921c3590911c60a0820152945061072b8786610cd7565b909450915060008551600981111561074557610745611a91565b0361077357604085015180828451602086018860a08b01515af161076d573d6000803e3d6000fd5b016108e1565b60018551600981111561078857610788611a91565b0361079b576107968261101d565b6108e1565b6002855160098111156107b0576107b0611a91565b036107be5761079682611055565b6003855160098111156107d3576107d3611a91565b036107e157610796826110b6565b6004855160098111156107f6576107f6611a91565b0361080457610796826110e8565b60058551600981111561081957610819611a91565b036108275761079682611152565b60068551600981111561083c5761083c611a91565b036108575761084a826111bb565b80825292506020016108e1565b60078551600981111561086c5761086c611a91565b0361087a5761084a826111d6565b60088551600981111561088f5761088f611a91565b0361089c575a98506108e1565b6009855160098111156108b1576108b1611a91565b036108c8575a6108c1908a611abd565b98506108e1565b6040516312f269e560e01b815260040160405180910390fd5b865160208801018111156108f457600080fd5b600b860195506106b0565b896109258960c001518a61010001516001600160a01b0316610c4790919063ffffffff16565b61092f9190611abd565b99508761014001518a101561095757604051637294b85560e11b815260040160405180910390fd5b8a156109c85760c088015160e08901516101008a015160a08b0151604080516001600160a01b0394851681529284166020840152820152606081018d905291169033907f20efd6d5195b7b50273f01cd79a27989255356f9f13293edc53ee142accfdb759060800160405180910390a35b5050505050505050915091565b6000546001600160a01b031633146102ac5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610318565b600180546001600160a01b031916905561032a8161151e565b6060610a6d8383604051806060016040528060278152602001611cef6027913961156e565b9392505050565b6000806000846001600160a01b031684604051610a919190611ad0565b6000604051808303816000865af19150503d8060008114610ace576040519150601f19603f3d011682016040523d82523d6000602084013e610ad3565b606091505b5091509150610ae38583836115e6565b95945050505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152813560f090811c906002840135901c6000601f19850135610b67866004611aec565b61ffff811660208701819052909250610b81908590611aec565b61ffff16808652610b93908490611aec565b61ffff166040860152610ba68682611aec565b61ffff16606086015284516040860151600091610bcd91610bc860448b611b07565b61161a565b602084013560f01c608088015260a087015250506022810135606090811c60c08601526036820135811c60e0860152604a820135901c610100850152605e810135610120850152607e0135610140840152509092915050565b4281101561032a5760405163931997cf60e01b815260040160405180910390fd5b60006001600160a01b03831615610cc7576040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610c9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190611b22565b610a6d565b506001600160a01b031631919050565b6000606081836020015161ffff1667ffffffffffffffff811115610cfd57610cfd611a17565b6040519080825280601f01601f191660200182016040528015610d27576020820181803683370190505b50915060008060008060209050600080896060015190505b896080015161ffff168161ffff161015610f6157803560f81c95506000866007811115610d6e57610d6e611a91565b03610dac57600181013560f01c9450600381013560f01c93508360018114610d995785359950610da3565b8560208d01015199505b50600501610d3f565b6001866007811115610dc057610dc0611a91565b03610dff57600181013560f01c60008181526020899052604090205460e01b8985018190529095509150610df5600484611aec565b9250600301610d3f565b6002866007811115610e1357610e13611a91565b03610e3657600181013560f01c803560601c898501529450610df5602084611aec565b6003866007811115610e4a57610e4a611a91565b03610e6a57600181013560f01c8035898501529450610df5602084611aec565b6004866007811115610e7e57610e7e611a91565b03610eb157600181013560f01c9450600381013560f01c93508385848a0137610ea78484611aec565b9250600501610d3f565b6005866007811115610ec557610ec5611a91565b03610eec57600181013560f01c94508460208c01015183890152602083610df59190611aec565b6006866007811115610f0057610f00611a91565b03610f1f573088840152610f15602084611aec565b9250600101610d3f565b6007866007811115610f3357610f33611a91565b03610f48573388840152610f15602084611aec565b604051635485b7ef60e11b815260040160405180910390fd5b50886020015161ffff16602083610f789190611b07565b61ffff1614610f9a57604051632dbf5cd360e11b815260040160405180910390fd5b600089516009811115610faf57610faf611a91565b03611010576001600160e01b03198116600003610fdf57604051631cd4b64760e21b815260040160405180910390fd5b6001600160e01b031981166323b872dd60e01b03611010576040516322fe1f0760e01b815260040160405180910390fd5b5050505050509250929050565b602081015160408201516060830151600081900361103b5750505050565b61104f6001600160a01b038416838361164b565b50505050565b60208101516040820151606083015160808401516001600160a01b0383163314611092576040516322fe1f0760e01b815260040160405180910390fd5b806000036110a1575050505050565b6105cf6001600160a01b038516848484611708565b60208101516040820151606083015160008190036110d45750505050565b61104f6001600160a01b03841683836104e1565b6000806020830151915060408301519050816001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561113457600080fd5b505af1158015611148573d6000803e3d6000fd5b5050505050505050565b60208101516040808301519051632e1a7d4d60e01b8152600481018290526001600160a01b03831690632e1a7d4d90602401600060405180830381600087803b15801561119e57600080fd5b505af11580156111b2573d6000803e3d6000fd5b50505050505050565b6020810151600090610a6d6001600160a01b03821630610c47565b60408051600a8082526101608201909252600091829190602082016101408036833701905050905060008080805b600a8160ff16116114f757600381026020880101600181015160f81c600a811015611236576020810260208801015195505b600981111561125257600a810390506020810260408a01015195505b50600281015160f81c600a811015611271576020810260208801015194505b600981111561128d57600a810390506020810260408a01015194505b505160f81c915060008260098111156112a8576112a8611a91565b036112e057846112b9600183611b3b565b60ff16815181106112cc576112cc611a2d565b602002602001015195505050505050919050565b60018260098111156112f4576112f4611a91565b03611329576113038385611b54565b858260ff168151811061131857611318611a2d565b6020026020010181815250506114ef565b600282600981111561133d5761133d611a91565b0361134c576113038385611abd565b600382600981111561136057611360611a91565b0361136f576113038385611b67565b600482600981111561138357611383611a91565b03611392576113038385611b7e565b60058260098111156113a6576113a6611a91565b036113b5576113038385611c84565b60068260098111156113c9576113c9611a91565b0361144657836000600f82900b1215611414576113e581611c90565b6001600160801b0316868360ff168151811061140357611403611a2d565b602002602001018181525050611440565b806001600160801b0316868360ff168151811061143357611433611a2d565b6020026020010181815250505b506114ef565b600782600981111561145a5761145a611a91565b0361149d578360008112156114875761147281611cbf565b868360ff168151811061140357611403611a2d565b80868360ff168151811061143357611433611a2d565b60088260098111156114b1576114b1611a91565b036114c85782841c602082026020870101526114ef565b60098260098111156114dc576114dc611a91565b036114ef5782841b602082026020870101525b600101611204565b508360098151811061150b5761150b611a2d565b6020026020010151945050505050919050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060600080856001600160a01b03168560405161158b9190611ad0565b600060405180830381855af49150503d80600081146115c6576040519150601f19603f3d011682016040523d82523d6000602084013e6115cb565b606091505b50915091506115dc8683838761176d565b9695505050505050565b60008215610a6d57815160000361160f576001600160a01b0384163b15610cc257506001610a6d565b506020015192915050565b6000835b8361ffff168161ffff16101561029257803560f01c8301356116408184611b54565b92505060020161161e565b6040516001600160a01b038316602482015260448101829052839061167d90829063095ea7b360e01b90606401610577565b61104f576040516001600160a01b0384166024820152600060448201526116b190859063095ea7b360e01b90606401610577565b15806116ea57506040516001600160a01b0384166024820152604481018390526116e890859063095ea7b360e01b90606401610577565b155b1561104f576040516340b27c2160e11b815260040160405180910390fd5b6040516001600160a01b038085166024830152831660448201526064810182905284906000906117459083906323b872dd60e01b90608401610577565b90508061176557604051631e4e7d0960e21b815260040160405180910390fd5b505050505050565b606083156117dc5782516000036117d5576001600160a01b0385163b6117d55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610318565b50816117e6565b6117e683836117ee565b949350505050565b8151156117fe5781518083602001fd5b8060405162461bcd60e51b81526004016103189190611cdb565b6000806020838503121561182b57600080fd5b823567ffffffffffffffff8082111561184357600080fd5b818501915085601f83011261185757600080fd5b81358181111561186657600080fd5b86602082850101111561187857600080fd5b60209290920196919550909350505050565b6000806020838503121561189d57600080fd5b823567ffffffffffffffff808211156118b557600080fd5b818501915085601f8301126118c957600080fd5b8135818111156118d857600080fd5b8660208260051b850101111561187857600080fd5b60005b838110156119085781810151838201526020016118f0565b50506000910152565b600081518084526119298160208601602086016118ed565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561199457603f19888603018452611982858351611911565b94509285019290850190600101611966565b5092979650505050505050565b600080604083850312156119b457600080fd5b823561ffff811681146119c657600080fd5b915060208301356001600160e01b0319811681146119e357600080fd5b809150509250929050565b600060208284031215611a0057600080fd5b81356001600160a01b0381168114610a6d57600080fd5b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112611a5a57600080fd5b83018035915067ffffffffffffffff821115611a7557600080fd5b602001915036819003821315611a8a57600080fd5b9250929050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8181038181111561042a5761042a611aa7565b60008251611ae28184602087016118ed565b9190910192915050565b61ffff81811683821601908082111561042857610428611aa7565b61ffff82811682821603908082111561042857610428611aa7565b600060208284031215611b3457600080fd5b5051919050565b60ff828116828216039081111561042a5761042a611aa7565b8082018082111561042a5761042a611aa7565b808202811582820484141761042a5761042a611aa7565b600082611b9b57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b80851115611bdb578160001904821115611bc157611bc1611aa7565b80851615611bce57918102915b93841c9390800290611ba5565b509250929050565b600082611bf25750600161042a565b81611bff5750600061042a565b8160018114611c155760028114611c1f57611c3b565b600191505061042a565b60ff841115611c3057611c30611aa7565b50506001821b61042a565b5060208310610133831016604e8410600b8410161715611c5e575081810a61042a565b611c688383611ba0565b8060001904821115611c7c57611c7c611aa7565b029392505050565b6000610a6d8383611be3565b600081600f0b6f7fffffffffffffffffffffffffffffff198103611cb657611cb6611aa7565b60000392915050565b6000600160ff1b8201611cd457611cd4611aa7565b5060000390565b602081526000610a6d602083018461191156fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b4a92f96a9eb4f8f853b1484e7308f48cc68ce43973c2be8a58a99682be6041a64736f6c63430008160033

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.