DexAggregatorCore
0x09ad820aac5779683b481c4674208a4e1b024afa
Verification
Verified
v0.8.28+commit.7893614a
Type
Contract
7,570 bytes
ABI entries
31
4 read · 9 write
License
none
Contract information
- Address
- 0x09ad820aac5779683b481c4674208a4e1b024afa
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.28+commit.7893614a
- Optimization
- Enabled
- Creator
- 0x9f2eFccb40…958977f694
- Creation tx
- 0xe5b4fdb44b…191578149d
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (4)
owner() → address
paused() → bool
pendingOwner() → address
whitelist(address) → bool
Events (5)
OwnershipTransferStartedOwnershipTransferredPausedUnpausedUpdateWhitelist
ABI
[
{
"inputs": [],
"name": "ApprovalFailed",
"type": "error"
},
{
"inputs": [],
"name": "FailedUnwrap",
"type": "error"
},
{
"inputs": [],
"name": "FailedWrap",
"type": "error"
},
{
"inputs": [],
"name": "InvalidCall",
"type": "error"
},
{
"inputs": [],
"name": "InvalidCaller",
"type": "error"
},
{
"inputs": [],
"name": "InvalidCommand",
"type": "error"
},
{
"inputs": [],
"name": "InvalidOutput",
"type": "error"
},
{
"inputs": [],
"name": "SimulationCompleted",
"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": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "value",
"type": "bool"
}
],
"name": "UpdateWhitelist",
"type": "event"
},
{
"stateMutability": "nonpayable",
"type": "fallback"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"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": "pause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "paused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"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": "simulate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "swapWithoutSignature",
"outputs": [
{
"internalType": "uint256",
"name": "gasUsed",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "unpause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"internalType": "bool",
"name": "value",
"type": "bool"
}
],
"name": "updateWhitelist",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "whitelist",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Ownable2Step} from "openzeppelin-solidity/contracts/access/Ownable2Step.sol";
import {Pausable} from "openzeppelin-solidity/contracts/security/Pausable.sol";
import {Address} from "openzeppelin-solidity/contracts/utils/Address.sol";
import {IDexAggregatorCore} from "./interfaces/IDexAggregatorCore.sol";
import {LibAsset} from "./libraries/LibAsset.sol";
import {LibRouter, SwapData} from "./libraries/LibRouter.sol";
error ExpiredTransaction();
error InvalidCall();
error InvalidCommand();
error InvalidTransferFromCall();
error ApprovalFailed();
error TransferFromFailed();
error TransferFailed();
error UniswapV3InvalidAmount();
error InvalidCaller();
error InvalidOutput();
error InvalidNativeAmount();
error SimulationCompleted();
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,
Comparison,
EstimateGasStart,
EstimateGasEnd,
Simulation
}
/// @notice DO NOT approve tokens to this contract. It is not safe. All the approvals should be given to DexAggregator and not DexAggregatorCore.
contract DexAggregatorCore is IDexAggregatorCore, Ownable2Step, Pausable {
using LibAsset for address;
mapping(address => bool) public whitelist;
address private lastCaller;
/// @dev Restricts swap functions with signatures to be called only by bridge.
modifier onlyWhitelisted() {
if (!whitelist[msg.sender]) {
revert InvalidCaller();
}
_;
}
/// @dev See {IDexAggregatorCore-updateBridge}
function updateWhitelist(address caller, bool value) external onlyOwner {
whitelist[caller] = value;
emit UpdateWhitelist(msg.sender, caller, value);
}
/// @dev See {IDexAggregatorCore-pause}
function pause() public onlyOwner whenNotPaused {
_pause();
}
/// @dev See {IDexAggregatorCore-unpause}
function unpause() public onlyOwner whenPaused {
_unpause();
}
/// @dev See {IDexAggregatorCore-multicall}
function multicall(bytes[] calldata data) external onlyOwner 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;
}
/// @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();
}
if (amount0Delta <= 0 && amount1Delta <= 0) {
revert UniswapV3InvalidAmount();
}
uint256 amount = amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
assetIn.transfer(msg.sender, amount);
}
/// @dev See {IDexAggregatorCore-simulate}
function simulate(bytes calldata) external {
SwapData memory swapData = LibRouter.getData();
execute(lastCaller, swapData.fromAssetAddress);
revert SimulationCompleted();
}
/// @dev See {IDexAggregatorCore-swapWithoutSignature}
function swapWithoutSignature(bytes calldata) external payable onlyWhitelisted returns (uint256 gasUsed) {
SwapData memory swapData = LibRouter.getData();
gasUsed = execute(msg.sender, swapData.fromAssetAddress);
}
/// @dev Prepares CommandData for command iteration.
function getCommandData()
private
pure
returns (uint16 commandsOffset, uint16 commandsOffsetEnd, uint16 outputsLength)
{
assembly {
commandsOffset := add(70, shr(240, calldataload(68))) // dataOffset + dataLength
commandsOffsetEnd := add(68, calldataload(36)) // commandsOffsetEnd / swapArgsOffset + swapArgsLength (swapArgsOffset - 32)
outputsLength := shr(240, calldataload(70)) // dataOffset + 32
}
}
/// @dev Handles the execution of a sequence of commands for the swap operation.
/// @param fromAddress The address from which the assets will be swapped.
/// @param fromAssetAddress The address of the asset to be swapped.
/// @return gasUsed The amount of gas used during the execution of the swap.
function execute(address fromAddress, address fromAssetAddress) private returns (uint256 gasUsed) {
(uint16 commandsOffset, uint16 commandsOffsetEnd, uint16 outputsLength) = getCommandData();
uint256 outputPtr;
assembly {
outputPtr := mload(0x40)
mstore(0x40, add(outputPtr, outputsLength))
}
uint256 outputOffsetPtr = outputPtr;
bool breakLoop;
unchecked {
for (uint256 i = commandsOffset; i < commandsOffsetEnd; ) {
(gasUsed, outputOffsetPtr, breakLoop) = executeCommand(
i,
fromAddress,
fromAssetAddress,
outputPtr,
outputOffsetPtr,
gasUsed
);
if (breakLoop) {
break;
}
i += 9;
}
}
if (outputOffsetPtr > outputPtr + outputsLength) {
revert InvalidOutput();
}
}
/// @dev Builds the input for a specific command.
/// @param i Command data position.
/// @param outputPtr Memory pointer of the currently available output.
/// @return input Calculated input data.
/// @return nativeAmount Native token amount.
function getInput(uint256 i, uint256 outputPtr) private view returns (bytes memory input, uint256 nativeAmount) {
assembly {
let sequencesPositionEnd := shr(240, calldataload(add(i, 5)))
input := mload(0x40)
nativeAmount := 0
let j := shr(240, calldataload(add(i, 3))) // sequencesPosition
let inputOffsetPtr := add(input, 32)
for {
} lt(j, sequencesPositionEnd) {
} {
let sequenceType := shr(248, calldataload(j))
switch sequenceType
// NativeAmountDirect
case 0 {
nativeAmount := mload(add(outputPtr, shr(240, calldataload(add(j, 1)))))
j := add(j, 3)
}
// Selector
case 1 {
mstore(inputOffsetPtr, calldataload(shr(240, calldataload(add(j, 1)))))
inputOffsetPtr := add(inputOffsetPtr, 4)
j := add(j, 3)
}
// Address
case 2 {
mstore(inputOffsetPtr, shr(96, calldataload(shr(240, calldataload(add(j, 1))))))
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 3)
}
// Amount
case 3 {
let p := shr(240, calldataload(add(j, 1)))
mstore(inputOffsetPtr, shr(shr(248, calldataload(p)), calldataload(add(p, 1))))
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 3)
}
// Data
case 4 {
let l := shr(240, calldataload(add(j, 3)))
calldatacopy(inputOffsetPtr, shr(240, calldataload(add(j, 1))), l)
inputOffsetPtr := add(inputOffsetPtr, l)
j := add(j, 5)
}
// CommandOutput
case 5 {
mstore(inputOffsetPtr, mload(add(outputPtr, shr(240, calldataload(add(j, 1))))))
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 3)
}
// RouterAddress
case 6 {
mstore(inputOffsetPtr, address())
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 1)
}
// SenderAddress
case 7 {
mstore(inputOffsetPtr, caller())
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 1)
}
// NativeAmountIndexed
case 11 {
let p := shr(240, calldataload(add(j, 1)))
nativeAmount := shr(shr(248, calldataload(p)), calldataload(add(p, 1)))
j := add(j, 5)
}
// NativeAmountAdjusted
case 12 {
let p := shr(240, calldataload(add(j, 1)))
let amountIn := shr(shr(248, calldataload(p)), calldataload(add(p, 1)))
p := shr(240, calldataload(add(j, 3)))
switch gt(amountIn, calldataload(132))
case 1 {
nativeAmount := sub(
shr(shr(248, calldataload(p)), calldataload(add(p, 1))),
sub(amountIn, calldataload(132))
)
}
default {
nativeAmount := add(
shr(shr(248, calldataload(p)), calldataload(add(p, 1))),
sub(calldataload(132), amountIn)
)
}
j := add(j, 5)
}
// AmountIn
case 13 {
mstore(inputOffsetPtr, calldataload(132))
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 1)
}
// RouteAmountIn
case 14 {
let p := shr(240, calldataload(add(j, 1)))
let amountIn := shr(shr(248, calldataload(p)), calldataload(add(p, 1)))
p := shr(240, calldataload(add(j, 3)))
switch gt(amountIn, calldataload(132))
case 1 {
mstore(
inputOffsetPtr,
sub(
shr(shr(248, calldataload(p)), calldataload(add(p, 1))),
sub(amountIn, calldataload(132))
)
)
}
default {
mstore(
inputOffsetPtr,
add(
shr(shr(248, calldataload(p)), calldataload(add(p, 1))),
sub(calldataload(132), amountIn)
)
)
}
inputOffsetPtr := add(inputOffsetPtr, 32)
j := add(j, 5)
}
default {
// InvalidSequenceType
mstore(0, 0xa90b6fde00000000000000000000000000000000000000000000000000000000)
revert(0, 4)
}
}
mstore(input, sub(inputOffsetPtr, add(input, 32)))
mstore(0x40, inputOffsetPtr)
}
}
/// @dev Executes a command call with the given parameters.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
/// @param outputOffsetPtr The pointer to the offset of the output in memory.
/// @return New outputOffsetPtr position.
function executeCommandCall(uint256 i, uint256 outputPtr, uint256 outputOffsetPtr) private returns (uint256) {
bytes memory input;
uint256 nativeAmount;
(input, nativeAmount) = getInput(i, outputPtr);
uint256 outputLength;
assembly {
outputLength := shr(240, calldataload(add(i, 1)))
switch shr(224, mload(add(input, 32))) // selector
case 0 {
// InvalidSelector
mstore(0, 0x7352d91c00000000000000000000000000000000000000000000000000000000)
revert(0, 4)
}
case 0x23b872dd {
// Blacklist transferFrom in custom calls
// InvalidTransferFromCall
mstore(0, 0x1751a8e400000000000000000000000000000000000000000000000000000000)
revert(0, 4)
}
case 0x51905636 {
// Blacklist OFT sendFrom in custom call
mstore(0, 0x1751a8e400000000000000000000000000000000000000000000000000000000)
revert(0, 4)
}
default {
let targetAddress := shr(96, calldataload(shr(240, calldataload(add(i, 7))))) // targetPosition
if eq(targetAddress, address()) {
// InvalidCall
mstore(0, 0xae962d4e00000000000000000000000000000000000000000000000000000000)
revert(0, 4)
}
if iszero(
call(
gas(),
targetAddress,
nativeAmount,
add(input, 32),
mload(input),
outputOffsetPtr,
outputLength
)
) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
outputOffsetPtr += outputLength;
return outputOffsetPtr;
}
/// @dev Executes a command approval with the given parameters.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
function executeCommandApproval(uint256 i, uint256 outputPtr) private {
(bytes memory input, ) = getInput(i, outputPtr);
address self;
address spender;
uint256 amount;
assembly {
self := mload(add(input, 32))
spender := mload(add(input, 64))
amount := mload(add(input, 96))
}
self.approve(spender, amount);
}
/// @dev Executes a transfer command from a specific address and asset.
/// @param i The command position.
/// @param outputPtr The pointer to the output location in memory.
/// @param fromAssetAddress The address of the asset to transfer from.
/// @param fromAddress The address to transfer the asset from.
function executeCommandTransferFrom(
uint256 i,
uint256 outputPtr,
address fromAssetAddress,
address fromAddress
) private {
(bytes memory input, ) = getInput(i, outputPtr);
uint256 amount;
assembly {
amount := mload(add(input, 64))
}
if (amount > 0) {
address to;
assembly {
to := mload(add(input, 32))
}
fromAssetAddress.transferFrom(fromAddress, to, amount);
}
}
/// @dev Executes a transfer command with the given parameters.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
function executeCommandTransfer(uint256 i, uint256 outputPtr) private {
(bytes memory input, ) = getInput(i, outputPtr);
uint256 amount;
assembly {
amount := mload(add(input, 96))
}
if (amount > 0) {
address self;
address recipient;
assembly {
self := mload(add(input, 32))
recipient := mload(add(input, 64))
}
self.transfer(recipient, amount);
}
}
/// @dev Executes a wrap command with the given parameters.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
function executeCommandWrap(uint256 i, uint256 outputPtr) private {
(bytes memory input, ) = getInput(i, outputPtr);
address self;
uint256 amount;
assembly {
self := mload(add(input, 32))
amount := mload(add(input, 64))
}
self.wrap(amount);
}
/// @dev Executes an unwrap command with the given parameters.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
function executeCommandUnwrap(uint256 i, uint256 outputPtr) private {
(bytes memory input, ) = getInput(i, outputPtr);
address self;
uint256 amount;
assembly {
self := mload(add(input, 32))
amount := mload(add(input, 64))
}
self.unwrap(amount);
}
/// @dev Executes a balance command and returns the resulting balance.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
/// @param outputOffsetPtr The pointer to the offset of the output in memory.
/// @return New outputOffsetPtr position.
function executeCommandBalance(
uint256 i,
uint256 outputPtr,
uint256 outputOffsetPtr
) private view returns (uint256) {
(bytes memory input, ) = getInput(i, outputPtr);
address self;
uint256 amount;
assembly {
self := mload(add(input, 32))
}
amount = self.getBalance();
assembly {
mstore(outputOffsetPtr, amount)
}
outputOffsetPtr += 32;
return outputOffsetPtr;
}
/// @dev Executes a mathematical command.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
/// @param outputOffsetPtr The pointer to the offset of the output in memory.
/// @return New outputOffsetPtr position.
function executeCommandMath(uint256 i, uint256 outputPtr, uint256 outputOffsetPtr) private view returns (uint256) {
(bytes memory input, ) = getInput(i, outputPtr);
assembly {
function math(currentInputPtr) -> amount {
let currentOutputPtr := mload(0x40)
let j := 0
let amount0 := 0
let amount1 := 0
let operator := 0
for {
} lt(j, 10) {
} {
let pos := add(currentInputPtr, mul(j, 3))
let amount0Index := shr(248, mload(add(pos, 1)))
switch lt(amount0Index, 10)
case 1 {
amount0 := mload(add(currentOutputPtr, mul(amount0Index, 32)))
}
default {
amount0Index := sub(amount0Index, 10)
amount0 := mload(add(add(currentInputPtr, 32), mul(amount0Index, 32)))
}
let amount1Index := shr(248, mload(add(pos, 2)))
switch lt(amount1Index, 10)
case 1 {
amount1 := mload(add(currentOutputPtr, mul(amount1Index, 32)))
}
default {
amount1Index := sub(amount1Index, 10)
amount1 := mload(add(add(currentInputPtr, 32), mul(amount1Index, 32)))
}
operator := shr(248, mload(pos))
switch operator
// None
case 0 {
let finalPtr := add(currentOutputPtr, mul(sub(j, 1), 32))
amount := mload(finalPtr)
mstore(0x40, add(finalPtr, 32))
leave
}
// Add
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), add(amount0, amount1))
}
// Sub
case 2 {
mstore(add(currentOutputPtr, mul(j, 32)), sub(amount0, amount1))
}
// Mul
case 3 {
mstore(add(currentOutputPtr, mul(j, 32)), mul(amount0, amount1))
}
// Div
case 4 {
mstore(add(currentOutputPtr, mul(j, 32)), div(amount0, amount1))
}
// Pow
case 5 {
mstore(add(currentOutputPtr, mul(j, 32)), exp(amount0, amount1))
}
// Abs128
case 6 {
amount0 := signextend(15, amount0)
let mask := sar(127, amount0)
amount0 := xor(amount0, mask)
amount0 := sub(amount0, mask)
mstore(add(currentOutputPtr, mul(j, 32)), amount0)
}
// Abs256
case 7 {
let mask := sar(255, amount0)
amount0 := xor(amount0, mask)
amount0 := sub(amount0, mask)
mstore(add(currentOutputPtr, mul(j, 32)), amount0)
}
// Shr
case 8 {
mstore(add(currentOutputPtr, mul(j, 32)), shr(amount0, amount1))
}
// Shl
case 9 {
mstore(add(currentOutputPtr, mul(j, 32)), shl(amount0, amount1))
}
j := add(j, 1)
}
let finalPtr := add(currentOutputPtr, mul(9, 32))
amount := mload(finalPtr)
mstore(0x40, add(finalPtr, 32))
}
mstore(outputOffsetPtr, math(add(input, 32)))
}
outputOffsetPtr += 32;
return outputOffsetPtr;
}
/// @dev Executes a comparison command.
/// @param i The command data position.
/// @param outputPtr The pointer to the output location in memory.
/// @param outputOffsetPtr The pointer to the offset of the output in memory.
/// @return New outputOffsetPtr position.
function executeCommandComparison(
uint256 i,
uint256 outputPtr,
uint256 outputOffsetPtr
) private view returns (uint256) {
(bytes memory input, ) = getInput(i, outputPtr);
assembly {
function comparison(currentInputPtr) -> amount {
let currentOutputPtr := mload(0x40)
let j := 0
let amount0 := 0
let amount1 := 0
let amount2 := 0
let amount3 := 0
let operator := 0
for {
} lt(j, 6) {
} {
let pos := add(currentInputPtr, mul(j, 5))
let amount0Index := shr(248, mload(add(pos, 1)))
switch lt(amount0Index, 6)
case 1 {
amount0 := mload(add(currentOutputPtr, mul(amount0Index, 32)))
}
default {
amount0Index := sub(amount0Index, 6)
amount0 := mload(add(add(currentInputPtr, 32), mul(amount0Index, 32)))
}
let amount1Index := shr(248, mload(add(pos, 2)))
switch lt(amount1Index, 6)
case 1 {
amount1 := mload(add(currentOutputPtr, mul(amount1Index, 32)))
}
default {
amount1Index := sub(amount1Index, 6)
amount1 := mload(add(add(currentInputPtr, 32), mul(amount1Index, 32)))
}
let amount2Index := shr(248, mload(add(pos, 3)))
switch lt(amount2Index, 6)
case 1 {
amount2 := mload(add(currentOutputPtr, mul(amount2Index, 32)))
}
default {
amount2Index := sub(amount2Index, 6)
amount2 := mload(add(add(currentInputPtr, 32), mul(amount2Index, 32)))
}
let amount3Index := shr(248, mload(add(pos, 4)))
switch lt(amount3Index, 6)
case 1 {
amount3 := mload(add(currentOutputPtr, mul(amount3Index, 32)))
}
default {
amount3Index := sub(amount3Index, 6)
amount3 := mload(add(add(currentInputPtr, 32), mul(amount3Index, 32)))
}
operator := shr(248, mload(pos))
switch operator
// None
case 0 {
let finalPtr := add(currentOutputPtr, mul(sub(j, 1), 32))
amount := mload(finalPtr)
mstore(0x40, add(finalPtr, 32))
leave
}
// Lt
case 1 {
switch lt(amount0, amount1)
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), amount2)
}
default {
mstore(add(currentOutputPtr, mul(j, 32)), amount3)
}
}
// Lte
case 2 {
switch or(lt(amount0, amount1), eq(amount0, amount1))
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), amount2)
}
default {
mstore(add(currentOutputPtr, mul(j, 32)), amount3)
}
}
// Gt
case 3 {
switch gt(amount0, amount1)
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), amount2)
}
default {
mstore(add(currentOutputPtr, mul(j, 32)), amount3)
}
}
// Gte
case 4 {
switch or(gt(amount0, amount1), eq(amount0, amount1))
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), amount2)
}
default {
mstore(add(currentOutputPtr, mul(j, 32)), amount3)
}
}
// Eq
case 5 {
switch eq(amount0, amount1)
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), amount2)
}
default {
mstore(add(currentOutputPtr, mul(j, 32)), amount3)
}
}
// Ne
case 6 {
switch eq(amount0, amount1)
case 1 {
mstore(add(currentOutputPtr, mul(j, 32)), amount3)
}
default {
mstore(add(currentOutputPtr, mul(j, 32)), amount2)
}
}
j := add(j, 1)
}
let finalPtr := add(currentOutputPtr, mul(5, 32))
amount := mload(finalPtr)
mstore(0x40, add(finalPtr, 32))
}
mstore(outputOffsetPtr, comparison(add(input, 32)))
}
outputOffsetPtr += 32;
return outputOffsetPtr;
}
/// @dev Executes a simulation command.
/// @param i The command data position.
function executeCommandSimulation(uint256 i) private {
lastCaller = msg.sender;
i -= 70; // dataOffset
assembly {
// Load free memory pointer
let ptr := mload(0x40)
// Copy entire calldata into memory
calldatacopy(ptr, 0, calldatasize())
// Set current commandsOffset
mstore(add(ptr, 68), shl(240, add(i, 9)))
mstore(add(ptr, 70), calldataload(70))
// Overwrite first 4 bytes with new selector
mstore(ptr, 0x2421706200000000000000000000000000000000000000000000000000000000)
mstore(0x40, and(add(add(ptr, calldatasize()), 31), not(31)))
// Perform call
let success := call(gas(), address(), 0, ptr, calldatasize(), 0, 0)
}
}
/// @dev Handles the execution of the specified command commands for the swap operation.
/// @param i The command data position.
/// @param fromAddress The wallet / contract of the fromAssetAddress.
/// @param fromAssetAddress The asset will be transfered from the user.
/// @param outputPtr Starting position of the output memory pointer.
/// @param outputOffsetPtr Current position of the output memory pointer.
/// @param gasUsed Recorded gas between commands.
function executeCommand(
uint256 i,
address fromAddress,
address fromAssetAddress,
uint256 outputPtr,
uint256 outputOffsetPtr,
uint256 gasUsed
) private returns (uint256, uint256, bool) {
CommandAction commandAction;
assembly {
commandAction := shr(248, calldataload(i))
}
bool breakLoop;
if (commandAction == CommandAction.Call) {
outputOffsetPtr = executeCommandCall(i, outputPtr, outputOffsetPtr);
} else if (commandAction == CommandAction.Approval) {
executeCommandApproval(i, outputPtr);
} else if (commandAction == CommandAction.TransferFrom) {
executeCommandTransferFrom(i, outputPtr, fromAssetAddress, fromAddress);
} else if (commandAction == CommandAction.Transfer) {
executeCommandTransfer(i, outputPtr);
} else if (commandAction == CommandAction.Wrap) {
executeCommandWrap(i, outputPtr);
} else if (commandAction == CommandAction.Unwrap) {
executeCommandUnwrap(i, outputPtr);
} else if (commandAction == CommandAction.Balance) {
outputOffsetPtr = executeCommandBalance(i, outputPtr, outputOffsetPtr);
} else if (commandAction == CommandAction.Math) {
outputOffsetPtr = executeCommandMath(i, outputPtr, outputOffsetPtr);
} else if (commandAction == CommandAction.Comparison) {
outputOffsetPtr = executeCommandComparison(i, outputPtr, outputOffsetPtr);
} else if (commandAction == CommandAction.EstimateGasStart) {
gasUsed = gasleft();
} else if (commandAction == CommandAction.EstimateGasEnd) {
gasUsed -= gasleft();
} else if (commandAction == CommandAction.Simulation) {
executeCommandSimulation(i);
breakLoop = true;
} else {
revert InvalidCommand();
}
return (gasUsed, outputOffsetPtr, breakLoop);
}
/// @dev Used to receive ethers
receive() external payable {}
}
Chain explorer3235msChain node79ms