编译器
0.8.19+commit.7dd6d404
文件 1 的 15:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
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");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
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);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
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);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
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 {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 15:Consts.sol
pragma solidity 0.8.x;
library Consts {
address public constant MULTICALL_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;
address public constant PERMIT2_ADDRESS = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
}
文件 3 的 15:DutchOrderLib.sol
pragma solidity ^0.8.0;
import {OrderInfo} from "../base/ReactorStructs.sol";
import {OrderInfoLib} from "./OrderInfoLib.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
struct DutchOutput {
address token;
uint256 startAmount;
uint256 endAmount;
address recipient;
}
struct DutchInput {
ERC20 token;
uint256 startAmount;
uint256 endAmount;
}
struct DutchOrder {
OrderInfo info;
uint256 decayStartTime;
uint256 decayEndTime;
DutchInput input;
DutchOutput[] outputs;
}
library DutchOrderLib {
using OrderInfoLib for OrderInfo;
bytes internal constant DUTCH_OUTPUT_TYPE =
"DutchOutput(address token,uint256 startAmount,uint256 endAmount,address recipient)";
bytes32 internal constant DUTCH_OUTPUT_TYPE_HASH = keccak256(DUTCH_OUTPUT_TYPE);
bytes internal constant DUTCH_LIMIT_ORDER_TYPE = abi.encodePacked(
"DutchOrder(",
"OrderInfo info,",
"uint256 decayStartTime,",
"uint256 decayEndTime,",
"address inputToken,",
"uint256 inputStartAmount,",
"uint256 inputEndAmount,",
"DutchOutput[] outputs)"
);
bytes internal constant ORDER_TYPE =
abi.encodePacked(DUTCH_LIMIT_ORDER_TYPE, DUTCH_OUTPUT_TYPE, OrderInfoLib.ORDER_INFO_TYPE);
bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE);
string internal constant TOKEN_PERMISSIONS_TYPE = "TokenPermissions(address token,uint256 amount)";
string internal constant PERMIT2_ORDER_TYPE =
string(abi.encodePacked("DutchOrder witness)", ORDER_TYPE, TOKEN_PERMISSIONS_TYPE));
function hash(DutchOutput memory output) internal pure returns (bytes32) {
return keccak256(
abi.encode(DUTCH_OUTPUT_TYPE_HASH, output.token, output.startAmount, output.endAmount, output.recipient)
);
}
function hash(DutchOutput[] memory outputs) internal pure returns (bytes32) {
unchecked {
bytes memory packedHashes = new bytes(32 * outputs.length);
for (uint256 i = 0; i < outputs.length; i++) {
bytes32 outputHash = hash(outputs[i]);
assembly {
mstore(add(add(packedHashes, 0x20), mul(i, 0x20)), outputHash)
}
}
return keccak256(packedHashes);
}
}
function hash(DutchOrder memory order) internal pure returns (bytes32) {
return keccak256(
abi.encode(
ORDER_TYPE_HASH,
order.info.hash(),
order.decayStartTime,
order.decayEndTime,
order.input.token,
order.input.startAmount,
order.input.endAmount,
hash(order.outputs)
)
);
}
}
文件 4 的 15:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 5 的 15:ExclusiveDutchOrderLib.sol
pragma solidity ^0.8.0;
import {OrderInfo} from "../base/ReactorStructs.sol";
import {DutchOutput, DutchInput, DutchOrderLib} from "./DutchOrderLib.sol";
import {OrderInfoLib} from "./OrderInfoLib.sol";
struct ExclusiveDutchOrder {
OrderInfo info;
uint256 decayStartTime;
uint256 decayEndTime;
address exclusiveFiller;
uint256 exclusivityOverrideBps;
DutchInput input;
DutchOutput[] outputs;
}
library ExclusiveDutchOrderLib {
using DutchOrderLib for DutchOutput[];
using OrderInfoLib for OrderInfo;
bytes internal constant EXCLUSIVE_DUTCH_LIMIT_ORDER_TYPE = abi.encodePacked(
"ExclusiveDutchOrder(",
"OrderInfo info,",
"uint256 decayStartTime,",
"uint256 decayEndTime,",
"address exclusiveFiller,",
"uint256 exclusivityOverrideBps,",
"address inputToken,",
"uint256 inputStartAmount,",
"uint256 inputEndAmount,",
"DutchOutput[] outputs)"
);
bytes internal constant ORDER_TYPE = abi.encodePacked(
EXCLUSIVE_DUTCH_LIMIT_ORDER_TYPE, DutchOrderLib.DUTCH_OUTPUT_TYPE, OrderInfoLib.ORDER_INFO_TYPE
);
bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE);
string internal constant PERMIT2_ORDER_TYPE = string(
abi.encodePacked(
"ExclusiveDutchOrder witness)",
DutchOrderLib.DUTCH_OUTPUT_TYPE,
EXCLUSIVE_DUTCH_LIMIT_ORDER_TYPE,
OrderInfoLib.ORDER_INFO_TYPE,
DutchOrderLib.TOKEN_PERMISSIONS_TYPE
)
);
function hash(ExclusiveDutchOrder memory order) internal pure returns (bytes32) {
return keccak256(
abi.encode(
ORDER_TYPE_HASH,
order.info.hash(),
order.decayStartTime,
order.decayEndTime,
order.exclusiveFiller,
order.exclusivityOverrideBps,
order.input.token,
order.input.startAmount,
order.input.endAmount,
order.outputs.hash()
)
);
}
}
文件 6 的 15:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 7 的 15:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 8 的 15:IMulticall3.sol
pragma solidity >=0.6.2 <0.9.0;
pragma experimental ABIEncoderV2;
interface IMulticall3 {
struct Call {
address target;
bytes callData;
}
struct Call3 {
address target;
bool allowFailure;
bytes callData;
}
struct Call3Value {
address target;
bool allowFailure;
uint256 value;
bytes callData;
}
struct Result {
bool success;
bytes returnData;
}
function aggregate(Call[] calldata calls)
external
payable
returns (uint256 blockNumber, bytes[] memory returnData);
function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData);
function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData);
function blockAndAggregate(Call[] calldata calls)
external
payable
returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);
function getBasefee() external view returns (uint256 basefee);
function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash);
function getBlockNumber() external view returns (uint256 blockNumber);
function getChainId() external view returns (uint256 chainid);
function getCurrentBlockCoinbase() external view returns (address coinbase);
function getCurrentBlockDifficulty() external view returns (uint256 difficulty);
function getCurrentBlockGasLimit() external view returns (uint256 gaslimit);
function getCurrentBlockTimestamp() external view returns (uint256 timestamp);
function getEthBalance(address addr) external view returns (uint256 balance);
function getLastBlockHash() external view returns (bytes32 blockHash);
function tryAggregate(bool requireSuccess, Call[] calldata calls)
external
payable
returns (Result[] memory returnData);
function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls)
external
payable
returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);
}
文件 9 的 15:IReactor.sol
pragma solidity ^0.8.0;
import {ResolvedOrder, SignedOrder} from "../base/ReactorStructs.sol";
import {IReactorCallback} from "./IReactorCallback.sol";
interface IReactor {
function execute(SignedOrder calldata order) external payable;
function executeWithCallback(SignedOrder calldata order, bytes calldata callbackData) external payable;
function executeBatch(SignedOrder[] calldata orders) external payable;
function executeBatchWithCallback(SignedOrder[] calldata orders, bytes calldata callbackData) external payable;
}
文件 10 的 15:IReactorCallback.sol
pragma solidity ^0.8.0;
import {ResolvedOrder} from "../base/ReactorStructs.sol";
interface IReactorCallback {
function reactorCallback(ResolvedOrder[] memory resolvedOrders, bytes memory callbackData) external;
}
文件 11 的 15:IValidationCallback.sol
pragma solidity ^0.8.0;
import {OrderInfo, ResolvedOrder} from "../base/ReactorStructs.sol";
interface IValidationCallback {
function validate(address filler, ResolvedOrder calldata resolvedOrder) external view;
}
文件 12 的 15:LiquidityHub.sol
pragma solidity 0.8.x;
import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IReactor} from "uniswapx/src/interfaces/IReactor.sol";
import {IReactorCallback} from "uniswapx/src/interfaces/IReactorCallback.sol";
import {IValidationCallback} from "uniswapx/src/interfaces/IValidationCallback.sol";
import {ResolvedOrder, SignedOrder} from "uniswapx/src/base/ReactorStructs.sol";
import {ExclusiveDutchOrder} from "uniswapx/src/lib/ExclusiveDutchOrderLib.sol";
import {Consts} from "./Consts.sol";
contract LiquidityHub is IReactorCallback, IValidationCallback {
using SafeERC20 for IERC20;
error InvalidSender(address sender);
error InvalidOrder();
event Resolved(
bytes32 indexed orderHash,
address indexed swapper,
address indexed ref,
address inToken,
address outToken,
uint256 inAmount,
uint256 outAmount
);
event ExtraOut(address indexed recipient, address token, uint256 amount);
event Surplus(address indexed ref, address swapper, address token, uint256 amount, uint256 refshare);
uint8 public constant VERSION = 6;
address public constant INVALID_ADDRESS = address(1);
IReactor public immutable reactor;
IAllowed public immutable allowed;
constructor(IReactor _reactor, IAllowed _allowed) {
reactor = _reactor;
allowed = _allowed;
}
modifier onlyAllowed() {
if (!allowed.allowed(msg.sender)) revert InvalidSender(msg.sender);
_;
}
modifier onlyReactor() {
if (msg.sender != address(reactor)) revert InvalidSender(msg.sender);
_;
}
function execute(SignedOrder calldata order, IMulticall3.Call[] calldata calls, uint256 outAmountSwapper)
external
onlyAllowed
{
reactor.executeWithCallback(order, abi.encode(calls, outAmountSwapper));
ExclusiveDutchOrder memory o = abi.decode(order.order, (ExclusiveDutchOrder));
(address ref, uint8 share) = abi.decode(o.info.additionalValidationData, (address, uint8));
_surplus(ref, o.info.swapper, address(o.input.token), share);
for (uint256 i = 0; i < o.outputs.length; i++) {
_surplus(ref, o.info.swapper, address(o.outputs[i].token), share);
}
}
function reactorCallback(ResolvedOrder[] memory orders, bytes memory callbackData) external override onlyReactor {
ResolvedOrder memory order = orders[0];
(IMulticall3.Call[] memory calls, uint256 outAmountSwapper) =
abi.decode(callbackData, (IMulticall3.Call[], uint256));
_executeMulticall(calls);
(address outToken, uint256 outAmount) = _handleOrderOutputs(order);
if (outAmountSwapper > outAmount) _transfer(outToken, order.info.swapper, outAmountSwapper - outAmount);
address ref = abi.decode(order.info.additionalValidationData, (address));
emit Resolved(
order.hash, order.info.swapper, ref, address(order.input.token), outToken, order.input.amount, outAmount
);
}
function _executeMulticall(IMulticall3.Call[] memory calls) private {
Address.functionDelegateCall(
Consts.MULTICALL_ADDRESS, abi.encodeWithSelector(IMulticall3.aggregate.selector, calls)
);
}
function _handleOrderOutputs(ResolvedOrder memory order) private returns (address outToken, uint256 outAmount) {
outToken = INVALID_ADDRESS;
for (uint256 i = 0; i < order.outputs.length; i++) {
uint256 amount = order.outputs[i].amount;
if (amount > 0) {
address token = address(order.outputs[i].token);
_outputReactor(token, amount);
if (order.outputs[i].recipient == order.info.swapper) {
if (outToken != INVALID_ADDRESS && outToken != token) revert InvalidOrder();
outToken = token;
outAmount += amount;
} else {
emit ExtraOut(order.outputs[i].recipient, token, amount);
}
}
}
}
function _surplus(address ref, address swapper, address token, uint8 share) private {
uint256 balance = _balanceOf(token, address(this));
if (balance == 0) return;
uint256 refshare = (ref != address(0)) ? balance * share / 100 : 0;
if (refshare > 0) _transfer(token, ref, refshare);
_transfer(token, swapper, balance - refshare);
emit Surplus(ref, swapper, token, balance, refshare);
}
function _outputReactor(address token, uint256 amount) private {
if (token == address(0)) {
Address.sendValue(payable(address(reactor)), amount);
} else {
uint256 allowance = IERC20(token).allowance(address(this), address(reactor));
IERC20(token).safeApprove(address(reactor), 0);
IERC20(token).safeApprove(address(reactor), allowance + amount);
}
}
function _transfer(address token, address to, uint256 amount) private {
if (token == address(0)) Address.sendValue(payable(to), amount);
else IERC20(token).safeTransfer(to, amount);
}
function _balanceOf(address token, address who) private view returns (uint256) {
return (token == address(0)) ? who.balance : IERC20(token).balanceOf(who);
}
function validate(address filler, ResolvedOrder calldata) external view override {
if (filler != address(this)) revert InvalidSender(filler);
}
receive() external payable {
}
}
interface IAllowed {
function allowed(address) external view returns (bool);
}
文件 13 的 15:OrderInfoLib.sol
pragma solidity ^0.8.0;
import {OrderInfo} from "../base/ReactorStructs.sol";
library OrderInfoLib {
bytes internal constant ORDER_INFO_TYPE =
"OrderInfo(address reactor,address swapper,uint256 nonce,uint256 deadline,address additionalValidationContract,bytes additionalValidationData)";
bytes32 internal constant ORDER_INFO_TYPE_HASH = keccak256(ORDER_INFO_TYPE);
function hash(OrderInfo memory info) internal pure returns (bytes32) {
return keccak256(
abi.encode(
ORDER_INFO_TYPE_HASH,
info.reactor,
info.swapper,
info.nonce,
info.deadline,
info.additionalValidationContract,
keccak256(info.additionalValidationData)
)
);
}
}
文件 14 的 15:ReactorStructs.sol
pragma solidity ^0.8.0;
import {IReactor} from "../interfaces/IReactor.sol";
import {IValidationCallback} from "../interfaces/IValidationCallback.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
struct OrderInfo {
IReactor reactor;
address swapper;
uint256 nonce;
uint256 deadline;
IValidationCallback additionalValidationContract;
bytes additionalValidationData;
}
struct InputToken {
ERC20 token;
uint256 amount;
uint256 maxAmount;
}
struct OutputToken {
address token;
uint256 amount;
address recipient;
}
struct ResolvedOrder {
OrderInfo info;
InputToken input;
OutputToken[] outputs;
bytes sig;
bytes32 hash;
}
struct SignedOrder {
bytes order;
bytes sig;
}
文件 15 的 15:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
{
"compilationTarget": {
"src/LiquidityHub.sol": "LiquidityHub"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": [
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":UniswapX/=lib/UniswapX/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-gas-snapshot/=lib/UniswapX/lib/forge-gas-snapshot/src/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
":openzeppelin/=lib/openzeppelin-contracts/contracts/",
":permit2/=lib/UniswapX/lib/permit2/",
":solmate/=lib/solmate/",
":uniswapx/=lib/UniswapX/"
]
}
[{"inputs":[{"internalType":"contract IReactor","name":"_reactor","type":"address"},{"internalType":"contract IAllowed","name":"_allowed","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidOrder","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"InvalidSender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExtraOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"swapper","type":"address"},{"indexed":true,"internalType":"address","name":"ref","type":"address"},{"indexed":false,"internalType":"address","name":"inToken","type":"address"},{"indexed":false,"internalType":"address","name":"outToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"inAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outAmount","type":"uint256"}],"name":"Resolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ref","type":"address"},{"indexed":false,"internalType":"address","name":"swapper","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refshare","type":"uint256"}],"name":"Surplus","type":"event"},{"inputs":[],"name":"INVALID_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowed","outputs":[{"internalType":"contract IAllowed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"order","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct SignedOrder","name":"order","type":"tuple"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct IMulticall3.Call[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"outAmountSwapper","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reactor","outputs":[{"internalType":"contract IReactor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"contract IReactor","name":"reactor","type":"address"},{"internalType":"address","name":"swapper","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"contract IValidationCallback","name":"additionalValidationContract","type":"address"},{"internalType":"bytes","name":"additionalValidationData","type":"bytes"}],"internalType":"struct OrderInfo","name":"info","type":"tuple"},{"components":[{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"internalType":"struct InputToken","name":"input","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct OutputToken[]","name":"outputs","type":"tuple[]"},{"internalType":"bytes","name":"sig","type":"bytes"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"internalType":"struct ResolvedOrder[]","name":"orders","type":"tuple[]"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"reactorCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"filler","type":"address"},{"components":[{"components":[{"internalType":"contract IReactor","name":"reactor","type":"address"},{"internalType":"address","name":"swapper","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"contract IValidationCallback","name":"additionalValidationContract","type":"address"},{"internalType":"bytes","name":"additionalValidationData","type":"bytes"}],"internalType":"struct OrderInfo","name":"info","type":"tuple"},{"components":[{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"internalType":"struct InputToken","name":"input","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct OutputToken[]","name":"outputs","type":"tuple[]"},{"internalType":"bytes","name":"sig","type":"bytes"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"internalType":"struct ResolvedOrder","name":"","type":"tuple"}],"name":"validate","outputs":[],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]