编译器
0.6.12+commit.27d51765
文件 1 的 57:AMMLibEIP712.sol
pragma solidity ^0.6.0;
import "./BaseLibEIP712.sol";
contract AMMLibEIP712 is BaseLibEIP712 {
struct Order {
address makerAddr;
address takerAssetAddr;
address makerAssetAddr;
uint256 takerAssetAmount;
uint256 makerAssetAmount;
address userAddr;
address payable receiverAddr;
uint256 salt;
uint256 deadline;
}
bytes32 public constant TRADE_WITH_PERMIT_TYPEHASH = keccak256(
abi.encodePacked(
"tradeWithPermit(",
"address makerAddr,",
"address takerAssetAddr,",
"address makerAssetAddr,",
"uint256 takerAssetAmount,",
"uint256 makerAssetAmount,",
"address userAddr,",
"address receiverAddr,",
"uint256 salt,",
"uint256 deadline",
")"
)
);
}
文件 2 的 57:AMMQuoter.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./interfaces/IUniswapExchange.sol";
import "./interfaces/IUniswapFactory.sol";
import "./interfaces/IUniswapRouterV2.sol";
import "./interfaces/ICurveFi.sol";
import "./interfaces/IWeth.sol";
import "./interfaces/IPermanentStorage.sol";
import "./interfaces/IUniswapV3Quoter.sol";
import "./utils/LibBytes.sol";
contract AMMQuoter {
using SafeMath for uint256;
using LibBytes for bytes;
string public constant version = "5.2.0";
address private constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address private constant ZERO_ADDRESS = address(0);
address public constant UNISWAP_V2_ROUTER_02_ADDRESS = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address public constant UNISWAP_V3_ROUTER_ADDRESS = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
address public constant UNISWAP_V3_QUOTER_ADDRESS = 0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6;
address public constant SUSHISWAP_ROUTER_ADDRESS = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F;
address public immutable weth;
IPermanentStorage public immutable permStorage;
struct GroupedVars {
address makerAddr;
address takerAssetAddr;
address makerAssetAddr;
uint256 takerAssetAmount;
uint256 makerAssetAmount;
address[] path;
}
event CurveTokenAdded(
address indexed makerAddress,
address indexed assetAddress,
int128 index
);
constructor (IPermanentStorage _permStorage, address _weth) public {
permStorage = _permStorage;
weth = _weth;
}
function isETH(address assetAddress) public pure returns (bool) {
return (assetAddress == ZERO_ADDRESS || assetAddress == ETH_ADDRESS);
}
function getMakerOutAmountWithPath(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount,
address[] calldata _path,
bytes memory _makerSpecificData
)
public
returns (uint256 makerAssetAmount)
{
GroupedVars memory vars;
vars.makerAddr = _makerAddr;
vars.takerAssetAddr = _takerAssetAddr;
vars.makerAssetAddr = _makerAssetAddr;
vars.takerAssetAmount = _takerAssetAmount;
vars.path = _path;
if (vars.makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
vars.makerAddr == SUSHISWAP_ROUTER_ADDRESS) {
IUniswapRouterV2 router = IUniswapRouterV2(vars.makerAddr);
uint256[] memory amounts = router.getAmountsOut(vars.takerAssetAmount, vars.path);
makerAssetAmount = amounts[amounts.length-1];
} else if (vars.makerAddr == UNISWAP_V3_ROUTER_ADDRESS) {
IUniswapV3Quoter quoter = IUniswapV3Quoter(UNISWAP_V3_QUOTER_ADDRESS);
uint8 swapType = uint8(uint256(_makerSpecificData.readBytes32(0)));
if (swapType == 1) {
address v3TakerInternalAsset = isETH(vars.takerAssetAddr) ? weth : vars.takerAssetAddr;
address v3MakerInternalAsset = isETH(vars.makerAssetAddr) ? weth : vars.makerAssetAddr;
(, uint24 poolFee) = abi.decode(_makerSpecificData, (uint8, uint24));
makerAssetAmount = quoter.quoteExactInputSingle(v3TakerInternalAsset, v3MakerInternalAsset, poolFee, vars.takerAssetAmount, 0);
} else if (swapType == 2) {
(, bytes memory path) = abi.decode(_makerSpecificData, (uint8, bytes));
makerAssetAmount = quoter.quoteExactInput(path, vars.takerAssetAmount);
} else {
revert("AMMQuoter: Invalid UniswapV3 swap type");
}
} else {
address curveTakerIntenalAsset = isETH(vars.takerAssetAddr) ? ETH_ADDRESS : vars.takerAssetAddr;
address curveMakerIntenalAsset = isETH(vars.makerAssetAddr) ? ETH_ADDRESS : vars.makerAssetAddr;
(int128 fromTokenCurveIndex, int128 toTokenCurveIndex, uint16 swapMethod,) = permStorage.getCurvePoolInfo(vars.makerAddr, curveTakerIntenalAsset, curveMakerIntenalAsset);
if (fromTokenCurveIndex > 0 && toTokenCurveIndex > 0) {
require(swapMethod != 0, "AMMQuoter: swap method not registered");
fromTokenCurveIndex = fromTokenCurveIndex - 1;
toTokenCurveIndex = toTokenCurveIndex - 1;
ICurveFi curve = ICurveFi(vars.makerAddr);
if (swapMethod == 1) {
makerAssetAmount = curve.get_dy(fromTokenCurveIndex, toTokenCurveIndex, vars.takerAssetAmount).sub(1);
} else if (swapMethod == 2) {
makerAssetAmount = curve.get_dy_underlying(fromTokenCurveIndex, toTokenCurveIndex, vars.takerAssetAmount).sub(1);
}
} else {
revert("AMMQuoter: Unsupported makerAddr");
}
}
return makerAssetAmount;
}
function getMakerOutAmount(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount
)
public
view
returns (uint256)
{
uint256 makerAssetAmount;
if (_makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
_makerAddr == SUSHISWAP_ROUTER_ADDRESS) {
IUniswapRouterV2 router = IUniswapRouterV2(_makerAddr);
address[] memory path = new address[](2);
if (isETH(_takerAssetAddr)) {
path[0] = weth;
path[1] = _makerAssetAddr;
} else if (isETH(_makerAssetAddr)) {
path[0] = _takerAssetAddr;
path[1] = weth;
} else {
path[0] = _takerAssetAddr;
path[1] = _makerAssetAddr;
}
uint256[] memory amounts = router.getAmountsOut(_takerAssetAmount, path);
makerAssetAmount = amounts[1];
} else {
address curveTakerIntenalAsset = isETH(_takerAssetAddr) ? ETH_ADDRESS : _takerAssetAddr;
address curveMakerIntenalAsset = isETH(_makerAssetAddr) ? ETH_ADDRESS : _makerAssetAddr;
(int128 fromTokenCurveIndex, int128 toTokenCurveIndex, uint16 swapMethod,) = permStorage.getCurvePoolInfo(_makerAddr, curveTakerIntenalAsset, curveMakerIntenalAsset);
if (fromTokenCurveIndex > 0 && toTokenCurveIndex > 0) {
require(swapMethod != 0, "AMMQuoter: swap method not registered");
fromTokenCurveIndex = fromTokenCurveIndex - 1;
toTokenCurveIndex = toTokenCurveIndex - 1;
ICurveFi curve = ICurveFi(_makerAddr);
if (swapMethod == 1) {
makerAssetAmount = curve.get_dy(fromTokenCurveIndex, toTokenCurveIndex, _takerAssetAmount).sub(1);
} else if (swapMethod == 2) {
makerAssetAmount = curve.get_dy_underlying(fromTokenCurveIndex, toTokenCurveIndex, _takerAssetAmount).sub(1);
}
} else {
revert("AMMQuoter: Unsupported makerAddr");
}
}
return makerAssetAmount;
}
function getBestOutAmount(
address[] calldata _makerAddresses,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount
)
external
view
returns (address bestMaker, uint256 bestAmount)
{
bestAmount = 0;
uint256 poolLength = _makerAddresses.length;
for (uint256 i = 0; i < poolLength; i++) {
address makerAddress = _makerAddresses[i];
uint256 makerAssetAmount = getMakerOutAmount(makerAddress, _takerAssetAddr, _makerAssetAddr, _takerAssetAmount);
if (makerAssetAmount > bestAmount) {
bestAmount = makerAssetAmount;
bestMaker = makerAddress;
}
}
return (bestMaker, bestAmount);
}
function getTakerInAmountWithPath(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _makerAssetAmount,
address[] calldata _path,
bytes memory _makerSpecificData
)
public
returns (uint256 takerAssetAmount)
{
GroupedVars memory vars;
vars.makerAddr = _makerAddr;
vars.takerAssetAddr = _takerAssetAddr;
vars.makerAssetAddr = _makerAssetAddr;
vars.makerAssetAmount = _makerAssetAmount;
vars.path = _path;
if (vars.makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
vars.makerAddr == SUSHISWAP_ROUTER_ADDRESS) {
IUniswapRouterV2 router = IUniswapRouterV2(vars.makerAddr);
uint256[] memory amounts = router.getAmountsIn(vars.makerAssetAmount, _path);
takerAssetAmount = amounts[0];
} else if (vars.makerAddr == UNISWAP_V3_ROUTER_ADDRESS) {
IUniswapV3Quoter quoter = IUniswapV3Quoter(UNISWAP_V3_QUOTER_ADDRESS);
uint8 swapType = uint8(uint256(_makerSpecificData.readBytes32(0)));
if (swapType == 3) {
address v3TakerInternalAsset = isETH(vars.takerAssetAddr) ? weth : vars.takerAssetAddr;
address v3MakerInternalAsset = isETH(vars.makerAssetAddr) ? weth : vars.makerAssetAddr;
(, uint24 poolFee) = abi.decode(_makerSpecificData, (uint8, uint24));
takerAssetAmount = quoter.quoteExactOutputSingle(v3TakerInternalAsset, v3MakerInternalAsset, poolFee, vars.makerAssetAmount, 0);
} else if (swapType == 4) {
(, bytes memory path) = abi.decode(_makerSpecificData, (uint8, bytes));
takerAssetAmount = quoter.quoteExactOutput(path, vars.makerAssetAmount);
} else {
revert("AMMQuoter: Invalid UniswapV3 swap type");
}
} else {
address curveTakerIntenalAsset = isETH(vars.takerAssetAddr) ? ETH_ADDRESS : vars.takerAssetAddr;
address curveMakerIntenalAsset = isETH(vars.makerAssetAddr) ? ETH_ADDRESS : vars.makerAssetAddr;
(int128 fromTokenCurveIndex, int128 toTokenCurveIndex, uint16 swapMethod, bool supportGetDx) = permStorage.getCurvePoolInfo(vars.makerAddr, curveTakerIntenalAsset, curveMakerIntenalAsset);
if (fromTokenCurveIndex > 0 && toTokenCurveIndex > 0) {
require(swapMethod != 0, "AMMQuoter: swap method not registered");
fromTokenCurveIndex = fromTokenCurveIndex - 1;
toTokenCurveIndex = toTokenCurveIndex - 1;
ICurveFi curve = ICurveFi(vars.makerAddr);
if (supportGetDx) {
if (swapMethod == 1) {
takerAssetAmount = curve.get_dx(fromTokenCurveIndex, toTokenCurveIndex, vars.makerAssetAmount);
} else if (swapMethod == 2) {
takerAssetAmount = curve.get_dx_underlying(fromTokenCurveIndex, toTokenCurveIndex, vars.makerAssetAmount);
}
} else {
if (swapMethod == 1) {
takerAssetAmount = curve.get_dy(toTokenCurveIndex, fromTokenCurveIndex, vars.makerAssetAmount);
} else if (swapMethod == 2) {
takerAssetAmount = curve.get_dy_underlying(toTokenCurveIndex, fromTokenCurveIndex, vars.makerAssetAmount);
}
}
} else {
revert("AMMQuoter: Unsupported makerAddr");
}
}
return takerAssetAmount;
}
function getTakerInAmount(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _makerAssetAmount
)
public
view
returns (uint256)
{
uint256 takerAssetAmount;
if (_makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
_makerAddr == SUSHISWAP_ROUTER_ADDRESS) {
IUniswapRouterV2 router = IUniswapRouterV2(_makerAddr);
address[] memory path = new address[](2);
if (isETH(_takerAssetAddr)) {
path[0] = weth;
path[1] = _makerAssetAddr;
} else if (isETH(_makerAssetAddr)) {
path[0] = _takerAssetAddr;
path[1] = weth;
} else {
path[0] = _takerAssetAddr;
path[1] = _makerAssetAddr;
}
uint256[] memory amounts = router.getAmountsIn(_makerAssetAmount, path);
takerAssetAmount = amounts[0];
} else {
address curveTakerIntenalAsset = isETH(_takerAssetAddr) ? ETH_ADDRESS : _takerAssetAddr;
address curveMakerIntenalAsset = isETH(_makerAssetAddr) ? ETH_ADDRESS : _makerAssetAddr;
(int128 fromTokenCurveIndex, int128 toTokenCurveIndex, uint16 swapMethod, bool supportGetDx) = permStorage.getCurvePoolInfo(_makerAddr, curveTakerIntenalAsset, curveMakerIntenalAsset);
if (fromTokenCurveIndex > 0 && toTokenCurveIndex > 0) {
require(swapMethod != 0, "AMMQuoter: swap method not registered");
fromTokenCurveIndex = fromTokenCurveIndex - 1;
toTokenCurveIndex = toTokenCurveIndex - 1;
ICurveFi curve = ICurveFi(_makerAddr);
if (supportGetDx) {
if (swapMethod == 1) {
takerAssetAmount = curve.get_dx(fromTokenCurveIndex, toTokenCurveIndex, _makerAssetAmount);
} else if (swapMethod == 2) {
takerAssetAmount = curve.get_dx_underlying(fromTokenCurveIndex, toTokenCurveIndex, _makerAssetAmount);
}
} else {
if (swapMethod == 1) {
takerAssetAmount = curve.get_dy(toTokenCurveIndex, fromTokenCurveIndex, _makerAssetAmount);
} else if (swapMethod == 2) {
takerAssetAmount = curve.get_dy_underlying(toTokenCurveIndex, fromTokenCurveIndex, _makerAssetAmount);
}
}
} else {
revert("AMMQuoter: Unsupported makerAddr");
}
}
return takerAssetAmount;
}
function getBestInAmount(
address[] calldata _makerAddresses,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _makerAssetAmount
)
external
view
returns (address bestMaker, uint256 bestAmount)
{
bestAmount = 2**256 - 1;
uint256 poolLength = _makerAddresses.length;
for (uint256 i = 0; i < poolLength; i++) {
address makerAddress = _makerAddresses[i];
uint256 takerAssetAmount = getTakerInAmount(makerAddress, _takerAssetAddr, _makerAssetAddr, _makerAssetAmount);
if (takerAssetAmount < bestAmount) {
bestAmount = takerAssetAmount;
bestMaker = makerAddress;
}
}
return (bestMaker, bestAmount);
}
}
文件 3 的 57:AMMWrapper.sol
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./interfaces/ISpender.sol";
import "./interfaces/IUniswapExchange.sol";
import "./interfaces/IUniswapFactory.sol";
import "./interfaces/IUniswapRouterV2.sol";
import "./interfaces/ICurveFi.sol";
import "./interfaces/IAMM.sol";
import "./interfaces/IWeth.sol";
import "./interfaces/IPermanentStorage.sol";
import "./utils/AMMLibEIP712.sol";
import "./utils/SignatureValidator.sol";
contract AMMWrapper is
IAMM,
ReentrancyGuard,
AMMLibEIP712,
SignatureValidator
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
string public constant version = "5.2.0";
uint256 internal constant MAX_UINT = 2**256 - 1;
uint256 internal constant BPS_MAX = 10000;
address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant ZERO_ADDRESS = address(0);
address public immutable userProxy;
IWETH public immutable weth;
IPermanentStorage public immutable permStorage;
address public constant UNISWAP_V2_ROUTER_02_ADDRESS = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address public constant SUSHISWAP_ROUTER_ADDRESS = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F;
address public operator;
uint256 public subsidyFactor;
ISpender public spender;
struct TxMetaData {
string source;
bytes32 transactionHash;
uint256 settleAmount;
uint256 receivedAmount;
uint16 feeFactor;
uint16 subsidyFactor;
}
struct InternalTxData {
bool fromEth;
bool toEth;
address takerAssetInternalAddr;
address makerAssetInternalAddr;
address[] path;
bytes makerSpecificData;
}
struct CurveData {
int128 fromTokenCurveIndex;
int128 toTokenCurveIndex;
uint16 swapMethod;
}
event TransferOwnership(address newOperator);
event UpgradeSpender(address newSpender);
event SetSubsidyFactor(uint256 newSubisdyFactor);
event AllowTransfer(address spender);
event DisallowTransfer(address spender);
event DepositETH(uint256 ethBalance);
event Swapped(
string source,
bytes32 indexed transactionHash,
address indexed userAddr,
address takerAssetAddr,
uint256 takerAssetAmount,
address makerAddr,
address makerAssetAddr,
uint256 makerAssetAmount,
address receiverAddr,
uint256 settleAmount,
uint256 receivedAmount,
uint16 feeFactor,
uint16 subsidyFactor
);
receive() external payable {}
modifier onlyOperator() {
require(operator == msg.sender, "AMMWrapper: not the operator");
_;
}
modifier onlyUserProxy() {
require(address(userProxy) == msg.sender, "AMMWrapper: not the UserProxy contract");
_;
}
function transferOwnership(address _newOperator) external onlyOperator {
require(_newOperator != address(0), "AMMWrapper: operator can not be zero address");
operator = _newOperator;
emit TransferOwnership(_newOperator);
}
modifier approveTakerAsset(address _takerAssetInternalAddr, address _makerAddr) {
bool isTakerAssetETH = _isInternalAssetETH(_takerAssetInternalAddr);
if (! isTakerAssetETH) IERC20(_takerAssetInternalAddr).safeApprove(_makerAddr, MAX_UINT);
_;
if (! isTakerAssetETH) IERC20(_takerAssetInternalAddr).safeApprove(_makerAddr, 0);
}
constructor (
address _operator,
uint256 _subsidyFactor,
address _userProxy,
ISpender _spender,
IPermanentStorage _permStorage,
IWETH _weth
) public {
operator = _operator;
subsidyFactor = _subsidyFactor;
userProxy = _userProxy;
spender = _spender;
permStorage = _permStorage;
weth = _weth;
}
function upgradeSpender(address _newSpender) external onlyOperator {
require(_newSpender != address(0), "AMMWrapper: spender can not be zero address");
spender = ISpender(_newSpender);
emit UpgradeSpender(_newSpender);
}
function setSubsidyFactor(uint256 _subsidyFactor) external onlyOperator {
subsidyFactor = _subsidyFactor;
emit SetSubsidyFactor(_subsidyFactor);
}
function setAllowance(address[] calldata _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, MAX_UINT);
emit AllowTransfer(_spender);
}
}
function closeAllowance(address[] calldata _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, 0);
emit DisallowTransfer(_spender);
}
}
function depositETH() external onlyOperator {
uint256 balance = address(this).balance;
if (balance > 0) {
weth.deposit{value: balance}();
emit DepositETH(balance);
}
}
function trade(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
uint256 _feeFactor,
address _userAddr,
address payable _receiverAddr,
uint256 _salt,
uint256 _deadline,
bytes calldata _sig
)
override
payable
external
nonReentrant
onlyUserProxy
returns (uint256)
{
Order memory order = Order(
_makerAddr,
_takerAssetAddr,
_makerAssetAddr,
_takerAssetAmount,
_makerAssetAmount,
_userAddr,
_receiverAddr,
_salt,
_deadline
);
require(order.deadline >= block.timestamp, "AMMWrapper: expired order");
TxMetaData memory txMetaData;
InternalTxData memory internalTxData;
txMetaData.subsidyFactor = uint16(subsidyFactor);
txMetaData.feeFactor = uint16(_feeFactor);
if (! permStorage.isRelayerValid(tx.origin)) {
txMetaData.feeFactor = (txMetaData.subsidyFactor > txMetaData.feeFactor) ? txMetaData.subsidyFactor : txMetaData.feeFactor;
txMetaData.subsidyFactor = 0;
}
internalTxData.fromEth = (order.takerAssetAddr == ZERO_ADDRESS || order.takerAssetAddr == ETH_ADDRESS);
internalTxData.toEth = (order.makerAssetAddr == ZERO_ADDRESS || order.makerAssetAddr == ETH_ADDRESS);
if(_isCurve(order.makerAddr)) {
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? ETH_ADDRESS : order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? ETH_ADDRESS : order.makerAssetAddr;
} else {
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? address(weth) : order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? address(weth) : order.makerAssetAddr;
}
txMetaData.transactionHash = _verify(
order,
_sig
);
_prepare(order, internalTxData);
(txMetaData.source, txMetaData.receivedAmount) = _swap(
order,
txMetaData,
internalTxData
);
txMetaData.settleAmount = _settle(
order,
txMetaData,
internalTxData
);
emit Swapped(
txMetaData.source,
txMetaData.transactionHash,
order.userAddr,
order.takerAssetAddr,
order.takerAssetAmount,
order.makerAddr,
order.makerAssetAddr,
order.makerAssetAmount,
order.receiverAddr,
txMetaData.settleAmount,
txMetaData.receivedAmount,
txMetaData.feeFactor,
txMetaData.subsidyFactor
);
return txMetaData.settleAmount;
}
function _isCurve(address _makerAddr) virtual internal pure returns (bool) {
if (
_makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
_makerAddr == SUSHISWAP_ROUTER_ADDRESS
) return false;
else return true;
}
function _isInternalAssetETH(address _internalAssetAddr) internal pure returns (bool) {
if (_internalAssetAddr == ETH_ADDRESS || _internalAssetAddr == ZERO_ADDRESS) return true;
else return false;
}
function _getSelfBalance(address _makerAssetInternalAddr) internal view returns (uint256) {
if (_isInternalAssetETH(_makerAssetInternalAddr)) {
return address(this).balance;
} else {
return IERC20(_makerAssetInternalAddr).balanceOf(address(this));
}
}
function _verify(
Order memory _order,
bytes calldata _sig
) internal returns (bytes32 transactionHash) {
transactionHash = keccak256(
abi.encode(
TRADE_WITH_PERMIT_TYPEHASH,
_order.makerAddr,
_order.takerAssetAddr,
_order.makerAssetAddr,
_order.takerAssetAmount,
_order.makerAssetAmount,
_order.userAddr,
_order.receiverAddr,
_order.salt,
_order.deadline
)
);
bytes32 EIP712SignDigest = keccak256(
abi.encodePacked(
EIP191_HEADER,
EIP712_DOMAIN_SEPARATOR,
transactionHash
)
);
require(isValidSignature(_order.userAddr, EIP712SignDigest, bytes(""), _sig), "AMMWrapper: invalid user signature");
permStorage.setAMMTransactionSeen(transactionHash);
}
function _prepare(Order memory _order, InternalTxData memory _internalTxData) internal {
if (_internalTxData.fromEth) {
require(msg.value > 0, "AMMWrapper: msg.value is zero");
require(_order.takerAssetAmount == msg.value, "AMMWrapper: msg.value doesn't match");
if (! _isInternalAssetETH(_internalTxData.takerAssetInternalAddr)) {
weth.deposit{value: msg.value}();
}
} else {
spender.spendFromUser(_order.userAddr, _order.takerAssetAddr, _order.takerAssetAmount);
}
}
function _swap(
Order memory _order,
TxMetaData memory _txMetaData,
InternalTxData memory _internalTxData
)
internal
approveTakerAsset(_internalTxData.takerAssetInternalAddr, _order.makerAddr)
returns (string memory source, uint256 receivedAmount)
{
uint256 minAmount = _order.makerAssetAmount.mul((BPS_MAX.sub(_txMetaData.subsidyFactor))).div(BPS_MAX);
if (_order.makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
_order.makerAddr == SUSHISWAP_ROUTER_ADDRESS) {
source = (_order.makerAddr == SUSHISWAP_ROUTER_ADDRESS) ? "SushiSwap" : "Uniswap V2";
receivedAmount = _tradeUniswapV2TokenToToken(
_order.makerAddr,
_internalTxData.takerAssetInternalAddr,
_internalTxData.makerAssetInternalAddr,
_order.takerAssetAmount,
minAmount,
_order.deadline
);
} else {
CurveData memory curveData;
(
curveData.fromTokenCurveIndex,
curveData.toTokenCurveIndex,
curveData.swapMethod,
) = permStorage.getCurvePoolInfo(
_order.makerAddr,
_internalTxData.takerAssetInternalAddr,
_internalTxData.makerAssetInternalAddr
);
require(curveData.swapMethod != 0, "AMMWrapper: swap method not registered");
if (curveData.fromTokenCurveIndex > 0 && curveData.toTokenCurveIndex > 0) {
source = "Curve";
curveData.fromTokenCurveIndex = curveData.fromTokenCurveIndex - 1;
curveData.toTokenCurveIndex = curveData.toTokenCurveIndex - 1;
uint256 balanceBeforeTrade = _getSelfBalance(_internalTxData.makerAssetInternalAddr);
_tradeCurveTokenToToken(
_order.makerAddr,
curveData.fromTokenCurveIndex,
curveData.toTokenCurveIndex,
_order.takerAssetAmount,
minAmount,
curveData.swapMethod
);
uint256 balanceAfterTrade = _getSelfBalance(_internalTxData.makerAssetInternalAddr);
receivedAmount = balanceAfterTrade.sub(balanceBeforeTrade);
} else {
revert("AMMWrapper: unsupported makerAddr");
}
}
}
function _settle(
Order memory _order,
TxMetaData memory _txMetaData,
InternalTxData memory _internalTxData
)
internal
returns (uint256 settleAmount)
{
uint256 _feeFactor = _txMetaData.feeFactor;
uint256 _subsidyFactor = _txMetaData.subsidyFactor;
if (_txMetaData.receivedAmount == _order.makerAssetAmount) {
settleAmount = _txMetaData.receivedAmount;
} else if (_txMetaData.receivedAmount > _order.makerAssetAmount) {
bool shouldCollectFee = _txMetaData.receivedAmount.sub(_order.makerAssetAmount).mul(BPS_MAX) > _feeFactor.mul(_txMetaData.receivedAmount);
if (shouldCollectFee) {
settleAmount = _txMetaData.receivedAmount.mul(BPS_MAX.sub(_feeFactor)).div(BPS_MAX);
} else {
settleAmount = _order.makerAssetAmount;
}
} else {
require(_subsidyFactor > 0, "AMMWrapper: this trade will not be subsidized");
uint256 actualSubsidyFactor = (_subsidyFactor < _feeFactor) ? _subsidyFactor : _feeFactor;
bool inSubsidyRange = _order.makerAssetAmount.sub(_txMetaData.receivedAmount).mul(BPS_MAX) <= actualSubsidyFactor.mul(_txMetaData.receivedAmount);
require(inSubsidyRange, "AMMWrapper: amount difference larger than subsidy amount");
uint256 selfBalance = _getSelfBalance(_internalTxData.makerAssetInternalAddr);
bool hasEnoughToSubsidize = selfBalance >= _order.makerAssetAmount;
if (! hasEnoughToSubsidize && _isInternalAssetETH(_internalTxData.makerAssetInternalAddr)) {
uint256 amountShort = _order.makerAssetAmount.sub(selfBalance);
if (amountShort <= weth.balanceOf(address(this))) {
weth.withdraw(amountShort);
hasEnoughToSubsidize = true;
}
}
require(hasEnoughToSubsidize, "AMMWrapper: not enough savings to subsidize");
settleAmount = _order.makerAssetAmount;
}
if (_internalTxData.toEth) {
if (! _isInternalAssetETH(_internalTxData.makerAssetInternalAddr)) {
weth.withdraw(settleAmount);
}
_order.receiverAddr.transfer(settleAmount);
} else {
IERC20(_order.makerAssetAddr).safeTransfer(_order.receiverAddr, settleAmount);
}
}
function _tradeCurveTokenToToken(
address _makerAddr,
int128 i,
int128 j,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
uint16 swapMethod
)
internal
{
ICurveFi curve = ICurveFi(_makerAddr);
if (swapMethod == 1) {
curve.exchange{value: msg.value}(i, j, _takerAssetAmount, _makerAssetAmount);
} else if (swapMethod == 2) {
curve.exchange_underlying{value: msg.value}(i, j, _takerAssetAmount, _makerAssetAmount);
}
}
function _tradeUniswapV2TokenToToken(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
uint256 _deadline
)
internal
returns (uint256)
{
IUniswapRouterV2 router = IUniswapRouterV2(_makerAddr);
address[] memory path = new address[](2);
path[0] = _takerAssetAddr;
path[1] = _makerAssetAddr;
uint256[] memory amounts = router.swapExactTokensForTokens(
_takerAssetAmount,
_makerAssetAmount,
path,
address(this),
_deadline
);
return amounts[1];
}
}
文件 4 的 57:AMMWrapperWithPath.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./AMMWrapper.sol";
import "./interfaces/ISpender.sol";
import "./interfaces/IUniswapRouterV2.sol";
import "./interfaces/IUniswapV3SwapRouter.sol";
import "./interfaces/IPermanentStorage.sol";
import "./utils/UniswapV3PathLib.sol";
contract AMMWrapperWithPath is AMMWrapper {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using Path for bytes;
address public constant UNISWAP_V3_ROUTER_ADDRESS = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
event Swapped(
TxMetaData,
Order order
);
constructor (
address _operator,
uint256 _subsidyFactor,
address _userProxy,
ISpender _spender,
IPermanentStorage _permStorage,
IWETH _weth
) public AMMWrapper(_operator, _subsidyFactor, _userProxy, _spender, _permStorage, _weth) {}
function trade(
Order memory _order,
uint256 _feeFactor,
bytes calldata _sig,
bytes calldata _makerSpecificData,
address[] calldata _path
)
payable
external
nonReentrant
onlyUserProxy
returns (uint256)
{
require(_order.deadline >= block.timestamp, "AMMWrapper: expired order");
TxMetaData memory txMetaData;
InternalTxData memory internalTxData;
txMetaData.subsidyFactor = uint16(subsidyFactor);
txMetaData.feeFactor = uint16(_feeFactor);
internalTxData.makerSpecificData = _makerSpecificData;
internalTxData.path = _path;
if (! permStorage.isRelayerValid(tx.origin)) {
txMetaData.feeFactor = (txMetaData.subsidyFactor > txMetaData.feeFactor) ? txMetaData.subsidyFactor : txMetaData.feeFactor;
txMetaData.subsidyFactor = 0;
}
internalTxData.fromEth = (_order.takerAssetAddr == ZERO_ADDRESS || _order.takerAssetAddr == ETH_ADDRESS);
internalTxData.toEth = (_order.makerAssetAddr == ZERO_ADDRESS || _order.makerAssetAddr == ETH_ADDRESS);
if(_isCurve(_order.makerAddr)) {
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? ETH_ADDRESS : _order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? ETH_ADDRESS : _order.makerAssetAddr;
} else {
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? address(weth) : _order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? address(weth) : _order.makerAssetAddr;
}
txMetaData.transactionHash = _verify(
_order,
_sig
);
_prepare(_order, internalTxData);
(txMetaData.source, txMetaData.receivedAmount) = _swapWithPath(
_order,
txMetaData,
internalTxData
);
txMetaData.settleAmount = _settle(
_order,
txMetaData,
internalTxData
);
emit Swapped(
txMetaData,
_order
);
return txMetaData.settleAmount;
}
function _isCurve(address _makerAddr) override internal pure returns (bool) {
if (
_makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
_makerAddr == UNISWAP_V3_ROUTER_ADDRESS ||
_makerAddr == SUSHISWAP_ROUTER_ADDRESS
) return false;
else return true;
}
function _swapWithPath(
Order memory _order,
TxMetaData memory _txMetaData,
InternalTxData memory _internalTxData
)
internal
approveTakerAsset(_internalTxData.takerAssetInternalAddr, _order.makerAddr)
returns (string memory source, uint256 receivedAmount)
{
uint256 minAmount = _order.makerAssetAmount.mul((BPS_MAX.sub(_txMetaData.subsidyFactor))).div(BPS_MAX);
if (_order.makerAddr == UNISWAP_V2_ROUTER_02_ADDRESS ||
_order.makerAddr == SUSHISWAP_ROUTER_ADDRESS) {
source = (_order.makerAddr == SUSHISWAP_ROUTER_ADDRESS) ? "SushiSwap" : "Uniswap V2";
receivedAmount = _tradeUniswapV2TokenToToken(
_order.makerAddr,
_internalTxData.takerAssetInternalAddr,
_internalTxData.makerAssetInternalAddr,
_order.takerAssetAmount,
minAmount,
_order.deadline,
_internalTxData.path
);
} else if (_order.makerAddr == UNISWAP_V3_ROUTER_ADDRESS) {
source = "Uniswap V3";
receivedAmount = _tradeUniswapV3TokenToToken(
_order.makerAddr,
_internalTxData.takerAssetInternalAddr,
_internalTxData.makerAssetInternalAddr,
_order.deadline,
_order.takerAssetAmount,
minAmount,
_internalTxData.makerSpecificData
);
} else {
CurveData memory curveData;
(
curveData.fromTokenCurveIndex,
curveData.toTokenCurveIndex,
curveData.swapMethod,
) = permStorage.getCurvePoolInfo(
_order.makerAddr,
_internalTxData.takerAssetInternalAddr,
_internalTxData.makerAssetInternalAddr
);
require(curveData.swapMethod != 0,"AMMWrapper: swap method not registered");
if (curveData.fromTokenCurveIndex > 0 && curveData.toTokenCurveIndex > 0) {
source = "Curve";
curveData.fromTokenCurveIndex = curveData.fromTokenCurveIndex - 1;
curveData.toTokenCurveIndex = curveData.toTokenCurveIndex - 1;
uint256 balanceBeforeTrade = _getSelfBalance(_internalTxData.makerAssetInternalAddr);
_tradeCurveTokenToToken(
_order.makerAddr,
curveData.fromTokenCurveIndex,
curveData.toTokenCurveIndex,
_order.takerAssetAmount,
minAmount,
curveData.swapMethod
);
uint256 balanceAfterTrade = _getSelfBalance(_internalTxData.makerAssetInternalAddr);
receivedAmount = balanceAfterTrade.sub(balanceBeforeTrade);
} else {
revert("AMMWrapper: unsupported makerAddr");
}
}
}
function _tradeUniswapV2TokenToToken(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
uint256 _deadline,
address[] memory _path
)
internal
returns (uint256)
{
IUniswapRouterV2 router = IUniswapRouterV2(_makerAddr);
if (_path.length == 0) {
_path = new address[](2);
_path[0] = _takerAssetAddr;
_path[1] = _makerAssetAddr;
} else {
require(_path.length >= 2, "AMMWrapper: path length must be at least two");
require(_path[0] == _takerAssetAddr, "AMMWrapper: first element of path must match taker asset");
require(_path[_path.length - 1] == _makerAssetAddr, "AMMWrapper: last element of path must match maker asset");
}
uint256[] memory amounts = router.swapExactTokensForTokens(
_takerAssetAmount,
_makerAssetAmount,
_path,
address(this),
_deadline
);
return amounts[amounts.length - 1];
}
function _validateUniswapV3Path(
bytes memory _path,
address _takerAssetAddr,
address _makerAssetAddr
) internal {
(address tokenA, address tokenB, ) = _path.decodeFirstPool();
if (_path.hasMultiplePools()) {
_path = _path.skipToken();
while (_path.hasMultiplePools()) {
_path = _path.skipToken();
}
(, tokenB, ) = _path.decodeFirstPool();
}
require(tokenA == _takerAssetAddr, "AMMWrapper: first element of path must match taker asset");
require(tokenB == _makerAssetAddr, "AMMWrapper: last element of path must match maker asset");
}
function _tradeUniswapV3TokenToToken(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _deadline,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
bytes memory _makerSpecificData
)
internal
returns (uint256 amountOut)
{
ISwapRouter router = ISwapRouter(_makerAddr);
uint8 swapType = uint8(uint256(_makerSpecificData.readBytes32(0)));
if (swapType == 1) {
(, uint24 poolFee) = abi.decode(_makerSpecificData, (uint8, uint24));
ISwapRouter.ExactInputSingleParams memory exactInputSingleParams;
exactInputSingleParams.tokenIn = _takerAssetAddr;
exactInputSingleParams.tokenOut = _makerAssetAddr;
exactInputSingleParams.fee = poolFee;
exactInputSingleParams.recipient = address(this);
exactInputSingleParams.deadline = _deadline;
exactInputSingleParams.amountIn = _takerAssetAmount;
exactInputSingleParams.amountOutMinimum = _makerAssetAmount;
exactInputSingleParams.sqrtPriceLimitX96 = 0;
amountOut = router.exactInputSingle(exactInputSingleParams);
} else if (swapType == 2) {
(, bytes memory path) = abi.decode(_makerSpecificData, (uint8, bytes));
_validateUniswapV3Path(path, _takerAssetAddr, _makerAssetAddr);
ISwapRouter.ExactInputParams memory exactInputParams;
exactInputParams.path = path;
exactInputParams.recipient = address(this);
exactInputParams.deadline = _deadline;
exactInputParams.amountIn = _takerAssetAmount;
exactInputParams.amountOutMinimum = _makerAssetAmount;
amountOut = router.exactInput(exactInputParams);
} else {
revert("AMMWrapper: unsupported UniswapV3 swap type");
}
}
}
文件 5 的 57:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 6 的 57:AllowanceTarget.sol
pragma solidity ^0.6.5;
import "@openzeppelin/contracts/utils/Address.sol";
import "./interfaces/IAllowanceTarget.sol";
contract AllowanceTarget is IAllowanceTarget {
using Address for address;
uint256 constant private TIME_LOCK_DURATION = 1 days;
address public spender;
address public newSpender;
uint256 public timelockExpirationTime;
modifier onlySpender() {
require(spender == msg.sender, "AllowanceTarget: not the spender");
_;
}
constructor(address _spender) public {
require(_spender != address(0), "AllowanceTarget: _spender should not be 0");
spender = _spender;
}
function setSpenderWithTimelock(address _newSpender) override external onlySpender {
require(_newSpender.isContract(), "AllowanceTarget: new spender not a contract");
require(newSpender == address(0) && timelockExpirationTime == 0, "AllowanceTarget: SetSpender in progress");
timelockExpirationTime = now + TIME_LOCK_DURATION;
newSpender = _newSpender;
}
function completeSetSpender() override external {
require(timelockExpirationTime != 0, "AllowanceTarget: no pending SetSpender");
require(now >= timelockExpirationTime, "AllowanceTarget: time lock not expired yet");
spender = newSpender;
timelockExpirationTime = 0;
newSpender = address(0);
}
function teardown() override external onlySpender {
selfdestruct(payable(spender));
}
function executeCall(
address payable target,
bytes calldata callData
)
override
external
onlySpender
returns (bytes memory resultData)
{
bool success;
(success, resultData) = target.call(callData);
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
}
}
文件 7 的 57:BaseLibEIP712.sol
pragma solidity ^0.6.0;
contract BaseLibEIP712 {
string public constant EIP191_HEADER = "\x19\x01";
string public constant EIP712_DOMAIN_NAME = "Tokenlon";
string public constant EIP712_DOMAIN_VERSION = "v5";
bytes32 public immutable EIP712_DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
getChainID(),
address(this)
)
);
function getChainID() internal pure returns (uint) {
uint chainId;
assembly {
chainId := chainid()
}
return chainId;
}
}
文件 8 的 57:DelayedMultiSig.sol
pragma solidity 0.6.12;
import "./MultiSig.sol";
contract DelayedMultiSig is
MultiSig
{
event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime);
event TimeLockChange(uint32 secondsTimeLocked);
uint32 public secondsTimeLocked;
mapping (uint256 => uint256) public confirmationTimes;
modifier notFullyConfirmed(
uint256 transactionId
) {
require(
!isConfirmed(transactionId),
"TX_FULLY_CONFIRMED"
);
_;
}
modifier fullyConfirmed(
uint256 transactionId
) {
require(
isConfirmed(transactionId),
"TX_NOT_FULLY_CONFIRMED"
);
_;
}
modifier pastTimeLock(
uint256 transactionId
) virtual {
require(
block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked,
"TIME_LOCK_INCOMPLETE"
);
_;
}
constructor (
address[] memory _owners,
uint256 _required,
uint32 _secondsTimeLocked
)
public
MultiSig(_owners, _required)
{
secondsTimeLocked = _secondsTimeLocked;
}
function changeTimeLock(
uint32 _secondsTimeLocked
)
public
onlyWallet
{
secondsTimeLocked = _secondsTimeLocked;
emit TimeLockChange(_secondsTimeLocked);
}
function confirmTransaction(
uint256 transactionId
)
public
override
ownerExists(msg.sender)
transactionExists(transactionId)
notConfirmed(transactionId, msg.sender)
notFullyConfirmed(transactionId)
{
confirmations[transactionId][msg.sender] = true;
emit Confirmation(msg.sender, transactionId);
if (isConfirmed(transactionId)) {
setConfirmationTime(transactionId, block.timestamp);
}
}
function confirmTransaction(
address signer,
uint256 transactionId,
bytes memory sig
)
public
override
ownerExists(signer)
transactionExists(transactionId)
notConfirmed(transactionId, signer)
notFullyConfirmed(transactionId)
{
bytes32 EIP712SignDigest = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0x01),
EIP712_DOMAIN_SEPARATOR,
keccak256(
abi.encode(
CONFIRM_TRANSACTION_TYPE_HASH,
transactionId
)
)
)
);
validateSignature(signer, EIP712SignDigest, sig);
confirmations[transactionId][signer] = true;
emit Confirmation(signer, transactionId);
if (isConfirmed(transactionId)) {
setConfirmationTime(transactionId, block.timestamp);
}
}
function executeTransaction(
uint256 transactionId
)
public
override
ownerExists(msg.sender)
notExecuted(transactionId)
fullyConfirmed(transactionId)
pastTimeLock(transactionId)
{
Transaction storage txn = transactions[transactionId];
txn.executed = true;
bool success = externalCall(
txn.destination,
txn.value,
txn.data.length,
txn.data
);
require(
success,
"TX_REVERTED"
);
emit Execution(transactionId);
}
function executeMultipleTransactions(
uint256[] memory transactionIds
)
public
ownerExists(msg.sender)
{
for (uint256 i = 0; i < transactionIds.length; i++) {
executeTransaction(transactionIds[i]);
}
}
function setConfirmationTime(
uint256 transactionId,
uint256 confirmationTime
)
internal
{
confirmationTimes[transactionId] = confirmationTime;
emit ConfirmationTimeSet(transactionId, confirmationTime);
}
}
文件 9 的 57:ERC1271WalletStub.sol
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../interfaces/ISetAllowance.sol";
import "../interfaces/IERC1271Wallet.sol";
contract ERC1271WalletStub is
ISetAllowance,
IERC1271Wallet
{
using SafeERC20 for IERC20;
bytes4 constant internal ERC1271_MAGICVALUE = 0x20c13b0b;
bytes4 constant internal ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e;
uint256 private constant MAX_UINT = 2**256 - 1;
address public operator;
modifier onlyOperator() {
require(operator == msg.sender, "Quoter: not the operator");
_;
}
constructor (address _operator) public {
operator = _operator;
}
function setAllowance(address[] memory _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, MAX_UINT);
}
}
function closeAllowance(address[] memory _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, 0);
}
}
function isValidSignature(
bytes calldata _data,
bytes calldata _signature)
override
external
view
returns (bytes4 magicValue)
{
return ERC1271_MAGICVALUE;
}
function isValidSignature(
bytes32 _hash,
bytes calldata _signature)
override
external
view
returns (bytes4 magicValue)
{
return ERC1271_MAGICVALUE_BYTES32;
}
}
文件 10 的 57:IAMM.sol
pragma solidity ^0.6.0;
import "./ISetAllowance.sol";
interface IAMM is ISetAllowance {
function trade(
address _makerAddress,
address _fromAssetAddress,
address _toAssetAddress,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
uint256 _feeFactor,
address _spender,
address payable _receiver,
uint256 _nonce,
uint256 _deadline,
bytes memory _sig
) payable external returns (uint256);
}
文件 11 的 57:IAllowanceTarget.sol
pragma solidity ^0.6.0;
interface IAllowanceTarget {
function setSpenderWithTimelock(address _newSpender) external;
function completeSetSpender() external;
function executeCall(address payable _target, bytes calldata _callData) external returns (bytes memory resultData);
function teardown() external;
}
文件 12 的 57:ICurveFi.sol
pragma solidity >=0.5.0 <0.8.0;
interface ICurveFi {
function get_virtual_price() external returns (uint256 out);
function add_liquidity(
uint256[2] calldata amounts,
uint256 deadline
) external;
function add_liquidity(
uint256[3] calldata amounts,
uint256 min_mint_amount
) external;
function add_liquidity(
uint256[4] calldata amounts,
uint256 min_mint_amount
) external;
function get_dx(
int128 i,
int128 j,
uint256 dy
) external view returns (uint256 out);
function get_dx_underlying(
int128 i,
int128 j,
uint256 dy
) external view returns (uint256 out);
function get_dy(
int128 i,
int128 j,
uint256 dx
) external view returns (uint256 out);
function get_dy_underlying(
int128 i,
int128 j,
uint256 dx
) external view returns (uint256 out);
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external payable;
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy,
uint256 deadline
) external payable;
function exchange_underlying(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external payable;
function exchange_underlying(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy,
uint256 deadline
) external payable;
function remove_liquidity(
uint256 _amount,
uint256 deadline,
uint256[2] calldata min_amounts
) external;
function remove_liquidity_imbalance(
uint256[2] calldata amounts,
uint256 deadline
) external;
function remove_liquidity_imbalance(
uint256[3] calldata amounts,
uint256 max_burn_amount
) external;
function remove_liquidity(uint256 _amount, uint256[3] calldata amounts)
external;
function remove_liquidity_imbalance(
uint256[4] calldata amounts,
uint256 max_burn_amount
) external;
function remove_liquidity(uint256 _amount, uint256[4] calldata amounts)
external;
function commit_new_parameters(
int128 amplification,
int128 new_fee,
int128 new_admin_fee
) external;
function apply_new_parameters() external;
function revert_new_parameters() external;
function commit_transfer_ownership(address _owner) external;
function apply_transfer_ownership() external;
function revert_transfer_ownership() external;
function withdraw_admin_fees() external;
function coins(int128 arg0) external returns (address out);
function underlying_coins(int128 arg0) external returns (address out);
function balances(int128 arg0) external returns (uint256 out);
function A() external returns (int128 out);
function fee() external returns (int128 out);
function admin_fee() external returns (int128 out);
function owner() external returns (address out);
function admin_actions_deadline() external returns (uint256 out);
function transfer_ownership_deadline() external returns (uint256 out);
function future_A() external returns (int128 out);
function future_fee() external returns (int128 out);
function future_admin_fee() external returns (int128 out);
function future_owner() external returns (address out);
}
文件 13 的 57:IERC1271Wallet.sol
pragma solidity ^0.6.0;
interface IERC1271Wallet {
function isValidSignature(
bytes calldata _data,
bytes calldata _signature)
external
view
returns (bytes4 magicValue);
function isValidSignature(
bytes32 _hash,
bytes calldata _signature)
external
view
returns (bytes4 magicValue);
}
文件 14 的 57:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 15 的 57:IHasBlackListERC20Token.sol
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IHasBlackListERC20Token is IERC20 {
function isBlackListed(address user) external returns (bool);
function addBlackList(address user) external;
function removeBlackList(address user) external;
}
文件 16 的 57:IPMM.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../pmm/0xLibs/LibOrder.sol";
import "./ISetAllowance.sol";
interface IPMM is ISetAllowance {
function fill(
uint256 userSalt,
bytes memory data,
bytes memory userSignature
) external payable returns (uint256);
}
文件 17 的 57:IPermanentStorage.sol
pragma solidity ^0.6.0;
interface IPermanentStorage {
function wethAddr() external view returns (address);
function getCurvePoolInfo(address _makerAddr, address _takerAssetAddr, address _makerAssetAddr) external view returns (int128 takerAssetIndex, int128 makerAssetIndex, uint16 swapMethod, bool supportGetDx);
function setCurvePoolInfo(address _makerAddr, address[] calldata _underlyingCoins, address[] calldata _coins, bool _supportGetDx) external;
function isTransactionSeen(bytes32 _transactionHash) external view returns (bool);
function isAMMTransactionSeen(bytes32 _transactionHash) external view returns (bool);
function isRFQTransactionSeen(bytes32 _transactionHash) external view returns (bool);
function isRelayerValid(address _relayer) external view returns (bool);
function setTransactionSeen(bytes32 _transactionHash) external;
function setAMMTransactionSeen(bytes32 _transactionHash) external;
function setRFQTransactionSeen(bytes32 _transactionHash) external;
function setRelayersValid(address[] memory _relayers, bool[] memory _isValids) external;
}
文件 18 的 57:IRFQ.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../utils/RFQLibEIP712.sol";
import "./ISetAllowance.sol";
interface IRFQ is ISetAllowance {
function fill(
RFQLibEIP712.Order memory _order,
bytes memory _mmSignature,
bytes memory _userSignature
) external payable returns (uint256);
}
文件 19 的 57:ISetAllowance.sol
pragma solidity ^0.6.0;
interface ISetAllowance {
function setAllowance(address[] memory tokenList, address spender) external;
function closeAllowance(address[] memory tokenList, address spender) external;
}
文件 20 的 57:ISpender.sol
pragma solidity ^0.6.0;
interface ISpender {
function spendFromUser(address _user, address _tokenAddr, uint256 _amount) external;
function spendFromUserTo(address _user, address _tokenAddr, address _receiverAddr, uint256 _amount) external;
}
文件 21 的 57:IUniswapExchange.sol
pragma solidity >=0.5.0 <0.8.0;
interface IUniswapExchange {
function tokenAddress() external view returns (address token);
function factoryAddress() external view returns (address factory);
function addLiquidity(uint256 min_liquidity, uint256 max_tokens, uint256 deadline) external payable returns (uint256);
function removeLiquidity(uint256 amount, uint256 min_eth, uint256 min_tokens, uint256 deadline) external returns (uint256, uint256);
function getEthToTokenInputPrice(uint256 eth_sold) external view returns (uint256 tokens_bought);
function getEthToTokenOutputPrice(uint256 tokens_bought) external view returns (uint256 eth_sold);
function getTokenToEthInputPrice(uint256 tokens_sold) external view returns (uint256 eth_bought);
function getTokenToEthOutputPrice(uint256 eth_bought) external view returns (uint256 tokens_sold);
function ethToTokenSwapInput(uint256 min_tokens, uint256 deadline) external payable returns (uint256 tokens_bought);
function ethToTokenTransferInput(uint256 min_tokens, uint256 deadline, address recipient) external payable returns (uint256 tokens_bought);
function ethToTokenSwapOutput(uint256 tokens_bought, uint256 deadline) external payable returns (uint256 eth_sold);
function ethToTokenTransferOutput(uint256 tokens_bought, uint256 deadline, address recipient) external payable returns (uint256 eth_sold);
function tokenToEthSwapInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline) external returns (uint256 eth_bought);
function tokenToEthTransferInput(uint256 tokens_sold, uint256 min_eth, uint256 deadline, address recipient) external returns (uint256 eth_bought);
function tokenToEthSwapOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline) external returns (uint256 tokens_sold);
function tokenToEthTransferOutput(uint256 eth_bought, uint256 max_tokens, uint256 deadline, address recipient) external returns (uint256 tokens_sold);
function tokenToTokenSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address token_addr) external returns (uint256 tokens_bought);
function tokenToTokenTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_bought);
function tokenToTokenSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address token_addr) external returns (uint256 tokens_sold);
function tokenToTokenTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address token_addr) external returns (uint256 tokens_sold);
function tokenToExchangeSwapInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address exchange_addr) external returns (uint256 tokens_bought);
function tokenToExchangeTransferInput(uint256 tokens_sold, uint256 min_tokens_bought, uint256 min_eth_bought, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_bought);
function tokenToExchangeSwapOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address exchange_addr) external returns (uint256 tokens_sold);
function tokenToExchangeTransferOutput(uint256 tokens_bought, uint256 max_tokens_sold, uint256 max_eth_sold, uint256 deadline, address recipient, address exchange_addr) external returns (uint256 tokens_sold);
function name() external view returns (bytes32);
function symbol() external view returns (bytes32);
function decimals() external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
function allowance(address _owner, address _spender) external view returns (uint256);
function balanceOf(address _owner) external view returns (uint256);
function totalSupply() external view returns (uint256);
function setup(address token_addr) external;
}
文件 22 的 57:IUniswapFactory.sol
pragma solidity >=0.5.0 <0.8.0;
interface IUniswapFactory {
event PairCreated(
address indexed token0,
address indexed token1,
address pair,
uint256
);
function getPair(address tokenA, address tokenB)
external
view
returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function createPair(address tokenA, address tokenB)
external
returns (address pair);
function createExchange(address token) external returns (address exchange);
function getExchange(address token) external view returns (address exchange);
function getToken(address exchange) external view returns (address token);
function getTokenWithId(uint256 tokenId) external view returns (address token);
function initializeFactory(address template) external;
}
文件 23 的 57:IUniswapRouterV2.sol
pragma solidity >=0.5.0 <0.8.0;
interface IUniswapRouterV2 {
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
}
文件 24 的 57:IUniswapV3Quoter.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
interface IUniswapV3Quoter {
function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut);
function quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountOut);
function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn);
function quoteExactOutputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountOut,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountIn);
}
文件 25 的 57:IUniswapV3SwapCallback.sol
pragma solidity >=0.5.0 <0.8.0;
interface IUniswapV3SwapCallback {
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}
文件 26 的 57:IUniswapV3SwapRouter.sol
pragma solidity >=0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
import "./IUniswapV3SwapCallback.sol";
interface ISwapRouter is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}
文件 27 的 57:IWeth.sol
pragma solidity ^0.6.0;
interface IWETH {
function balanceOf(address account) external view returns (uint256);
function deposit() external payable;
function withdraw(uint256 amount) external;
function transferFrom(address src, address dst, uint wad) external returns (bool);
}
文件 28 的 57:IZeroExchange.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
interface IZeroExchange {
function executeTransaction(
uint256 salt,
address signerAddress,
bytes calldata data,
bytes calldata signature
) external;
}
文件 29 的 57:LibBytes.sol
pragma solidity ^0.6.0;
library LibBytes {
using LibBytes for bytes;
function popLastByte(bytes memory b)
internal
pure
returns (bytes1 result)
{
require(
b.length > 0,
"LibBytes#popLastByte: greater than zero length required"
);
result = b[b.length - 1];
assembly {
let newLen := sub(mload(b), 1)
mstore(b, newLen)
}
return result;
}
function readAddress(
bytes memory b,
uint256 index
)
internal
pure
returns (address result)
{
require(
b.length >= index + 20,
"LibBytes#readAddress greater or equal to 20 length required"
);
index += 20;
assembly {
result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
return result;
}
function readBytes32(
bytes memory b,
uint256 index
)
internal
pure
returns (bytes32 result)
{
require(
b.length >= index + 32,
"LibBytes#readBytes32 greater or equal to 32 length required"
);
index += 32;
assembly {
result := mload(add(b, index))
}
return result;
}
function readBytes4(
bytes memory b,
uint256 index
)
internal
pure
returns (bytes4 result)
{
require(
b.length >= index + 4,
"LibBytes#readBytes4 greater or equal to 4 length required"
);
index += 32;
assembly {
result := mload(add(b, index))
result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
}
return result;
}
function readBytes2(
bytes memory b,
uint256 index
)
internal
pure
returns (bytes2 result)
{
require(
b.length >= index + 2,
"LibBytes#readBytes2 greater or equal to 2 length required"
);
index += 32;
assembly {
result := mload(add(b, index))
result := and(result, 0xFFFF000000000000000000000000000000000000000000000000000000000000)
}
return result;
}
}
文件 30 的 57:LibDecoder.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./LibOrder.sol";
import "../../utils/LibBytes.sol";
contract LibDecoder {
using LibBytes for bytes;
function decodeFillOrder(bytes memory data) internal pure returns(LibOrder.Order memory order, uint256 takerFillAmount, bytes memory mmSignature) {
require(
data.length > 800,
"LibDecoder: LENGTH_LESS_800"
);
require(
data.readBytes4(0) == 0x64a3bc15,
"LibDecoder: WRONG_METHOD_ID"
);
bytes memory dataSlice;
assembly {
dataSlice := add(data, 4)
}
return abi.decode(dataSlice, (LibOrder.Order, uint256, bytes));
}
function decodeMmSignature(bytes memory signature) internal pure returns(uint8 v, bytes32 r, bytes32 s) {
v = uint8(signature[0]);
r = signature.readBytes32(1);
s = signature.readBytes32(33);
return (v, r, s);
}
function decodeUserSignatureWithoutSign(bytes memory signature) internal pure returns(address receiver) {
require(
signature.length == 85 || signature.length == 86,
"LibDecoder: LENGTH_85_REQUIRED"
);
receiver = signature.readAddress(65);
return receiver;
}
function decodeUserSignature(bytes memory signature) internal pure returns(uint8 v, bytes32 r, bytes32 s, address receiver) {
receiver = decodeUserSignatureWithoutSign(signature);
v = uint8(signature[0]);
r = signature.readBytes32(1);
s = signature.readBytes32(33);
return (v, r, s, receiver);
}
function decodeERC20Asset(bytes memory assetData) internal pure returns(address) {
require(
assetData.length == 36,
"LibDecoder: LENGTH_36_REQUIRED"
);
return assetData.readAddress(16);
}
}
文件 31 的 57:LibEIP712.sol
pragma solidity ^0.6.0;
contract LibEIP712 {
string constant internal EIP191_HEADER = "\x19\x01";
string constant internal EIP712_DOMAIN_NAME = "0x Protocol";
string constant internal EIP712_DOMAIN_VERSION = "2";
bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
"EIP712Domain(",
"string name,",
"string version,",
"address verifyingContract",
")"
));
bytes32 public EIP712_DOMAIN_HASH;
constructor ()
public
{
EIP712_DOMAIN_HASH = keccak256(abi.encodePacked(
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
bytes12(0),
address(this)
));
}
function hashEIP712Message(bytes32 hashStruct)
internal
view
returns (bytes32 result)
{
bytes32 eip712DomainHash = EIP712_DOMAIN_HASH;
assembly {
let memPtr := mload(64)
mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000)
mstore(add(memPtr, 2), eip712DomainHash)
mstore(add(memPtr, 34), hashStruct)
result := keccak256(memPtr, 66)
}
return result;
}
}
文件 32 的 57:LibEncoder.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./LibEIP712.sol";
contract LibEncoder is
LibEIP712
{
bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = keccak256(
abi.encodePacked(
"ZeroExTransaction(",
"uint256 salt,",
"address signerAddress,",
"bytes data",
")"
));
function encodeTransactionHash(
uint256 salt,
address signerAddress,
bytes memory data
)
internal
view
returns (bytes32 result)
{
bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
bytes32 dataHash = keccak256(data);
assembly {
let memPtr := mload(64)
mstore(memPtr, schemaHash)
mstore(add(memPtr, 32), salt)
mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(memPtr, 96), dataHash)
result := keccak256(memPtr, 128)
}
result = hashEIP712Message(result);
return result;
}
}
文件 33 的 57:LibOrder.sol
pragma solidity ^0.6.0;
import "./LibEIP712.sol";
contract LibOrder is
LibEIP712
{
bytes32 constant internal EIP712_ORDER_SCHEMA_HASH = keccak256(abi.encodePacked(
"Order(",
"address makerAddress,",
"address takerAddress,",
"address feeRecipientAddress,",
"address senderAddress,",
"uint256 makerAssetAmount,",
"uint256 takerAssetAmount,",
"uint256 makerFee,",
"uint256 takerFee,",
"uint256 expirationTimeSeconds,",
"uint256 salt,",
"bytes makerAssetData,",
"bytes takerAssetData",
")"
));
enum OrderStatus {
INVALID,
INVALID_MAKER_ASSET_AMOUNT,
INVALID_TAKER_ASSET_AMOUNT,
FILLABLE,
EXPIRED,
FULLY_FILLED,
CANCELLED
}
struct Order {
address makerAddress;
address takerAddress;
address feeRecipientAddress;
address senderAddress;
uint256 makerAssetAmount;
uint256 takerAssetAmount;
uint256 makerFee;
uint256 takerFee;
uint256 expirationTimeSeconds;
uint256 salt;
bytes makerAssetData;
bytes takerAssetData;
}
struct OrderInfo {
uint8 orderStatus;
bytes32 orderHash;
uint256 orderTakerAssetFilledAmount;
}
function getOrderHash(Order memory order)
internal
view
returns (bytes32 orderHash)
{
orderHash = hashEIP712Message(hashOrder(order));
return orderHash;
}
function hashOrder(Order memory order)
internal
pure
returns (bytes32 result)
{
bytes32 schemaHash = EIP712_ORDER_SCHEMA_HASH;
bytes32 makerAssetDataHash = keccak256(order.makerAssetData);
bytes32 takerAssetDataHash = keccak256(order.takerAssetData);
assembly {
let pos1 := sub(order, 32)
let pos2 := add(order, 320)
let pos3 := add(order, 352)
let temp1 := mload(pos1)
let temp2 := mload(pos2)
let temp3 := mload(pos3)
mstore(pos1, schemaHash)
mstore(pos2, makerAssetDataHash)
mstore(pos3, takerAssetDataHash)
result := keccak256(pos1, 416)
mstore(pos1, temp1)
mstore(pos2, temp2)
mstore(pos3, temp3)
}
return result;
}
}
文件 34 的 57:MarketMakerProxy.sol
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "./interfaces/IWeth.sol";
import "./pmm/mmp/Ownable.sol";
import "./pmm/0xLibs/LibDecoder.sol";
interface IIMBTC {
function burn(uint256 amount, bytes calldata data) external;
}
interface IWBTC {
function burn(uint256 value) external;
}
contract MarketMakerProxy is
Ownable,
LibDecoder
{
using SafeERC20 for IERC20;
string public constant version = "5.0.0";
uint256 constant MAX_UINT = 2**256 - 1;
address public SIGNER;
address public WETH_ADDR;
address public withdrawer;
mapping (address => bool) public isWithdrawWhitelist;
modifier onlyWithdrawer() {
require(
msg.sender == withdrawer,
"MarketMakerProxy: only contract withdrawer"
);
_;
}
constructor () public {
owner = msg.sender;
operator = msg.sender;
}
receive() external payable {}
function setSigner(address _signer) public onlyOperator {
SIGNER = _signer;
}
function setConfig(address _weth) public onlyOperator {
WETH_ADDR = _weth;
}
function setWithdrawer(address _withdrawer) public onlyOperator {
withdrawer = _withdrawer;
}
function setAllowance(address[] memory token_addrs, address spender) public onlyOperator {
for (uint i = 0; i < token_addrs.length; i++) {
address token = token_addrs[i];
IERC20(token).safeApprove(spender, MAX_UINT);
}
}
function closeAllowance(address[] memory token_addrs, address spender) public onlyOperator {
for (uint i = 0; i < token_addrs.length; i++) {
address token = token_addrs[i];
IERC20(token).safeApprove(spender, 0);
}
}
function registerWithdrawWhitelist(address _addr, bool _add) public onlyOperator {
isWithdrawWhitelist[_addr] = _add;
}
function withdraw(address token, address payable to, uint256 amount) public onlyWithdrawer {
require(
isWithdrawWhitelist[to],
"MarketMakerProxy: not in withdraw whitelist"
);
if(token == WETH_ADDR) {
IWETH(WETH_ADDR).withdraw(amount);
to.transfer(amount);
} else {
IERC20(token).safeTransfer(to , amount);
}
}
function withdrawETH(address payable to, uint256 amount) public onlyWithdrawer {
require(
isWithdrawWhitelist[to],
"MarketMakerProxy: not in withdraw whitelist"
);
to.transfer(amount);
}
function isValidSignature(bytes32 orderHash, bytes memory signature) public view returns (bytes32) {
require(
SIGNER == _ecrecoverAddress(orderHash, signature),
"MarketMakerProxy: invalid signature"
);
return keccak256("isValidWalletSignature(bytes32,address,bytes)");
}
function _ecrecoverAddress(bytes32 orderHash, bytes memory signature) internal pure returns (address) {
(uint8 v, bytes32 r, bytes32 s) = decodeMmSignature(signature);
return ecrecover(
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
orderHash
)),
v, r, s
);
}
}
文件 35 的 57:MiningTreasury.sol
pragma solidity 0.6.12;
import "./MultiSig.sol";
contract MiningTreasury is MultiSig {
constructor (
address[] memory _owners,
uint256 _required
)
public
MultiSig(_owners, _required)
{
}
}
文件 36 的 57:MultiSig.sol
pragma solidity 0.6.12;
import "../utils/LibBytes.sol";
import "./MultiSigLibEIP712.sol";
contract MultiSig is MultiSigLibEIP712 {
using LibBytes for bytes;
event Deposit(address indexed depositer, uint256 amount);
event Confirmation(address indexed sender, uint256 indexed transactionId);
event Revocation(address indexed sender, uint256 indexed transactionId);
event Submission(uint256 indexed transactionId);
event Execution(uint256 indexed transactionId);
event ExecutionFailure(uint256 indexed transactionId);
event OwnerAddition(address indexed owner);
event OwnerRemoval(address indexed owner);
event RequirementChange(uint256 required);
uint256 constant public MAX_OWNER_COUNT = 50;
address constant ADDRESS_ZERO = address(0x0);
mapping (uint256 => Transaction) public transactions;
mapping (uint256 => mapping (address => bool)) public confirmations;
mapping (address => bool) public isOwner;
address[] public owners;
uint256 public required;
uint256 public transactionCount;
struct Transaction {
address destination;
uint256 value;
bytes data;
bool executed;
}
modifier onlyWallet() {
require(msg.sender == address(this));
_;
}
modifier ownerDoesNotExist(
address owner
) {
require(!isOwner[owner]);
_;
}
modifier ownerExists(
address owner
) {
require(isOwner[owner]);
_;
}
modifier transactionExists(
uint256 transactionId
) {
require(transactions[transactionId].destination != ADDRESS_ZERO);
_;
}
modifier confirmed(
uint256 transactionId,
address owner
) {
require(confirmations[transactionId][owner]);
_;
}
modifier notConfirmed(
uint256 transactionId,
address owner
) {
require(!confirmations[transactionId][owner]);
_;
}
modifier notExecuted(
uint256 transactionId
) {
require(!transactions[transactionId].executed);
_;
}
modifier notNull(
address _address
) {
require(_address != ADDRESS_ZERO);
_;
}
modifier validRequirement(
uint256 ownerCount,
uint256 _required
) {
require(
ownerCount <= MAX_OWNER_COUNT
&& _required <= ownerCount
&& _required != 0
&& ownerCount != 0
);
_;
}
receive() external payable {
emit Deposit(msg.sender, msg.value);
}
constructor(
address[] memory _owners,
uint256 _required
)
public
validRequirement(_owners.length, _required)
MultiSigLibEIP712()
{
for (uint256 i = 0; i < _owners.length; i++) {
require(!isOwner[_owners[i]] && _owners[i] != ADDRESS_ZERO);
isOwner[_owners[i]] = true;
}
owners = _owners;
required = _required;
}
function addOwner(
address owner
)
public
onlyWallet
ownerDoesNotExist(owner)
notNull(owner)
validRequirement(owners.length + 1, required)
{
isOwner[owner] = true;
owners.push(owner);
emit OwnerAddition(owner);
}
function removeOwner(
address owner
)
public
onlyWallet
ownerExists(owner)
{
isOwner[owner] = false;
for (uint256 i = 0; i < owners.length - 1; i++) {
if (owners[i] == owner) {
owners[i] = owners[owners.length - 1];
break;
}
}
delete owners[owners.length - 1];
if (required > owners.length) {
changeRequirement(owners.length);
}
emit OwnerRemoval(owner);
}
function replaceOwner(
address owner,
address newOwner
)
public
onlyWallet
ownerExists(owner)
ownerDoesNotExist(newOwner)
notNull(newOwner)
{
for (uint256 i = 0; i < owners.length; i++) {
if (owners[i] == owner) {
owners[i] = newOwner;
break;
}
}
isOwner[owner] = false;
isOwner[newOwner] = true;
emit OwnerRemoval(owner);
emit OwnerAddition(newOwner);
}
function changeRequirement(
uint256 _required
)
public
onlyWallet
validRequirement(owners.length, _required)
{
required = _required;
emit RequirementChange(_required);
}
function submitTransaction(
address destination,
uint256 value,
bytes memory data
)
public
returns (uint256)
{
uint256 transactionId = addTransaction(destination, value, data);
confirmTransaction(transactionId);
return transactionId;
}
function submitTransaction(
address signer,
uint256 transactionId,
address destination,
uint256 value,
bytes memory data,
bytes memory sig
)
public
ownerExists(signer)
returns (uint256)
{
bytes32 EIP712SignDigest = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0x01),
EIP712_DOMAIN_SEPARATOR,
keccak256(
abi.encode(
SUBMIT_TRANSACTION_TYPE_HASH,
transactionId,
destination,
value,
data
)
)
)
);
validateSignature(signer, EIP712SignDigest, sig);
uint256 _transactionId = addTransaction(destination, value, data);
require(transactionId == _transactionId);
confirmTransactionBySigner(signer, transactionId);
return transactionId;
}
function confirmTransactionBySigner(
address signer,
uint256 transactionId
)
internal
transactionExists(transactionId)
notConfirmed(transactionId, signer)
{
confirmations[transactionId][signer] = true;
emit Confirmation(signer, transactionId);
executeTransactionBySigner(signer, transactionId);
}
function executeTransactionBySigner(
address signer,
uint256 transactionId
)
internal
notExecuted(transactionId)
{
if (isConfirmed(transactionId)) {
Transaction storage txn = transactions[transactionId];
txn.executed = true;
if (externalCall(
txn.destination,
txn.value,
txn.data.length,
txn.data)
) {
emit Execution(transactionId);
} else {
emit ExecutionFailure(transactionId);
txn.executed = false;
}
}
}
function confirmTransaction(
uint256 transactionId
)
public
virtual
ownerExists(msg.sender)
transactionExists(transactionId)
notConfirmed(transactionId, msg.sender)
{
confirmations[transactionId][msg.sender] = true;
emit Confirmation(msg.sender, transactionId);
executeTransaction(transactionId);
}
function confirmTransaction(
address signer,
uint256 transactionId,
bytes memory sig
)
public
virtual
ownerExists(signer)
transactionExists(transactionId)
notConfirmed(transactionId, signer)
{
bytes32 EIP712SignDigest = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0x01),
EIP712_DOMAIN_SEPARATOR,
keccak256(
abi.encode(
CONFIRM_TRANSACTION_TYPE_HASH,
transactionId
)
)
)
);
validateSignature(signer, EIP712SignDigest, sig);
confirmations[transactionId][signer] = true;
emit Confirmation(signer, transactionId);
executeTransactionBySigner(signer, transactionId);
}
function revokeConfirmation(
uint256 transactionId
)
public
ownerExists(msg.sender)
confirmed(transactionId, msg.sender)
notExecuted(transactionId)
{
confirmations[transactionId][msg.sender] = false;
emit Revocation(msg.sender, transactionId);
}
function executeTransaction(
uint256 transactionId
)
public
virtual
ownerExists(msg.sender)
confirmed(transactionId, msg.sender)
notExecuted(transactionId)
{
if (isConfirmed(transactionId)) {
Transaction storage txn = transactions[transactionId];
txn.executed = true;
if (externalCall(
txn.destination,
txn.value,
txn.data.length,
txn.data)
) {
emit Execution(transactionId);
} else {
emit ExecutionFailure(transactionId);
txn.executed = false;
}
}
}
function isConfirmed(
uint256 transactionId
)
public
view
returns (bool)
{
uint256 count = 0;
for (uint256 i = 0; i < owners.length; i++) {
if (confirmations[transactionId][owners[i]]) {
count += 1;
}
if (count == required) {
return true;
}
}
}
function getConfirmationCount(
uint256 transactionId
)
public
view
returns (uint256)
{
uint256 count = 0;
for (uint256 i = 0; i < owners.length; i++) {
if (confirmations[transactionId][owners[i]]) {
count += 1;
}
}
return count;
}
function getTransactionCount(
bool pending,
bool executed
)
public
view
returns (uint256)
{
uint256 count = 0;
for (uint256 i = 0; i < transactionCount; i++) {
if (
pending && !transactions[i].executed
|| executed && transactions[i].executed
) {
count += 1;
}
}
return count;
}
function getOwners()
public
view
returns (address[] memory)
{
return owners;
}
function getConfirmations(
uint256 transactionId
)
public
view
returns (address[] memory)
{
address[] memory confirmationsTemp = new address[](owners.length);
uint256 count = 0;
uint256 i;
for (i = 0; i < owners.length; i++) {
if (confirmations[transactionId][owners[i]]) {
confirmationsTemp[count] = owners[i];
count += 1;
}
}
address[] memory _confirmations = new address[](count);
for (i = 0; i < count; i++) {
_confirmations[i] = confirmationsTemp[i];
}
return _confirmations;
}
function getTransactionIds(
uint256 from,
uint256 to,
bool pending,
bool executed
)
public
view
returns (uint256[] memory)
{
uint256[] memory transactionIdsTemp = new uint256[](transactionCount);
uint256 count = 0;
uint256 i;
for (i = 0; i < transactionCount; i++) {
if (
pending && !transactions[i].executed
|| executed && transactions[i].executed
) {
transactionIdsTemp[count] = i;
count += 1;
}
}
uint256[] memory _transactionIds = new uint256[](to - from);
for (i = from; i < to; i++) {
_transactionIds[i - from] = transactionIdsTemp[i];
}
return _transactionIds;
}
function validateSignature(
address signer,
bytes32 digest,
bytes memory sig
)
internal
{
require(sig.length == 65);
uint8 v = uint8(sig[64]);
bytes32 r = sig.readBytes32(0);
bytes32 s = sig.readBytes32(32);
address recovered = ecrecover(digest, v, r, s);
require(signer == recovered);
}
function externalCall(
address destination,
uint256 value,
uint256 dataLength,
bytes memory data
)
internal
returns (bool)
{
bool result;
assembly {
let x := mload(0x40)
let d := add(data, 32)
result := call(
sub(gas(), 34710),
destination,
value,
d,
dataLength,
x,
0
)
}
return result;
}
function addTransaction(
address destination,
uint256 value,
bytes memory data
)
internal
notNull(destination)
returns (uint256)
{
uint256 transactionId = transactionCount;
transactions[transactionId] = Transaction({
destination: destination,
value: value,
data: data,
executed: false
});
transactionCount += 1;
emit Submission(transactionId);
return transactionId;
}
}
文件 37 的 57:MultiSigLibEIP712.sol
pragma solidity 0.6.12;
contract MultiSigLibEIP712 {
string public constant EIP712_DOMAIN_NAME = "MultiSig";
string public constant EIP712_DOMAIN_VERSION = "v1";
bytes32 public EIP712_DOMAIN_SEPARATOR;
bytes32 public constant SUBMIT_TRANSACTION_TYPE_HASH = 0x2c78e27c3bb2592e67e8d37ad1a95bfccd188e77557c22593b1af0b920a08295;
bytes32 public constant CONFIRM_TRANSACTION_TYPE_HASH = 0x3e96bdc38d4133bc81813a187b2d41bc74332643ce7dbe82c7d94ead8366a65f;
constructor() public {
EIP712_DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
getChainID(),
address(this)
)
);
}
function getChainID() internal pure returns (uint) {
uint chainId;
assembly {
chainId := chainid()
}
return chainId;
}
}
文件 38 的 57:Ownable.sol
pragma solidity ^0.6.0;
contract Ownable {
address public owner;
address public operator;
constructor ()
public
{
owner = msg.sender;
}
modifier onlyOwner() {
require(
msg.sender == owner,
"Ownable: only contract owner"
);
_;
}
modifier onlyOperator() {
require(
msg.sender == operator,
"Ownable: only contract operator"
);
_;
}
function transferOwnership(address newOwner)
public
onlyOwner
{
if (newOwner != address(0)) {
owner = newOwner;
}
}
function setOperator(address newOperator)
public
onlyOwner
{
operator = newOperator;
}
}
文件 39 的 57:PMM.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "./pmm/0xLibs/LibOrder.sol";
import "./pmm/0xLibs/LibDecoder.sol";
import "./pmm/0xLibs/LibEncoder.sol";
import "./interfaces/ISpender.sol";
import "./interfaces/IZeroExchange.sol";
import "./interfaces/IWeth.sol";
import "./interfaces/IPMM.sol";
import "./interfaces/IPermanentStorage.sol";
import "./interfaces/IERC1271Wallet.sol";
contract PMM is
ReentrancyGuard,
IPMM,
LibOrder,
LibDecoder,
LibEncoder
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
using Address for address;
string public constant version = "5.0.0";
uint256 private constant MAX_UINT = 2**256 - 1;
string public constant SOURCE = "0x v2";
uint256 private constant BPS_MAX = 10000;
bytes4 constant internal ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e;
address public immutable userProxy;
ISpender public immutable spender;
IPermanentStorage public immutable permStorage;
IZeroExchange public immutable zeroExchange;
address public immutable zxERC20Proxy;
address public operator;
struct TradeInfo {
address user;
address receiver;
uint16 feeFactor;
address makerAssetAddr;
address takerAssetAddr;
bytes32 transactionHash;
bytes32 orderHash;
}
event FillOrder(
string source,
bytes32 indexed transactionHash,
bytes32 indexed orderHash,
address indexed userAddr,
address takerAssetAddr,
uint256 takerAssetAmount,
address makerAddr,
address makerAssetAddr,
uint256 makerAssetAmount,
address receiverAddr,
uint256 settleAmount,
uint16 feeFactor
);
receive() external payable {}
modifier onlyOperator {
require(operator == msg.sender, "PMM: not operator");
_;
}
modifier onlyUserProxy() {
require(address(userProxy) == msg.sender, "PMM: not the UserProxy contract");
_;
}
function transferOwnership(address _newOperator) external onlyOperator {
require(_newOperator != address(0), "AMMWrapper: operator can not be zero address");
operator = _newOperator;
}
constructor (address _operator, address _userProxy, ISpender _spender, IPermanentStorage _permStorage, IZeroExchange _zeroExchange, address _zxERC20Proxy) public {
operator = _operator;
userProxy = _userProxy;
spender = _spender;
permStorage = _permStorage;
zeroExchange = _zeroExchange;
zxERC20Proxy = _zxERC20Proxy;
EIP712_DOMAIN_HASH = keccak256(
abi.encodePacked(
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(bytes(EIP712_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)),
bytes12(0),
address(_zeroExchange)
)
);
}
function setAllowance(address[] calldata _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, MAX_UINT);
}
}
function closeAllowance(address[] calldata _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, 0);
}
}
function fill(
uint256 userSalt,
bytes memory data,
bytes memory userSignature
)
override
public
payable
onlyUserProxy
nonReentrant
returns (uint256)
{
(LibOrder.Order memory order,
TradeInfo memory tradeInfo) = _assertTransaction(userSalt, data, userSignature);
IWETH weth = IWETH(permStorage.wethAddr());
if (address(weth) == tradeInfo.takerAssetAddr) {
require(
msg.value == order.takerAssetAmount,
"PMM: insufficient ETH"
);
weth.deposit{value: msg.value}();
} else {
spender.spendFromUser(tradeInfo.user, tradeInfo.takerAssetAddr, order.takerAssetAmount);
}
IERC20(tradeInfo.takerAssetAddr).safeIncreaseAllowance(zxERC20Proxy, order.takerAssetAmount);
zeroExchange.executeTransaction(
userSalt,
address(this),
data,
""
);
uint256 settleAmount = _settle(weth, tradeInfo.receiver, tradeInfo.makerAssetAddr, order.makerAssetAmount, tradeInfo.feeFactor);
IERC20(tradeInfo.takerAssetAddr).safeApprove(zxERC20Proxy, 0);
emit FillOrder(
SOURCE,
tradeInfo.transactionHash,
tradeInfo.orderHash,
tradeInfo.user,
tradeInfo.takerAssetAddr,
order.takerAssetAmount,
order.makerAddress,
tradeInfo.makerAssetAddr,
order.makerAssetAmount,
tradeInfo.receiver,
settleAmount,
tradeInfo.feeFactor
);
return settleAmount;
}
function _assertTransaction(
uint256 userSalt,
bytes memory data,
bytes memory userSignature
)
internal
view
returns(
LibOrder.Order memory order,
TradeInfo memory tradeInfo
)
{
uint256 takerFillAmount;
bytes memory mmSignature;
(order, takerFillAmount, mmSignature) = decodeFillOrder(data);
require(
order.takerAddress == address(this),
"PMM: incorrect taker"
);
require(
order.takerAssetAmount == takerFillAmount,
"PMM: incorrect fill amount"
);
tradeInfo.transactionHash = encodeTransactionHash(
userSalt,
address(this),
data
);
tradeInfo.orderHash = getOrderHash(order);
tradeInfo.feeFactor = uint16(order.salt);
tradeInfo.receiver = decodeUserSignatureWithoutSign(userSignature);
tradeInfo.user = _ecrecoverAddress(tradeInfo.transactionHash, userSignature);
if (tradeInfo.user != order.feeRecipientAddress) {
require(
order.feeRecipientAddress.isContract(),
"PMM: invalid contract address"
);
require(
ERC1271_MAGICVALUE_BYTES32 == IERC1271Wallet(order.feeRecipientAddress)
.isValidSignature(
tradeInfo.transactionHash,
userSignature
),
"PMM: invalid ERC1271 signer"
);
tradeInfo.user = order.feeRecipientAddress;
}
require(
tradeInfo.feeFactor < BPS_MAX,
"PMM: invalid fee factor"
);
require(
tradeInfo.receiver != address(0),
"PMM: invalid receiver"
);
tradeInfo.makerAssetAddr = decodeERC20Asset(order.makerAssetData);
tradeInfo.takerAssetAddr = decodeERC20Asset(order.takerAssetData);
return (
order,
tradeInfo
);
}
function _settle(IWETH weth, address receiver, address makerAssetAddr, uint256 makerAssetAmount, uint16 feeFactor) internal returns(uint256) {
uint256 settleAmount = makerAssetAmount;
if (feeFactor > 0) {
settleAmount = settleAmount.mul((BPS_MAX).sub(feeFactor)).div(BPS_MAX);
}
if (makerAssetAddr == address(weth)){
weth.withdraw(settleAmount);
payable(receiver).transfer(settleAmount);
} else {
IERC20(makerAssetAddr).safeTransfer(receiver, settleAmount);
}
return settleAmount;
}
function _ecrecoverAddress(bytes32 transactionHash, bytes memory signature) internal pure returns (address){
(uint8 v, bytes32 r, bytes32 s, address receiver) = decodeUserSignature(signature);
return ecrecover(
keccak256(
abi.encodePacked(
transactionHash,
receiver
)),
v, r, s
);
}
}
文件 40 的 57:PSStorage.sol
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
library PSStorage {
bytes32 private constant STORAGE_SLOT = 0x92dd52b981a2dd69af37d8a3febca29ed6a974aede38ae66e4ef773173aba471;
struct Storage {
address ammWrapperAddr;
address pmmAddr;
address wethAddr;
address rfqAddr;
}
function getStorage() internal pure returns (Storage storage stor) {
assert(STORAGE_SLOT == bytes32(uint256(keccak256("permanent.storage.storage")) - 1));
bytes32 slot = STORAGE_SLOT;
assembly { stor_slot := slot }
}
}
library AMMWrapperStorage {
bytes32 private constant STORAGE_SLOT = 0xd38d862c9fa97c2fa857a46e08022d272a3579c114ca4f335f1e5fcb692c045e;
struct Storage {
mapping(bytes32 => bool) transactionSeen;
mapping(address => mapping(address => int128)) curveTokenIndexes;
mapping(address => bool) relayerValid;
mapping(address => mapping(address => int128)) curveWrappedTokenIndexes;
mapping(address => bool) curveSupportGetDx;
}
function getStorage() internal pure returns (Storage storage stor) {
assert(STORAGE_SLOT == bytes32(uint256(keccak256("permanent.ammwrapper.storage")) - 1));
bytes32 slot = STORAGE_SLOT;
assembly { stor_slot := slot }
}
}
library RFQStorage {
bytes32 private constant STORAGE_SLOT = 0x9174e76494cfb023ddc1eb0effb6c12e107165382bbd0ecfddbc38ea108bbe52;
struct Storage {
mapping(bytes32 => bool) transactionSeen;
}
function getStorage() internal pure returns (Storage storage stor) {
assert(STORAGE_SLOT == bytes32(uint256(keccak256("permanent.rfq.storage")) - 1));
bytes32 slot = STORAGE_SLOT;
assembly { stor_slot := slot }
}
}
文件 41 的 57:PartiallyDelayedMultiSig.sol
pragma solidity 0.6.12;
import "./DelayedMultiSig.sol";
contract PartiallyDelayedMultiSig is
DelayedMultiSig
{
event SelectorSet(address destination, bytes4 selector, bool approved);
bytes4 constant internal BYTES_ZERO = bytes4(0x0);
mapping (address => mapping (bytes4 => bool)) public instantData;
modifier pastTimeLock(
uint256 transactionId
) override {
require(
block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked
|| txCanBeExecutedInstantly(transactionId),
"TIME_LOCK_INCOMPLETE"
);
_;
}
constructor (
address[] memory _owners,
uint256 _required,
uint32 _secondsTimeLocked,
address[] memory _noDelayDestinations,
bytes4[] memory _noDelaySelectors
)
public
DelayedMultiSig(_owners, _required, _secondsTimeLocked)
{
require(
_noDelayDestinations.length == _noDelaySelectors.length,
"ADDRESS_AND_SELECTOR_MISMATCH"
);
for (uint256 i = 0; i < _noDelaySelectors.length; i++) {
address destination = _noDelayDestinations[i];
bytes4 selector = _noDelaySelectors[i];
instantData[destination][selector] = true;
emit SelectorSet(destination, selector, true);
}
}
function setSelector(
address destination,
bytes4 selector,
bool approved
)
public
onlyWallet
{
instantData[destination][selector] = approved;
emit SelectorSet(destination, selector, approved);
}
function txCanBeExecutedInstantly(
uint256 transactionId
)
internal
view
returns (bool)
{
Transaction memory txn = transactions[transactionId];
address dest = txn.destination;
bytes memory data = txn.data;
if (data.length == 0) {
return selectorCanBeExecutedInstantly(dest, BYTES_ZERO);
}
if (data.length < 4) {
return false;
}
bytes32 rawData;
assembly {
rawData := mload(add(data, 32))
}
bytes4 selector = bytes4(rawData);
return selectorCanBeExecutedInstantly(dest, selector);
}
function selectorCanBeExecutedInstantly(
address destination,
bytes4 selector
)
internal
view
returns (bool)
{
return instantData[destination][selector]
|| instantData[ADDRESS_ZERO][selector];
}
}
文件 42 的 57:PermanentStorage.sol
pragma solidity ^0.6.5;
import "./interfaces/IPermanentStorage.sol";
import "./utils/lib_storage/PSStorage.sol";
contract PermanentStorage is IPermanentStorage {
bytes32 public constant curveTokenIndexStorageId = 0xf4c750cdce673f6c35898d215e519b86e3846b1f0532fb48b84fe9d80f6de2fc;
bytes32 public constant transactionSeenStorageId = 0x695d523b8578c6379a2121164fd8de334b9c5b6b36dff5408bd4051a6b1704d0;
bytes32 public constant relayerValidStorageId = 0x2c97779b4deaf24e9d46e02ec2699240a957d92782b51165b93878b09dd66f61;
address public constant CURVE_renBTC_POOL = 0x93054188d876f558f4a66B2EF1d97d16eDf0895B;
address public constant CURVE_sBTC_POOL = 0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714;
address public constant CURVE_hBTC_POOL = 0x4CA9b3063Ec5866A4B82E437059D2C43d1be596F;
address public constant CURVE_sETH_POOL = 0xc5424B857f758E906013F3555Dad202e4bdB4567;
address private constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address private constant renBTC = 0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D;
address private constant wBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address private constant sBTC = 0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6;
address private constant hBTC = 0x0316EB71485b0Ab14103307bf65a021042c6d380;
address private constant sETH = 0x5e74C9036fb86BD7eCdcb084a0673EFc32eA31cb;
address public operator;
string public version;
mapping(bytes32 => mapping(address => bool)) private permission;
event TransferOwnership(address newOperator);
event SetPermission(bytes32 storageId, address role, bool enabled);
event UpgradeAMMWrapper(address newAMMWrapper);
event UpgradePMM(address newPMM);
event UpgradeRFQ(address newRFQ);
event UpgradeWETH(address newWETH);
modifier onlyOperator() {
require(operator == msg.sender, "PermanentStorage: not the operator");
_;
}
modifier validRole(bool _enabled, address _role) {
if (_enabled) {
require(
(_role == operator) || (_role == ammWrapperAddr()) || (_role == pmmAddr() || (_role == rfqAddr())),
"PermanentStorage: not a valid role"
);
}
_;
}
modifier isPermitted(bytes32 _storageId, address _role) {
require(permission[_storageId][_role], "PermanentStorage: has no permission");
_;
}
function transferOwnership(address _newOperator) external onlyOperator {
require(_newOperator != address(0), "PermanentStorage: operator can not be zero address");
operator = _newOperator;
emit TransferOwnership(_newOperator);
}
function setPermission(bytes32 _storageId, address _role, bool _enabled) external onlyOperator validRole(_enabled, _role) {
permission[_storageId][_role] = _enabled;
emit SetPermission(_storageId, _role, _enabled);
}
function initialize() external {
require(
keccak256(abi.encodePacked(version)) == keccak256(abi.encodePacked("5.1.0")),
"PermanentStorage: not upgrading from 5.1.0 version"
);
version = "5.2.0";
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_renBTC_POOL][renBTC] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_renBTC_POOL][wBTC] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_renBTC_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sBTC_POOL][renBTC] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sBTC_POOL][wBTC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sBTC_POOL][sBTC] = 3;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_sBTC_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_hBTC_POOL][hBTC] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_hBTC_POOL][wBTC] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_hBTC_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sETH_POOL][ETH] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sETH_POOL][sETH] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_sETH_POOL] = false;
}
function hasPermission(bytes32 _storageId, address _role) external view returns (bool) {
return permission[_storageId][_role];
}
function ammWrapperAddr() public view returns (address) {
return PSStorage.getStorage().ammWrapperAddr;
}
function pmmAddr() public view returns (address) {
return PSStorage.getStorage().pmmAddr;
}
function rfqAddr() public view returns (address) {
return PSStorage.getStorage().rfqAddr;
}
function wethAddr() override external view returns (address) {
return PSStorage.getStorage().wethAddr;
}
function getCurvePoolInfo(address _makerAddr, address _takerAssetAddr, address _makerAssetAddr) override external view returns (int128 takerAssetIndex, int128 makerAssetIndex, uint16 swapMethod, bool supportGetDx) {
int128 i = AMMWrapperStorage.getStorage().curveTokenIndexes[_makerAddr][_takerAssetAddr];
int128 j = AMMWrapperStorage.getStorage().curveTokenIndexes[_makerAddr][_makerAssetAddr];
supportGetDx = AMMWrapperStorage.getStorage().curveSupportGetDx[_makerAddr];
swapMethod = 0;
if (i != 0 && j != 0) {
takerAssetIndex = i;
makerAssetIndex = j;
swapMethod = 2;
} else {
int128 iWrapped = AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[_makerAddr][_takerAssetAddr];
int128 jWrapped = AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[_makerAddr][_makerAssetAddr];
if (iWrapped != 0 && jWrapped != 0) {
takerAssetIndex = iWrapped;
makerAssetIndex = jWrapped;
swapMethod = 1;
} else {
revert("PermanentStorage: invalid pair");
}
}
return (takerAssetIndex, makerAssetIndex, swapMethod, supportGetDx);
}
function isTransactionSeen(bytes32 _transactionHash) override external view returns (bool) {
return AMMWrapperStorage.getStorage().transactionSeen[_transactionHash];
}
function isAMMTransactionSeen(bytes32 _transactionHash) override external view returns (bool) {
return AMMWrapperStorage.getStorage().transactionSeen[_transactionHash];
}
function isRFQTransactionSeen(bytes32 _transactionHash) override external view returns (bool) {
return RFQStorage.getStorage().transactionSeen[_transactionHash];
}
function isRelayerValid(address _relayer) override external view returns (bool) {
return AMMWrapperStorage.getStorage().relayerValid[_relayer];
}
function upgradeAMMWrapper(address _newAMMWrapper) external onlyOperator {
PSStorage.getStorage().ammWrapperAddr = _newAMMWrapper;
emit UpgradeAMMWrapper(_newAMMWrapper);
}
function upgradePMM(address _newPMM) external onlyOperator {
PSStorage.getStorage().pmmAddr = _newPMM;
emit UpgradePMM(_newPMM);
}
function upgradeRFQ(address _newRFQ) external onlyOperator {
PSStorage.getStorage().rfqAddr = _newRFQ;
emit UpgradeRFQ(_newRFQ);
}
function upgradeWETH(address _newWETH) external onlyOperator {
PSStorage.getStorage().wethAddr = _newWETH;
emit UpgradeWETH(_newWETH);
}
function setCurvePoolInfo(address _makerAddr, address[] calldata _underlyingCoins, address[] calldata _coins, bool _supportGetDx) override external isPermitted(curveTokenIndexStorageId, msg.sender) {
int128 underlyingCoinsLength = int128(_underlyingCoins.length);
for (int128 i = 0 ; i < underlyingCoinsLength; i++) {
address assetAddr = _underlyingCoins[uint256(i)];
AMMWrapperStorage.getStorage().curveTokenIndexes[_makerAddr][assetAddr] = i + 1;
}
int128 coinsLength = int128(_coins.length);
for (int128 i = 0 ; i < coinsLength; i++) {
address assetAddr = _coins[uint256(i)];
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[_makerAddr][assetAddr] = i + 1;
}
AMMWrapperStorage.getStorage().curveSupportGetDx[_makerAddr] = _supportGetDx;
}
function setTransactionSeen(bytes32 _transactionHash) override external isPermitted(transactionSeenStorageId, msg.sender) {
require(!AMMWrapperStorage.getStorage().transactionSeen[_transactionHash], "PermanentStorage: transaction seen before");
AMMWrapperStorage.getStorage().transactionSeen[_transactionHash] = true;
}
function setAMMTransactionSeen(bytes32 _transactionHash) override external isPermitted(transactionSeenStorageId, msg.sender) {
require(!AMMWrapperStorage.getStorage().transactionSeen[_transactionHash], "PermanentStorage: transaction seen before");
AMMWrapperStorage.getStorage().transactionSeen[_transactionHash] = true;
}
function setRFQTransactionSeen(bytes32 _transactionHash) override external isPermitted(transactionSeenStorageId, msg.sender) {
require(!RFQStorage.getStorage().transactionSeen[_transactionHash], "PermanentStorage: transaction seen before");
RFQStorage.getStorage().transactionSeen[_transactionHash] = true;
}
function setRelayersValid(address[] calldata _relayers, bool[] calldata _isValids) override external isPermitted(relayerValidStorageId, msg.sender) {
require(_relayers.length == _isValids.length, "PermanentStorage: inputs length mismatch");
for (uint256 i = 0; i < _relayers.length; i++) {
AMMWrapperStorage.getStorage().relayerValid[_relayers[i]] = _isValids[i];
}
}
}
文件 43 的 57:PermanentStorageStub.sol
pragma solidity ^0.6.5;
import "../interfaces/IPermanentStorage.sol";
import "../utils/lib_storage/PSStorage.sol";
contract PermanentStorageStub is IPermanentStorage {
address public constant CURVE_COMPOUND_POOL = 0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56;
address public constant CURVE_USDT_POOL = 0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C;
address public constant CURVE_Y_POOL = 0x45F783CCE6B7FF23B2ab2D70e416cdb7D6055f51;
address public constant CURVE_3_POOL = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
address public constant CURVE_sUSD_POOL = 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD;
address public constant CURVE_BUSD_POOL = 0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27;
address public constant CURVE_renBTC_POOL = 0x93054188d876f558f4a66B2EF1d97d16eDf0895B;
address public constant CURVE_sBTC_POOL = 0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714;
address public constant CURVE_hBTC_POOL = 0x4CA9b3063Ec5866A4B82E437059D2C43d1be596F;
address public constant CURVE_sETH_POOL = 0xc5424B857f758E906013F3555Dad202e4bdB4567;
address private constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address private constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address private constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address private constant cDAI = 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643;
address private constant cUSDC = 0x39AA39c021dfbaE8faC545936693aC917d5E7563;
address private constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address private constant TUSD = 0x0000000000085d4780B73119b644AE5ecd22b376;
address private constant Y_POOL_yDAI = 0x16de59092dAE5CcF4A1E6439D611fd0653f0Bd01;
address private constant Y_POOL_yUSDC = 0xd6aD7a6750A7593E092a9B218d66C0A814a3436e;
address private constant Y_POOL_yUSDT = 0x83f798e925BcD4017Eb265844FDDAbb448f1707D;
address private constant Y_POOL_yTUSD = 0x73a052500105205d34Daf004eAb301916DA8190f;
address private constant sUSD = 0x57Ab1ec28D129707052df4dF418D58a2D46d5f51;
address private constant BUSD = 0x4Fabb145d64652a948d72533023f6E7A623C7C53;
address private constant BUSD_POOL_yDAI = 0xC2cB1040220768554cf699b0d863A3cd4324ce32;
address private constant BUSD_POOL_yUSDC = 0x26EA744E5B887E5205727f55dFBE8685e3b21951;
address private constant BUSD_POOL_yUSDT = 0xE6354ed5bC4b393a5Aad09f21c46E101e692d447;
address private constant BUSD_POOL_yBUSD = 0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE;
address private constant renBTC = 0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D;
address private constant wBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address private constant sBTC = 0xfE18be6b3Bd88A2D2A7f928d00292E7a9963CfC6;
address private constant hBTC = 0x0316EB71485b0Ab14103307bf65a021042c6d380;
address private constant sETH = 0x5e74C9036fb86BD7eCdcb084a0673EFc32eA31cb;
constructor() public {
PSStorage.getStorage().wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_COMPOUND_POOL][DAI] = 1;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_COMPOUND_POOL][USDC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_COMPOUND_POOL][cDAI] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_COMPOUND_POOL][cUSDC] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_COMPOUND_POOL] = true;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_USDT_POOL][DAI] = 1;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_USDT_POOL][USDC] = 2;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_USDT_POOL][USDT] = 3;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_USDT_POOL][cDAI] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_USDT_POOL][cUSDC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_USDT_POOL][USDT] = 3;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_USDT_POOL] = true;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_Y_POOL][DAI] = 1;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_Y_POOL][USDC] = 2;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_Y_POOL][USDT] = 3;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_Y_POOL][TUSD] = 4;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_Y_POOL][Y_POOL_yDAI] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_Y_POOL][Y_POOL_yUSDC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_Y_POOL][Y_POOL_yUSDT] = 3;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_Y_POOL][Y_POOL_yTUSD] = 4;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_Y_POOL] = true;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_3_POOL][DAI] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_3_POOL][USDC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_3_POOL][USDT] = 3;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_3_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sUSD_POOL][DAI] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sUSD_POOL][USDC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sUSD_POOL][USDT] = 3;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sUSD_POOL][sUSD] = 4;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_sUSD_POOL] = false;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_BUSD_POOL][DAI] = 1;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_BUSD_POOL][USDC] = 2;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_BUSD_POOL][USDT] = 3;
AMMWrapperStorage.getStorage().curveTokenIndexes[CURVE_BUSD_POOL][BUSD] = 4;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_BUSD_POOL][BUSD_POOL_yDAI] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_BUSD_POOL][BUSD_POOL_yUSDC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_BUSD_POOL][BUSD_POOL_yUSDT] = 3;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_BUSD_POOL][BUSD_POOL_yBUSD] = 4;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_BUSD_POOL] = true;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_renBTC_POOL][renBTC] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_renBTC_POOL][wBTC] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_renBTC_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sBTC_POOL][renBTC] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sBTC_POOL][wBTC] = 2;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sBTC_POOL][sBTC] = 3;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_sBTC_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_hBTC_POOL][hBTC] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_hBTC_POOL][wBTC] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_hBTC_POOL] = false;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sETH_POOL][ETH] = 1;
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[CURVE_sETH_POOL][sETH] = 2;
AMMWrapperStorage.getStorage().curveSupportGetDx[CURVE_sETH_POOL] = false;
}
function ammWrapperAddr() public view returns (address) {
return PSStorage.getStorage().ammWrapperAddr;
}
function pmmAddr() public view returns (address) {
return PSStorage.getStorage().pmmAddr;
}
function rfqAddr() public view returns (address) {
return PSStorage.getStorage().rfqAddr;
}
function wethAddr() override external view returns (address) {
return PSStorage.getStorage().wethAddr;
}
function getCurvePoolInfo(address _makerAddr, address _takerAssetAddr, address _makerAssetAddr) override external view returns (int128 takerAssetIndex, int128 makerAssetIndex, uint16 swapMethod, bool supportGetDx) {
int128 i = AMMWrapperStorage.getStorage().curveTokenIndexes[_makerAddr][_takerAssetAddr];
int128 j = AMMWrapperStorage.getStorage().curveTokenIndexes[_makerAddr][_makerAssetAddr];
supportGetDx = AMMWrapperStorage.getStorage().curveSupportGetDx[_makerAddr];
swapMethod = 0;
if (i != 0 && j != 0) {
takerAssetIndex = i;
makerAssetIndex = j;
swapMethod = 2;
} else {
int128 iWrapped = AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[_makerAddr][_takerAssetAddr];
int128 jWrapped = AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[_makerAddr][_makerAssetAddr];
if (iWrapped != 0 && jWrapped != 0) {
takerAssetIndex = iWrapped;
makerAssetIndex = jWrapped;
swapMethod = 1;
} else {
revert("PermanentStorage: invalid pair");
}
}
return (takerAssetIndex, makerAssetIndex, swapMethod, supportGetDx);
}
function isTransactionSeen(bytes32 _transactionHash) override external view returns (bool) {
return AMMWrapperStorage.getStorage().transactionSeen[_transactionHash];
}
function isAMMTransactionSeen(bytes32 _transactionHash) override external view returns (bool) {
return AMMWrapperStorage.getStorage().transactionSeen[_transactionHash];
}
function isRFQTransactionSeen(bytes32 _transactionHash) override external view returns (bool) {
return RFQStorage.getStorage().transactionSeen[_transactionHash];
}
function isRelayerValid(address _relayer) override external view returns (bool) {
return AMMWrapperStorage.getStorage().relayerValid[_relayer];
}
function upgradeAMMWrapper(address _newAMMWrapper) external {
PSStorage.getStorage().ammWrapperAddr = _newAMMWrapper;
}
function upgradePMM(address _newPMM) external {
PSStorage.getStorage().pmmAddr = _newPMM;
}
function upgradeRFQ(address _newRFQ) external {
PSStorage.getStorage().rfqAddr = _newRFQ;
}
function upgradeWETH(address _newWETH) external {
PSStorage.getStorage().wethAddr = _newWETH;
}
function setCurvePoolInfo(address _makerAddr, address[] calldata _underlyingCoins, address[] calldata _coins, bool _supportGetDx) override external {
int128 underlyingCoinsLength = int128(_underlyingCoins.length);
for (int128 i = 0 ; i < underlyingCoinsLength; i++) {
address assetAddr = _underlyingCoins[uint256(i)];
AMMWrapperStorage.getStorage().curveTokenIndexes[_makerAddr][assetAddr] = i + 1;
}
int128 coinsLength = int128(_coins.length);
for (int128 i = 0 ; i < coinsLength; i++) {
address assetAddr = _coins[uint256(i)];
AMMWrapperStorage.getStorage().curveWrappedTokenIndexes[_makerAddr][assetAddr] = i + 1;
}
AMMWrapperStorage.getStorage().curveSupportGetDx[_makerAddr] = _supportGetDx;
}
function setTransactionSeen(bytes32 _transactionHash) override external {
require(!AMMWrapperStorage.getStorage().transactionSeen[_transactionHash], "PermanentStorage: transaction seen before");
AMMWrapperStorage.getStorage().transactionSeen[_transactionHash] = true;
}
function setAMMTransactionSeen(bytes32 _transactionHash) override external {
require(!AMMWrapperStorage.getStorage().transactionSeen[_transactionHash], "PermanentStorage: transaction seen before");
AMMWrapperStorage.getStorage().transactionSeen[_transactionHash] = true;
}
function setRFQTransactionSeen(bytes32 _transactionHash) override external {
require(!RFQStorage.getStorage().transactionSeen[_transactionHash], "PermanentStorage: transaction seen before");
RFQStorage.getStorage().transactionSeen[_transactionHash] = true;
}
function setRelayersValid(address[] calldata _relayers, bool[] calldata _isValids) override external {
require(_relayers.length == _isValids.length, "PermanentStorage: inputs length mismatch");
for (uint256 i = 0; i < _relayers.length; i++) {
AMMWrapperStorage.getStorage().relayerValid[_relayers[i]] = _isValids[i];
}
}
}
文件 44 的 57:Proxy.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Proxy {
function _delegate(address implementation) internal {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
function _implementation() internal virtual view returns (address);
function _fallback() internal {
_beforeFallback();
_delegate(_implementation());
}
fallback () payable external {
_fallback();
}
receive () payable external {
_fallback();
}
function _beforeFallback() internal virtual {
}
}
文件 45 的 57:RFQ.sol
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "./interfaces/ISpender.sol";
import "./interfaces/IWeth.sol";
import "./interfaces/IRFQ.sol";
import "./interfaces/IPermanentStorage.sol";
import "./interfaces/IERC1271Wallet.sol";
import "./utils/RFQLibEIP712.sol";
contract RFQ is
ReentrancyGuard,
IRFQ,
RFQLibEIP712,
SignatureValidator
{
using SafeMath for uint256;
using SafeERC20 for IERC20;
using Address for address;
string public constant version = "5.2.0";
uint256 private constant MAX_UINT = 2**256 - 1;
string public constant SOURCE = "RFQ v1";
uint256 private constant BPS_MAX = 10000;
address public immutable userProxy;
IPermanentStorage public immutable permStorage;
IWETH public immutable weth;
address public operator;
ISpender public spender;
struct GroupedVars {
bytes32 orderHash;
bytes32 transactionHash;
}
event TransferOwnership(address newOperator);
event UpgradeSpender(address newSpender);
event AllowTransfer(address spender);
event DisallowTransfer(address spender);
event DepositETH(uint256 ethBalance);
event FillOrder(
string source,
bytes32 indexed transactionHash,
bytes32 indexed orderHash,
address indexed userAddr,
address takerAssetAddr,
uint256 takerAssetAmount,
address makerAddr,
address makerAssetAddr,
uint256 makerAssetAmount,
address receiverAddr,
uint256 settleAmount,
uint16 feeFactor
);
receive() external payable {}
modifier onlyOperator {
require(operator == msg.sender, "RFQ: not operator");
_;
}
modifier onlyUserProxy() {
require(address(userProxy) == msg.sender, "RFQ: not the UserProxy contract");
_;
}
function transferOwnership(address _newOperator) external onlyOperator {
require(_newOperator != address(0), "RFQ: operator can not be zero address");
operator = _newOperator;
emit TransferOwnership(_newOperator);
}
constructor (
address _operator,
address _userProxy,
ISpender _spender,
IPermanentStorage _permStorage,
IWETH _weth
) public {
operator = _operator;
userProxy = _userProxy;
spender = _spender;
permStorage = _permStorage;
weth = _weth;
}
function upgradeSpender(address _newSpender) external onlyOperator {
require(_newSpender != address(0), "RFQ: spender can not be zero address");
spender = ISpender(_newSpender);
emit UpgradeSpender(_newSpender);
}
function setAllowance(address[] calldata _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, MAX_UINT);
emit AllowTransfer(_spender);
}
}
function closeAllowance(address[] calldata _tokenList, address _spender) override external onlyOperator {
for (uint256 i = 0 ; i < _tokenList.length; i++) {
IERC20(_tokenList[i]).safeApprove(_spender, 0);
emit DisallowTransfer(_spender);
}
}
function depositETH() external onlyOperator {
uint256 balance = address(this).balance;
if (balance > 0) {
weth.deposit{value: balance}();
emit DepositETH(balance);
}
}
function fill(
RFQLibEIP712.Order memory _order,
bytes memory _mmSignature,
bytes memory _userSignature
)
override
payable
external
nonReentrant
onlyUserProxy
returns (uint256)
{
require(_order.deadline >= block.timestamp, "RFQ: expired order");
require(_order.feeFactor < BPS_MAX, "RFQ: invalid fee factor");
GroupedVars memory vars;
vars.orderHash = _getOrderHash(_order);
require(
isValidSignature(
_order.makerAddr,
_getOrderSignDigestFromHash(vars.orderHash),
bytes(""),
_mmSignature
),
"RFQ: invalid MM signature"
);
vars.transactionHash = _getTransactionHash(_order);
require(
isValidSignature(
_order.takerAddr,
_getTransactionSignDigestFromHash(vars.transactionHash),
bytes(""),
_userSignature
),
"RFQ: invalid user signature"
);
permStorage.setRFQTransactionSeen(vars.transactionHash);
if (address(weth) == _order.takerAssetAddr) {
require(
msg.value == _order.takerAssetAmount,
"RFQ: insufficient ETH"
);
weth.deposit{value: msg.value}();
} else {
spender.spendFromUser(_order.takerAddr, _order.takerAssetAddr, _order.takerAssetAmount);
}
spender.spendFromUser(_order.makerAddr, _order.makerAssetAddr, _order.makerAssetAmount);
return _settle(_order, vars);
}
function _settle(
RFQLibEIP712.Order memory _order,
GroupedVars memory _vars
) internal returns(uint256) {
IERC20(_order.takerAssetAddr).safeTransfer(_order.makerAddr, _order.takerAssetAmount);
uint256 settleAmount = _order.makerAssetAmount;
if (_order.feeFactor > 0) {
settleAmount = settleAmount.mul((BPS_MAX).sub(_order.feeFactor)).div(BPS_MAX);
}
if (_order.makerAssetAddr == address(weth)){
weth.withdraw(settleAmount);
payable(_order.receiverAddr).transfer(settleAmount);
} else {
IERC20(_order.makerAssetAddr).safeTransfer(_order.receiverAddr, settleAmount);
}
emit FillOrder(
SOURCE,
_vars.transactionHash,
_vars.orderHash,
_order.takerAddr,
_order.takerAssetAddr,
_order.takerAssetAmount,
_order.makerAddr,
_order.makerAssetAddr,
_order.makerAssetAmount,
_order.receiverAddr,
settleAmount,
uint16(_order.feeFactor)
);
return settleAmount;
}
}
文件 46 的 57:RFQLibEIP712.sol
pragma solidity ^0.6.0;
import "./BaseLibEIP712.sol";
import "./SignatureValidator.sol";
contract RFQLibEIP712 is BaseLibEIP712 {
struct Order {
address takerAddr;
address makerAddr;
address takerAssetAddr;
address makerAssetAddr;
uint256 takerAssetAmount;
uint256 makerAssetAmount;
address receiverAddr;
uint256 salt;
uint256 deadline;
uint256 feeFactor;
}
bytes32 public constant ORDER_TYPEHASH = keccak256(
abi.encodePacked(
"Order(",
"address takerAddr,",
"address makerAddr,",
"address takerAssetAddr,",
"address makerAssetAddr,",
"uint256 takerAssetAmount,",
"uint256 makerAssetAmount,",
"uint256 salt,",
"uint256 deadline,",
"uint256 feeFactor",
")"
)
);
function _getOrderHash(Order memory _order) internal pure returns (bytes32 orderHash) {
orderHash = keccak256(
abi.encode(
ORDER_TYPEHASH,
_order.takerAddr,
_order.makerAddr,
_order.takerAssetAddr,
_order.makerAssetAddr,
_order.takerAssetAmount,
_order.makerAssetAmount,
_order.salt,
_order.deadline,
_order.feeFactor
)
);
}
function _getOrderSignDigest(Order memory _order) internal view returns (bytes32 orderSignDigest) {
orderSignDigest = keccak256(
abi.encodePacked(
EIP191_HEADER,
EIP712_DOMAIN_SEPARATOR,
_getOrderHash(_order)
)
);
}
function _getOrderSignDigestFromHash(bytes32 _orderHash) internal view returns (bytes32 orderSignDigest) {
orderSignDigest = keccak256(
abi.encodePacked(
EIP191_HEADER,
EIP712_DOMAIN_SEPARATOR,
_orderHash
)
);
}
bytes32 public constant FILL_WITH_PERMIT_TYPEHASH = keccak256(
abi.encodePacked(
"fillWithPermit(",
"address makerAddr,",
"address takerAssetAddr,",
"address makerAssetAddr,",
"uint256 takerAssetAmount,",
"uint256 makerAssetAmount,",
"address takerAddr,",
"address receiverAddr,",
"uint256 salt,",
"uint256 deadline,",
"uint256 feeFactor",
")"
)
);
function _getTransactionHash(Order memory _order) internal pure returns(bytes32 transactionHash) {
transactionHash = keccak256(
abi.encode(
FILL_WITH_PERMIT_TYPEHASH,
_order.makerAddr,
_order.takerAssetAddr,
_order.makerAssetAddr,
_order.takerAssetAmount,
_order.makerAssetAmount,
_order.takerAddr,
_order.receiverAddr,
_order.salt,
_order.deadline,
_order.feeFactor
)
);
}
function _getTransactionSignDigest(Order memory _order) internal view returns (bytes32 transactionSignDigest) {
transactionSignDigest = keccak256(
abi.encodePacked(
EIP191_HEADER,
EIP712_DOMAIN_SEPARATOR,
_getTransactionHash(_order)
)
);
}
function _getTransactionSignDigestFromHash(bytes32 _txHash) internal view returns (bytes32 transactionSignDigest) {
transactionSignDigest = keccak256(
abi.encodePacked(
EIP191_HEADER,
EIP712_DOMAIN_SEPARATOR,
_txHash
)
);
}
}
文件 47 的 57:ReentrancyGuard.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 48 的 57:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
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 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 49 的 57:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 50 的 57:SignatureValidator.sol
pragma solidity ^0.6.0;
import "../interfaces/IERC1271Wallet.sol";
import "./LibBytes.sol";
interface IWallet {
function isValidSignature(
bytes32 hash,
bytes memory signature
)
external
view
returns (bool isValid);
}
contract SignatureValidator {
using LibBytes for bytes;
bytes4 constant internal ERC1271_MAGICVALUE = 0x20c13b0b;
bytes4 constant internal ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e;
bytes4 constant internal ERC1271_FALLBACK_MAGICVALUE_BYTES32 = 0xb0671381;
enum SignatureType {
Illegal,
Invalid,
EIP712,
EthSign,
WalletBytes,
WalletBytes32,
Wallet,
NSignatureTypes
}
function isValidSignature(
address _signerAddress,
bytes32 _hash,
bytes memory _data,
bytes memory _sig
)
public
view
returns (bool isValid)
{
require(
_sig.length > 0,
"SignatureValidator#isValidSignature: length greater than 0 required"
);
require(
_signerAddress != address(0x0),
"SignatureValidator#isValidSignature: invalid signer"
);
uint8 signatureTypeRaw = uint8(_sig.popLastByte());
require(
signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
"SignatureValidator#isValidSignature: unsupported signature"
);
SignatureType signatureType = SignatureType(signatureTypeRaw);
uint8 v;
bytes32 r;
bytes32 s;
address recovered;
if (signatureType == SignatureType.Illegal) {
revert("SignatureValidator#isValidSignature: illegal signature");
} else if (signatureType == SignatureType.EIP712) {
require(
_sig.length == 97,
"SignatureValidator#isValidSignature: length 97 required"
);
r = _sig.readBytes32(0);
s = _sig.readBytes32(32);
v = uint8(_sig[64]);
recovered = ecrecover(_hash, v, r, s);
isValid = _signerAddress == recovered;
return isValid;
} else if (signatureType == SignatureType.EthSign) {
require(
_sig.length == 97,
"SignatureValidator#isValidSignature: length 97 required"
);
r = _sig.readBytes32(0);
s = _sig.readBytes32(32);
v = uint8(_sig[64]);
recovered = ecrecover(
keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)),
v,
r,
s
);
isValid = _signerAddress == recovered;
return isValid;
} else if (signatureType == SignatureType.WalletBytes) {
isValid = ERC1271_MAGICVALUE == IERC1271Wallet(_signerAddress).isValidSignature(_data, _sig);
return isValid;
} else if (signatureType == SignatureType.WalletBytes32) {
isValid = ERC1271_MAGICVALUE_BYTES32 == IERC1271Wallet(_signerAddress).isValidSignature(_hash, _sig);
return isValid;
} else if (signatureType == SignatureType.Wallet) {
isValid = isValidWalletSignature(
_hash,
_signerAddress,
_sig
);
return isValid;
}
revert("SignatureValidator#isValidSignature: unsupported signature");
}
function isValidWalletSignature(
bytes32 hash,
address walletAddress,
bytes memory signature
)
internal
view
returns (bool isValid)
{
bytes memory _calldata = abi.encodeWithSelector(
IWallet(walletAddress).isValidSignature.selector,
hash,
signature
);
bytes32 magic_salt = bytes32(bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)")));
assembly {
if iszero(extcodesize(walletAddress)) {
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
let cdStart := add(_calldata, 32)
let success := staticcall(
gas(),
walletAddress,
cdStart,
mload(_calldata),
cdStart,
32
)
if iszero(eq(returndatasize(), 32)) {
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
switch success
case 0 {
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
case 1 {
isValid := eq(
and(mload(cdStart), 0xffffffff00000000000000000000000000000000000000000000000000000000),
and(magic_salt, 0xffffffff00000000000000000000000000000000000000000000000000000000)
)
}
}
return isValid;
}
}
文件 51 的 57:Spender.sol
pragma solidity ^0.6.5;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IAllowanceTarget.sol";
contract Spender {
using SafeMath for uint256;
address private constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address private constant ZERO_ADDRESS = address(0);
uint256 constant private TIME_LOCK_DURATION = 1 days;
address public operator;
address public pendingOperator;
address public allowanceTarget;
mapping(address => bool) private authorized;
mapping(address => bool) private tokenBlacklist;
uint256 public numPendingAuthorized;
mapping(uint256 => address) public pendingAuthorized;
uint256 public timelockExpirationTime;
uint256 public contractDeployedTime;
bool public timelockActivated;
mapping(address => bool) public consumeGasERC20Tokens;
event TimeLockActivated(uint256 activatedTimeStamp);
event TransferOwnership(address newOperator);
event SetAllowanceTarget(address allowanceTarget);
event SetNewSpender(address newSpender);
event SetConsumeGasERC20Token(address token);
event TearDownAllowanceTarget(uint256 tearDownTimeStamp);
event BlackListToken(address token, bool isBlacklisted);
event AuthorizeSpender(address spender, bool isAuthorized);
modifier onlyOperator() {
require(operator == msg.sender, "Spender: not the operator");
_;
}
modifier onlyAuthorized() {
require(authorized[msg.sender], "Spender: not authorized");
_;
}
function setNewOperator(address _newOperator) external onlyOperator {
require(_newOperator != address(0), "Spender: operator can not be zero address");
pendingOperator = _newOperator;
}
function acceptAsOperator() external {
require(pendingOperator == msg.sender, "Spender: only nominated one can accept as new operator");
operator = pendingOperator;
pendingOperator = address(0);
emit TransferOwnership(pendingOperator);
}
function activateTimelock() external {
bool canActivate = block.timestamp.sub(contractDeployedTime) > 1 days;
require(canActivate && ! timelockActivated, "Spender: can not activate timelock yet or has been activated");
timelockActivated = true;
emit TimeLockActivated(block.timestamp);
}
constructor(address _operator, address[] memory _consumeGasERC20Tokens) public {
require(_operator != address(0), "Spender: _operator should not be 0");
operator = _operator;
timelockActivated = false;
contractDeployedTime = block.timestamp;
for (uint256 i = 0; i < _consumeGasERC20Tokens.length; i++) {
consumeGasERC20Tokens[_consumeGasERC20Tokens[i]] = true;
}
}
function setAllowanceTarget(address _allowanceTarget) external onlyOperator {
require(allowanceTarget == address(0), "Spender: can not reset allowance target");
allowanceTarget = _allowanceTarget;
emit SetAllowanceTarget(_allowanceTarget);
}
function setNewSpender(address _newSpender) external onlyOperator {
IAllowanceTarget(allowanceTarget).setSpenderWithTimelock(_newSpender);
emit SetNewSpender(_newSpender);
}
function teardownAllowanceTarget() external onlyOperator {
IAllowanceTarget(allowanceTarget).teardown();
emit TearDownAllowanceTarget(block.timestamp);
}
function isBlacklisted(address _tokenAddr) external view returns (bool) {
return tokenBlacklist[_tokenAddr];
}
function blacklist(address[] calldata _tokenAddrs, bool[] calldata _isBlacklisted) external onlyOperator {
require(_tokenAddrs.length == _isBlacklisted.length, "Spender: length mismatch");
for (uint256 i = 0; i < _tokenAddrs.length; i++) {
tokenBlacklist[_tokenAddrs[i]] = _isBlacklisted[i];
emit BlackListToken(_tokenAddrs[i], _isBlacklisted[i]);
}
}
function isAuthorized(address _caller) external view returns (bool) {
return authorized[_caller];
}
function authorize(address[] calldata _pendingAuthorized) external onlyOperator {
require(_pendingAuthorized.length > 0, "Spender: authorize list is empty");
require(numPendingAuthorized == 0 && timelockExpirationTime == 0, "Spender: an authorize current in progress");
if (timelockActivated) {
numPendingAuthorized = _pendingAuthorized.length;
for (uint256 i = 0; i < _pendingAuthorized.length; i++) {
require(_pendingAuthorized[i] != address(0), "Spender: can not authorize zero address");
pendingAuthorized[i] = _pendingAuthorized[i];
}
timelockExpirationTime = now + TIME_LOCK_DURATION;
} else {
for (uint256 i = 0; i < _pendingAuthorized.length; i++) {
require(_pendingAuthorized[i] != address(0), "Spender: can not authorize zero address");
authorized[_pendingAuthorized[i]] = true;
emit AuthorizeSpender(_pendingAuthorized[i], true);
}
}
}
function completeAuthorize() external {
require(timelockExpirationTime != 0, "Spender: no pending authorize");
require(now >= timelockExpirationTime, "Spender: time lock not expired yet");
for (uint256 i = 0; i < numPendingAuthorized; i++) {
authorized[pendingAuthorized[i]] = true;
emit AuthorizeSpender(pendingAuthorized[i], true);
delete pendingAuthorized[i];
}
timelockExpirationTime = 0;
numPendingAuthorized = 0;
}
function deauthorize(address[] calldata _deauthorized) external onlyOperator {
for (uint256 i = 0; i < _deauthorized.length; i++) {
authorized[_deauthorized[i]] = false;
emit AuthorizeSpender(_deauthorized[i], false);
}
}
function setConsumeGasERC20Tokens(address[] memory _consumeGasERC20Tokens) external onlyOperator {
for (uint256 i = 0; i < _consumeGasERC20Tokens.length; i++) {
consumeGasERC20Tokens[_consumeGasERC20Tokens[i]] = true;
emit SetConsumeGasERC20Token(_consumeGasERC20Tokens[i]);
}
}
function spendFromUser(address _user, address _tokenAddr, uint256 _amount) external onlyAuthorized {
require(! tokenBlacklist[_tokenAddr], "Spender: token is blacklisted");
uint256 gasStipend;
if(consumeGasERC20Tokens[_tokenAddr]) gasStipend = 80000;
else gasStipend = gasleft();
if (_tokenAddr != ETH_ADDRESS && _tokenAddr != ZERO_ADDRESS) {
uint256 balanceBefore = IERC20(_tokenAddr).balanceOf(msg.sender);
(bool callSucceed, bytes memory returndata) = address(allowanceTarget).call{gas: gasStipend}(
abi.encodeWithSelector(
IAllowanceTarget.executeCall.selector,
_tokenAddr,
abi.encodeWithSelector(
IERC20.transferFrom.selector,
_user,
msg.sender,
_amount
)
)
);
require(callSucceed, "Spender: ERC20 transferFrom failed");
bytes memory decodedReturnData = abi.decode(returndata, (bytes));
if (decodedReturnData.length > 0) {
require(abi.decode(decodedReturnData, (bool)), "Spender: ERC20 transferFrom failed");
}
uint256 balanceAfter = IERC20(_tokenAddr).balanceOf(msg.sender);
require(balanceAfter.sub(balanceBefore) == _amount, "Spender: ERC20 transferFrom amount mismatch");
}
}
function spendFromUserTo(address _user, address _tokenAddr, address _receiver, uint256 _amount) external onlyAuthorized {
require(! tokenBlacklist[_tokenAddr], "Spender: token is blacklisted");
uint256 gasStipend;
if(consumeGasERC20Tokens[_tokenAddr]) gasStipend = 80000;
else gasStipend = gasleft();
if (_tokenAddr != ETH_ADDRESS && _tokenAddr != ZERO_ADDRESS) {
uint256 balanceBefore = IERC20(_tokenAddr).balanceOf(msg.sender);
(bool callSucceed, bytes memory returndata) = address(allowanceTarget).call{gas: gasStipend}(
abi.encodeWithSelector(
IAllowanceTarget.executeCall.selector,
_tokenAddr,
abi.encodeWithSelector(
IERC20.transferFrom.selector,
_user,
_receiver,
_amount
)
)
);
require(callSucceed, "Spender: ERC20 transferFrom failed");
bytes memory decodedReturnData = abi.decode(returndata, (bytes));
if (decodedReturnData.length > 0) {
require(abi.decode(decodedReturnData, (bool)), "Spender: ERC20 transferFrom failed");
}
uint256 balanceAfter = IERC20(_tokenAddr).balanceOf(msg.sender);
require(balanceAfter.sub(balanceBefore) == _amount, "Spender: ERC20 transferFrom amount mismatch");
}
}
}
文件 52 的 57:SpenderSimulation.sol
pragma solidity ^0.6.0;
import "./interfaces/IHasBlackListERC20Token.sol";
import "./interfaces/ISpender.sol";
contract SpenderSimulation {
ISpender public immutable spender;
mapping(address => bool) public hasBlackListERC20Tokens;
modifier checkBlackList(address _tokenAddr, address _user) {
if (hasBlackListERC20Tokens[_tokenAddr]) {
IHasBlackListERC20Token hasBlackListERC20Token = IHasBlackListERC20Token(_tokenAddr);
require(!hasBlackListERC20Token.isBlackListed(_user), "SpenderSimulation: user in token's blacklist");
}
_;
}
constructor (ISpender _spender, address[] memory _hasBlackListERC20Tokens) public {
spender = _spender;
for (uint256 i = 0; i < _hasBlackListERC20Tokens.length; i++) {
hasBlackListERC20Tokens[_hasBlackListERC20Tokens[i]] = true;
}
}
function simulate(address _user, address _tokenAddr, uint256 _amount) external checkBlackList(_tokenAddr, _user) {
spender.spendFromUser(_user, _tokenAddr, _amount);
revert("SpenderSimulation: transfer simulation success");
}
}
文件 53 的 57:Tokenlon.sol
pragma solidity ^0.6.0;
import "./upgrade_proxy/TransparentUpgradeableProxy.sol";
contract Tokenlon is TransparentUpgradeableProxy {
constructor(address _logic, address _admin, bytes memory _data) public payable TransparentUpgradeableProxy(_logic, _admin, _data) {}
}
文件 54 的 57:TransparentUpgradeableProxy.sol
pragma solidity >=0.6.0 <0.8.0;
import "./UpgradeableProxy.sol";
contract TransparentUpgradeableProxy is UpgradeableProxy {
constructor(address _logic, address _admin, bytes memory _data) public payable UpgradeableProxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_setAdmin(_admin);
}
event AdminChanged(address previousAdmin, address newAdmin);
bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
function admin() external ifAdmin returns (address) {
return _admin();
}
function implementation() external ifAdmin returns (address) {
return _implementation();
}
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), "TransparentUpgradeableProxy: new admin is the zero address");
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeTo(newImplementation);
(bool success,) = newImplementation.delegatecall(data);
require(success);
}
function _admin() internal view returns (address adm) {
bytes32 slot = _ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
function _setAdmin(address newAdmin) private {
bytes32 slot = _ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
function _beforeFallback() internal override virtual {
require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}
文件 55 的 57:UniswapV3PathLib.sol
pragma solidity >=0.6.0;
library BytesLib {
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40)
let lengthmod := and(_length, 31)
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_start + 20 >= _start, "toAddress_overflow");
require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
require(_start + 3 >= _start, "toUint24_overflow");
require(_bytes.length >= _start + 3, "toUint24_outOfBounds");
uint24 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x3), _start))
}
return tempUint;
}
}
library Path {
using BytesLib for bytes;
uint256 private constant ADDR_SIZE = 20;
uint256 private constant FEE_SIZE = 3;
uint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE;
uint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE;
uint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET;
function hasMultiplePools(bytes memory path) internal pure returns (bool) {
return path.length >= MULTIPLE_POOLS_MIN_LENGTH;
}
function decodeFirstPool(bytes memory path)
internal
pure
returns (
address tokenA,
address tokenB,
uint24 fee
)
{
tokenA = path.toAddress(0);
fee = path.toUint24(ADDR_SIZE);
tokenB = path.toAddress(NEXT_OFFSET);
}
function skipToken(bytes memory path) internal pure returns (bytes memory) {
return path.slice(NEXT_OFFSET, path.length - NEXT_OFFSET);
}
}
文件 56 的 57:UpgradeableProxy.sol
pragma solidity >=0.6.0 <0.8.0;
import "@openzeppelin/contracts/utils/Address.sol";
import "./Proxy.sol";
contract UpgradeableProxy is Proxy {
constructor(address _logic, bytes memory _data) public payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_setImplementation(_logic);
if(_data.length > 0) {
(bool success,) = _logic.delegatecall(_data);
require(success);
}
}
event Upgraded(address indexed implementation);
bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
function _implementation() internal override view returns (address impl) {
bytes32 slot = _IMPLEMENTATION_SLOT;
assembly {
impl := sload(slot)
}
}
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract");
bytes32 slot = _IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
}
文件 57 的 57:UserProxyStub.sol
pragma solidity ^0.6.5;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../interfaces/IAMM.sol";
contract UserProxyStub {
using SafeERC20 for IERC20;
uint256 private constant MAX_UINT = 2**256 - 1;
address private constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address private constant ZERO_ADDRESS = address(0);
address public operator;
address public weth;
address public ammWrapperAddr;
address public pmmAddr;
address public rfqAddr;
receive() external payable {
}
modifier onlyOperator() {
require(operator == msg.sender, "UserProxyStub: not the operator");
_;
}
constructor(address _weth) public {
operator = msg.sender;
weth = _weth;
}
function upgradePMM(address _pmmAddr) external onlyOperator {
pmmAddr = _pmmAddr;
}
function upgradeAMMWrapper(address _ammWrapperAddr) external onlyOperator {
ammWrapperAddr = _ammWrapperAddr;
}
function upgradeRFQ(address _rfqAddr) external onlyOperator {
rfqAddr = _rfqAddr;
}
function toAMM(bytes calldata _payload) external payable {
(bool callSucceed,) = ammWrapperAddr.call{value: msg.value}(_payload);
if (callSucceed == false) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
}
function toPMM(bytes calldata _payload) external payable {
(bool callSucceed,) = pmmAddr.call{value: msg.value}(_payload);
if (callSucceed == false) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
}
function toRFQ(bytes calldata _payload) external payable {
(bool callSucceed,) = rfqAddr.call{value: msg.value}(_payload);
if (callSucceed == false) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
}
}
{
"compilationTarget": {
"contracts/AMMWrapperWithPath.sol": "AMMWrapperWithPath"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint256","name":"_subsidyFactor","type":"uint256"},{"internalType":"address","name":"_userProxy","type":"address"},{"internalType":"contract ISpender","name":"_spender","type":"address"},{"internalType":"contract IPermanentStorage","name":"_permStorage","type":"address"},{"internalType":"contract IWETH","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"spender","type":"address"}],"name":"AllowTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ethBalance","type":"uint256"}],"name":"DepositETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"spender","type":"address"}],"name":"DisallowTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newSubisdyFactor","type":"uint256"}],"name":"SetSubsidyFactor","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"string","name":"source","type":"string"},{"internalType":"bytes32","name":"transactionHash","type":"bytes32"},{"internalType":"uint256","name":"settleAmount","type":"uint256"},{"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"internalType":"uint16","name":"feeFactor","type":"uint16"},{"internalType":"uint16","name":"subsidyFactor","type":"uint16"}],"indexed":false,"internalType":"struct AMMWrapper.TxMetaData","name":"","type":"tuple"},{"components":[{"internalType":"address","name":"makerAddr","type":"address"},{"internalType":"address","name":"takerAssetAddr","type":"address"},{"internalType":"address","name":"makerAssetAddr","type":"address"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"address","name":"userAddr","type":"address"},{"internalType":"address payable","name":"receiverAddr","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"indexed":false,"internalType":"struct AMMLibEIP712.Order","name":"order","type":"tuple"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"source","type":"string"},{"indexed":true,"internalType":"bytes32","name":"transactionHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"userAddr","type":"address"},{"indexed":false,"internalType":"address","name":"takerAssetAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"makerAddr","type":"address"},{"indexed":false,"internalType":"address","name":"makerAssetAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiverAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"settleAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"feeFactor","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"subsidyFactor","type":"uint16"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOperator","type":"address"}],"name":"TransferOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newSpender","type":"address"}],"name":"UpgradeSpender","type":"event"},{"inputs":[],"name":"EIP191_HEADER","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUSHISWAP_ROUTER_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRADE_WITH_PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_V2_ROUTER_02_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_V3_ROUTER_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokenList","type":"address[]"},{"internalType":"address","name":"_spender","type":"address"}],"name":"closeAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signerAddress","type":"address"},{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_sig","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permStorage","outputs":[{"internalType":"contract IPermanentStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokenList","type":"address[]"},{"internalType":"address","name":"_spender","type":"address"}],"name":"setAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_subsidyFactor","type":"uint256"}],"name":"setSubsidyFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spender","outputs":[{"internalType":"contract ISpender","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"subsidyFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_makerAddr","type":"address"},{"internalType":"address","name":"_takerAssetAddr","type":"address"},{"internalType":"address","name":"_makerAssetAddr","type":"address"},{"internalType":"uint256","name":"_takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"_makerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"_feeFactor","type":"uint256"},{"internalType":"address","name":"_userAddr","type":"address"},{"internalType":"address payable","name":"_receiverAddr","type":"address"},{"internalType":"uint256","name":"_salt","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_sig","type":"bytes"}],"name":"trade","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"makerAddr","type":"address"},{"internalType":"address","name":"takerAssetAddr","type":"address"},{"internalType":"address","name":"makerAssetAddr","type":"address"},{"internalType":"uint256","name":"takerAssetAmount","type":"uint256"},{"internalType":"uint256","name":"makerAssetAmount","type":"uint256"},{"internalType":"address","name":"userAddr","type":"address"},{"internalType":"address payable","name":"receiverAddr","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct AMMLibEIP712.Order","name":"_order","type":"tuple"},{"internalType":"uint256","name":"_feeFactor","type":"uint256"},{"internalType":"bytes","name":"_sig","type":"bytes"},{"internalType":"bytes","name":"_makerSpecificData","type":"bytes"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"trade","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOperator","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newSpender","type":"address"}],"name":"upgradeSpender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"userProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]