文件 1 的 23:Address.sol
pragma solidity ^0.7.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);
}
}
}
}
文件 2 的 23:Asset.sol
pragma solidity ^0.7.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { LibConstant } from "./LibConstant.sol";
library Asset {
using SafeERC20 for IERC20;
function isETH(address addr) internal pure returns (bool) {
return (addr == LibConstant.ETH_ADDRESS || addr == LibConstant.ZERO_ADDRESS);
}
function transferTo(
address asset,
address payable to,
uint256 amount
) internal {
if (to == address(this)) {
return;
}
if (isETH(asset)) {
require(address(this).balance >= amount, "insufficient balance");
(bool success, ) = to.call{ value: amount }("");
require(success, "unable to send ETH");
} else {
IERC20(asset).safeTransfer(to, amount);
}
}
}
文件 3 的 23:BaseLibEIP712.sol
pragma solidity ^0.7.6;
abstract 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 originalEIP712DomainSeparator;
uint256 public immutable originalChainId;
constructor() {
originalEIP712DomainSeparator = _buildDomainSeparator();
originalChainId = getChainID();
}
function getChainID() internal pure returns (uint256) {
uint256 chainId;
assembly {
chainId := chainid()
}
return chainId;
}
function _buildDomainSeparator() private view returns (bytes32) {
return
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 _getDomainSeparator() private view returns (bytes32) {
if (getChainID() == originalChainId) {
return originalEIP712DomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function getEIP712Hash(bytes32 structHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked(EIP191_HEADER, _getDomainSeparator(), structHash));
}
function EIP712_DOMAIN_SEPARATOR() external view returns (bytes32) {
return _getDomainSeparator();
}
}
文件 4 的 23:IERC1271Wallet.sol
pragma solidity >=0.7.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);
}
文件 5 的 23:IERC20.sol
pragma solidity ^0.7.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);
}
文件 6 的 23:IERC20Permit.sol
pragma solidity >=0.7.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 7 的 23:IPermanentStorage.sol
pragma solidity >=0.7.0;
interface IPermanentStorage {
event OperatorNominated(address indexed newOperator);
event OperatorChanged(address indexed oldOperator, address indexed newOperator);
event SetPermission(bytes32 storageId, address role, bool enabled);
event UpgradeAMMWrapper(address newAMMWrapper);
event UpgradePMM(address newPMM);
event UpgradeRFQ(address newRFQ);
event UpgradeRFQv2(address newRFQv2);
event UpgradeLimitOrder(address newLimitOrder);
event UpgradeWETH(address newWETH);
event SetCurvePoolInfo(address makerAddr, address[] underlyingCoins, address[] coins, bool supportGetD);
event SetRelayerValid(address relayer, bool valid);
function hasPermission(bytes32 _storageId, address _role) external view returns (bool);
function ammWrapperAddr() external view returns (address);
function pmmAddr() external view returns (address);
function rfqAddr() external view returns (address);
function rfqv2Addr() external view returns (address);
function limitOrderAddr() external view returns (address);
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 isAMMTransactionSeen(bytes32 _transactionHash) external view returns (bool);
function isRFQTransactionSeen(bytes32 _transactionHash) external view returns (bool);
function isRFQOfferFilled(bytes32 _offerHash) external view returns (bool);
function isLimitOrderTransactionSeen(bytes32 _transactionHash) external view returns (bool);
function isLimitOrderAllowFillSeen(bytes32 _allowFillHash) external view returns (bool);
function isRelayerValid(address _relayer) external view returns (bool);
function setAMMTransactionSeen(bytes32 _transactionHash) external;
function setRFQTransactionSeen(bytes32 _transactionHash) external;
function setRFQOfferFilled(bytes32 _offerHash) external;
function setLimitOrderTransactionSeen(bytes32 _transactionHash) external;
function setLimitOrderAllowFillSeen(bytes32 _allowFillHash) external;
function setRelayersValid(address[] memory _relayers, bool[] memory _isValids) external;
}
文件 8 的 23:IRFQv2.sol
pragma solidity >=0.7.0;
pragma abicoder v2;
import { RFQOrder } from "../utils/RFQOrder.sol";
interface IRFQv2 {
event FilledRFQ(
bytes32 indexed offerHash,
address indexed user,
address indexed maker,
address takerToken,
uint256 takerTokenAmount,
address makerToken,
uint256 makerTokenAmount,
address recipient,
uint256 settleAmount,
uint256 feeFactor
);
function fillRFQ(
RFQOrder calldata rfqOrder,
bytes calldata makerSignature,
bytes calldata makerTokenPermit,
bytes calldata takerSignature,
bytes calldata takerTokenPermit
) external payable;
}
文件 9 的 23:ISpender.sol
pragma solidity >=0.7.0;
interface ISpender {
event TimeLockActivated(uint256 activatedTimeStamp);
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);
function spendFromUser(
address _user,
address _tokenAddr,
uint256 _amount
) external;
}
文件 10 的 23:IStrategyBase.sol
pragma solidity >=0.7.0;
interface IStrategyBase {
event UpgradeSpender(address newSpender);
event AllowTransfer(address indexed spender, address token);
event DisallowTransfer(address indexed spender, address token);
event DepositETH(uint256 amount);
function upgradeSpender(address _newSpender) external;
function setAllowance(address[] calldata _tokenList, address _spender) external;
function closeAllowance(address[] calldata _tokenList, address _spender) external;
function depositETH() external;
}
文件 11 的 23:IUniswapPermit2.sol
pragma solidity >=0.7.0;
pragma abicoder v2;
interface IUniswapPermit2 {
struct PermitDetails {
address token;
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct PermitSingle {
PermitDetails details;
address spender;
uint256 sigDeadline;
}
function DOMAIN_SEPARATOR() external view returns (bytes32);
function allowance(
address user,
address token,
address spender
)
external
view
returns (
uint160 amount,
uint48 expiration,
uint48 nonce
);
function permit(
address owner,
PermitSingle memory permitSingle,
bytes calldata signature
) external;
function transferFrom(
address from,
address to,
uint160 amount,
address token
) external;
function approve(
address token,
address spender,
uint160 amount,
uint48 expiration
) external;
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
struct SignatureTransferDetails {
address to;
uint256 requestedAmount;
}
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
}
文件 12 的 23:IWETH.sol
pragma solidity >=0.7.0;
interface IWETH {
function balanceOf(address account) external view returns (uint256);
function deposit() external payable;
function withdraw(uint256 amount) external;
function transfer(address dst, uint256 wad) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
}
文件 13 的 23:LibBytes.sol
pragma solidity ^0.7.6;
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;
}
}
文件 14 的 23:LibConstant.sol
pragma solidity ^0.7.6;
library LibConstant {
int256 internal constant MAX_INT = 2**255 - 1;
uint256 internal constant MAX_UINT = 2**256 - 1;
uint16 internal constant BPS_MAX = 10000;
address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant ZERO_ADDRESS = address(0);
}
文件 15 的 23:Offer.sol
pragma solidity ^0.7.6;
string constant OFFER_TYPESTRING = "Offer(address taker,address maker,address takerToken,uint256 takerTokenAmount,address makerToken,uint256 makerTokenAmount,uint256 feeFactor,uint256 expiry,uint256 salt)";
bytes32 constant OFFER_DATA_TYPEHASH = keccak256(bytes(OFFER_TYPESTRING));
struct Offer {
address taker;
address payable maker;
address takerToken;
uint256 takerTokenAmount;
address makerToken;
uint256 makerTokenAmount;
uint256 feeFactor;
uint256 expiry;
uint256 salt;
}
function getOfferHash(Offer memory offer) pure returns (bytes32) {
return
keccak256(
abi.encode(
OFFER_DATA_TYPEHASH,
offer.taker,
offer.maker,
offer.takerToken,
offer.takerTokenAmount,
offer.makerToken,
offer.makerTokenAmount,
offer.feeFactor,
offer.expiry,
offer.salt
)
);
}
文件 16 的 23:Ownable.sol
pragma solidity ^0.7.6;
abstract contract Ownable {
address public owner;
address public nominatedOwner;
event OwnerNominated(address indexed newOwner);
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
constructor(address _owner) {
require(_owner != address(0), "owner should not be 0");
owner = _owner;
}
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
_;
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "not nominated");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
function renounceOwnership() external onlyOwner {
require(nominatedOwner == address(0), "pending nomination exists");
emit OwnerChanged(owner, address(0));
owner = address(0);
}
function nominateNewOwner(address newOwner) external onlyOwner {
nominatedOwner = newOwner;
emit OwnerNominated(newOwner);
}
}
文件 17 的 23:RFQOrder.sol
pragma solidity ^0.7.6;
import { Offer, getOfferHash, OFFER_TYPESTRING } from "./Offer.sol";
string constant RFQ_ORDER_TYPESTRING = string(abi.encodePacked("RFQOrder(Offer offer,address recipient)", OFFER_TYPESTRING));
bytes32 constant RFQ_ORDER_TYPEHASH = keccak256(bytes(RFQ_ORDER_TYPESTRING));
struct RFQOrder {
Offer offer;
address payable recipient;
}
function getRFQOrderHash(RFQOrder memory rfqOrder) pure returns (bytes32 offerHash, bytes32 orderHash) {
offerHash = getOfferHash(rfqOrder.offer);
orderHash = keccak256(abi.encode(RFQ_ORDER_TYPEHASH, offerHash, rfqOrder.recipient));
}
文件 18 的 23:RFQv2.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { TokenCollector } from "./utils/TokenCollector.sol";
import { BaseLibEIP712 } from "./utils/BaseLibEIP712.sol";
import { Asset } from "./utils/Asset.sol";
import { Offer } from "./utils/Offer.sol";
import { RFQOrder, getRFQOrderHash } from "./utils/RFQOrder.sol";
import { LibConstant } from "./utils/LibConstant.sol";
import { SignatureValidator } from "./utils/SignatureValidator.sol";
import { StrategyBase } from "./utils/StrategyBase.sol";
import { IRFQv2 } from "./interfaces/IRFQv2.sol";
contract RFQv2 is IRFQv2, StrategyBase, TokenCollector, SignatureValidator, BaseLibEIP712 {
using SafeMath for uint256;
using Asset for address;
address payable public feeCollector;
event SetFeeCollector(address newFeeCollector);
receive() external payable {}
constructor(
address _owner,
address _userProxy,
address _weth,
address _permStorage,
address _spender,
address _uniswapPermit2,
address payable _feeCollector
) StrategyBase(_owner, _userProxy, _weth, _permStorage, _spender) TokenCollector(_uniswapPermit2, _spender) {
feeCollector = _feeCollector;
}
function setFeeCollector(address payable _newFeeCollector) external onlyOwner {
require(_newFeeCollector != address(0), "zero address");
feeCollector = _newFeeCollector;
emit SetFeeCollector(_newFeeCollector);
}
function fillRFQ(
RFQOrder calldata order,
bytes calldata makerSignature,
bytes calldata makerTokenPermit,
bytes calldata takerSignature,
bytes calldata takerTokenPermit
) external payable override onlyUserProxy {
Offer calldata _offer = order.offer;
require(_offer.expiry > block.timestamp, "offer expired");
require(_offer.feeFactor < LibConstant.BPS_MAX, "invalid fee factor");
require(order.recipient != address(0), "zero recipient");
(bytes32 offerHash, bytes32 rfqOrderHash) = getRFQOrderHash(order);
permStorage.setRFQOfferFilled(offerHash);
require(isValidSignature(_offer.maker, getEIP712Hash(offerHash), bytes(""), makerSignature), "invalid signature");
if (_offer.taker != msg.sender) {
require(isValidSignature(_offer.taker, getEIP712Hash(rfqOrderHash), bytes(""), takerSignature), "invalid signature");
}
if (_offer.takerToken.isETH()) {
require(msg.value == _offer.takerTokenAmount, "invalid msg value");
weth.deposit{ value: msg.value }();
weth.transfer(_offer.maker, msg.value);
} else {
require(msg.value == 0, "invalid msg value");
_collect(_offer.takerToken, _offer.taker, _offer.maker, _offer.takerTokenAmount, takerTokenPermit);
}
_collect(_offer.makerToken, _offer.maker, address(this), _offer.makerTokenAmount, makerTokenPermit);
uint256 fee = _offer.makerTokenAmount.mul(_offer.feeFactor).div(LibConstant.BPS_MAX);
uint256 makerTokenToTaker = _offer.makerTokenAmount.sub(fee);
{
address makerToken = _offer.makerToken;
if (makerToken == address(weth)) {
weth.withdraw(_offer.makerTokenAmount);
makerToken = LibConstant.ETH_ADDRESS;
}
if (fee > 0) {
makerToken.transferTo(feeCollector, fee);
}
makerToken.transferTo(order.recipient, makerTokenToTaker);
}
_emitFilledRFQEvent(offerHash, order, makerTokenToTaker);
}
function _emitFilledRFQEvent(
bytes32 _offerHash,
RFQOrder calldata _rfqOrder,
uint256 _makerTokenToTaker
) internal {
emit FilledRFQ(
_offerHash,
_rfqOrder.offer.taker,
_rfqOrder.offer.maker,
_rfqOrder.offer.takerToken,
_rfqOrder.offer.takerTokenAmount,
_rfqOrder.offer.makerToken,
_rfqOrder.offer.makerTokenAmount,
_rfqOrder.recipient,
_makerTokenToTaker,
_rfqOrder.offer.feeFactor
);
}
}
文件 19 的 23:SafeERC20.sol
pragma solidity ^0.7.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");
}
}
}
文件 20 的 23:SafeMath.sol
pragma solidity ^0.7.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;
}
}
文件 21 的 23:SignatureValidator.sol
pragma solidity 0.7.6;
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 internal constant ERC1271_MAGICVALUE = 0x20c13b0b;
bytes4 internal constant ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e;
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 == 65 || _sig.length == 97, "SignatureValidator#isValidSignature: length 65 or 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 == 65 || _sig.length == 97, "SignatureValidator#isValidSignature: length 65 or 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;
}
}
文件 22 的 23:StrategyBase.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "./Ownable.sol";
import "./LibConstant.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/IStrategyBase.sol";
import "../interfaces/ISpender.sol";
import "../interfaces/IPermanentStorage.sol";
abstract contract StrategyBase is IStrategyBase, Ownable {
using SafeERC20 for IERC20;
address public immutable userProxy;
IWETH public immutable weth;
IPermanentStorage public immutable permStorage;
ISpender public spender;
constructor(
address _owner,
address _userProxy,
address _weth,
address _permStorage,
address _spender
) Ownable(_owner) {
userProxy = _userProxy;
weth = IWETH(_weth);
permStorage = IPermanentStorage(_permStorage);
spender = ISpender(_spender);
}
modifier onlyUserProxy() {
require(address(userProxy) == msg.sender, "Strategy: not from UserProxy contract");
_;
}
function upgradeSpender(address _newSpender) external override onlyOwner {
require(_newSpender != address(0), "Strategy: spender can not be zero address");
spender = ISpender(_newSpender);
emit UpgradeSpender(_newSpender);
}
function setAllowance(address[] calldata _tokenList, address _spender) external override onlyOwner {
for (uint256 i = 0; i < _tokenList.length; ++i) {
IERC20(_tokenList[i]).safeApprove(_spender, LibConstant.MAX_UINT);
emit AllowTransfer(_spender, _tokenList[i]);
}
}
function closeAllowance(address[] calldata _tokenList, address _spender) external override onlyOwner {
for (uint256 i = 0; i < _tokenList.length; ++i) {
IERC20(_tokenList[i]).safeApprove(_spender, 0);
emit DisallowTransfer(_spender, _tokenList[i]);
}
}
function depositETH() external override onlyOwner {
uint256 balance = address(this).balance;
if (balance > 0) {
weth.deposit{ value: balance }();
emit DepositETH(balance);
}
}
}
文件 23 的 23:TokenCollector.sol
pragma solidity ^0.7.6;
pragma abicoder v2;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IUniswapPermit2 } from "../interfaces/IUniswapPermit2.sol";
import { ISpender } from "../interfaces/ISpender.sol";
import { IERC20Permit } from "../interfaces/IERC20Permit.sol";
abstract contract TokenCollector {
using SafeERC20 for IERC20;
enum Source {
TokenlonSpender,
Token,
TokenPermit,
Permit2AllowanceTransfer,
Permit2SignatureTransfer
}
address public immutable permit2;
address public immutable tokenlonSpender;
constructor(address _permit2, address _tokenlonSpender) {
permit2 = _permit2;
tokenlonSpender = _tokenlonSpender;
}
function _collect(
address token,
address from,
address to,
uint256 amount,
bytes calldata data
) internal {
Source src = Source(uint8(data[0]));
if (src == Source.TokenlonSpender) {
ISpender(tokenlonSpender).spendFromUser(from, token, amount);
if (to != address(this)) {
IERC20(token).safeTransfer(to, amount);
}
return;
} else if (src == Source.Token) {
return IERC20(token).safeTransferFrom(from, to, amount);
} else if (src == Source.TokenPermit) {
(bool success, bytes memory result) = token.call(abi.encodePacked(IERC20Permit.permit.selector, data[1:]));
if (!success) {
assembly {
revert(add(result, 32), returndatasize())
}
}
return IERC20(token).safeTransferFrom(from, to, amount);
} else if (src == Source.Permit2AllowanceTransfer) {
bytes memory permit2Data = data[1:];
if (permit2Data.length > 0) {
(bool success, bytes memory result) = permit2.call(abi.encodePacked(IUniswapPermit2.permit.selector, permit2Data));
if (!success) {
assembly {
revert(add(result, 32), returndatasize())
}
}
}
return IUniswapPermit2(permit2).transferFrom(from, to, uint160(amount), token);
} else if (src == Source.Permit2SignatureTransfer) {
bytes memory permit2Data = data[1:];
require(permit2Data.length != 0, "empty permit2 data");
(uint256 nonce, uint256 deadline, bytes memory permitSig) = abi.decode(permit2Data, (uint256, uint256, bytes));
IUniswapPermit2.PermitTransferFrom memory permit = IUniswapPermit2.PermitTransferFrom({
permitted: IUniswapPermit2.TokenPermissions({ token: token, amount: amount }),
nonce: nonce,
deadline: deadline
});
IUniswapPermit2.SignatureTransferDetails memory detail = IUniswapPermit2.SignatureTransferDetails({ to: to, requestedAmount: amount });
return IUniswapPermit2(permit2).permitTransferFrom(permit, detail, from, permitSig);
}
revert();
}
}
{
"compilationTarget": {
"contracts/RFQv2.sol": "RFQv2"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": [
":@openzeppelin/=lib/openzeppelin-contracts/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"
]
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_userProxy","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_permStorage","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"address","name":"_uniswapPermit2","type":"address"},{"internalType":"address payable","name":"_feeCollector","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"AllowTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"DisallowTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"offerHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"address","name":"takerToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"takerTokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"makerToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"makerTokenAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"settleAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeFactor","type":"uint256"}],"name":"FilledRFQ","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"SetFeeCollector","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":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","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":[],"name":"feeCollector","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address payable","name":"maker","type":"address"},{"internalType":"address","name":"takerToken","type":"address"},{"internalType":"uint256","name":"takerTokenAmount","type":"uint256"},{"internalType":"address","name":"makerToken","type":"address"},{"internalType":"uint256","name":"makerTokenAmount","type":"uint256"},{"internalType":"uint256","name":"feeFactor","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"}],"internalType":"struct Offer","name":"offer","type":"tuple"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct RFQOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"internalType":"bytes","name":"makerTokenPermit","type":"bytes"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"internalType":"bytes","name":"takerTokenPermit","type":"bytes"}],"name":"fillRFQ","outputs":[],"stateMutability":"payable","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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originalChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originalEIP712DomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","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":[],"name":"permit2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokenList","type":"address[]"},{"internalType":"address","name":"_spender","type":"address"}],"name":"setAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newFeeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spender","outputs":[{"internalType":"contract ISpender","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenlonSpender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]