文件 1 的 1:ChaingeOrder.sol
pragma solidity ^0.8.9;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
abstract contract Controller is Ownable {
event ControllerAdded(address controller);
event ControllerRemoved(address controller);
mapping(address => bool) public controllers;
uint8 public controllerCnt = 0;
modifier onlyController() {
require(isController(_msgSender()), "no controller rights");
_;
}
function isController(address _controller) public view returns (bool) {
return _controller == owner() || controllers[_controller];
}
function addController(address _controller) public onlyOwner {
if (controllers[_controller] == false) {
controllers[_controller] = true;
controllerCnt++;
}
emit ControllerAdded(_controller);
}
function removeController(address _controller) public onlyOwner {
if (controllers[_controller] == true) {
controllers[_controller] = false;
controllerCnt--;
}
emit ControllerRemoved(_controller);
}
}
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(
address owner,
address spender
) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
interface IWETH is IERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() external payable;
function withdraw(uint256 amount) external;
}
library OpAddress {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(
address(this).balance >= amount,
"Address: insufficient balance"
);
(bool success, ) = recipient.call{value: amount}("");
require(
success,
"Address: unable to send value, recipient may have reverted"
);
}
function functionCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return
functionCallWithValue(
target,
data,
0,
"Address: low-level call failed"
);
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return
functionCallWithValue(
target,
data,
value,
"Address: low-level call with value failed"
);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(
address(this).balance >= value,
"Address: insufficient balance for call"
);
(bool success, bytes memory returndata) = target.call{value: value}(
data
);
return
verifyCallResultFromTarget(
target,
success,
returndata,
errorMessage
);
}
function functionStaticCall(
address target,
bytes memory data
) internal view returns (bytes memory) {
return
functionStaticCall(
target,
data,
"Address: low-level static call failed"
);
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return
verifyCallResultFromTarget(
target,
success,
returndata,
errorMessage
);
}
function functionDelegateCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return
functionDelegateCall(
target,
data,
"Address: low-level delegate call failed"
);
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return
verifyCallResultFromTarget(
target,
success,
returndata,
errorMessage
);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(
bytes memory returndata,
string memory errorMessage
) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
library SafeERC20 {
using OpAddress for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transfer.selector, to, value)
);
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
);
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, value)
);
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(
token,
abi.encodeWithSelector(
token.approve.selector,
spender,
oldAllowance + value
)
);
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(
oldAllowance >= value,
"SafeERC20: decreased allowance below zero"
);
_callOptionalReturn(
token,
abi.encodeWithSelector(
token.approve.selector,
spender,
oldAllowance - value
)
);
}
}
function forceApprove(
IERC20 token,
address spender,
uint256 value
) internal {
bytes memory approvalCall = abi.encodeWithSelector(
token.approve.selector,
spender,
value
);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(
token,
abi.encodeWithSelector(token.approve.selector, spender, 0)
);
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(
data,
"SafeERC20: low-level call failed"
);
require(
returndata.length == 0 || abi.decode(returndata, (bool)),
"SafeERC20: ERC20 operation did not succeed"
);
}
function _callOptionalReturnBool(
IERC20 token,
bytes memory data
) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success &&
(returndata.length == 0 || abi.decode(returndata, (bool))) &&
OpAddress.isContract(address(token));
}
function safeDeposit(IWETH weth, uint256 amount) internal {
if (amount > 0) {
bytes4 selector = IWETH.deposit.selector;
assembly ("memory-safe") {
mstore(0, selector)
if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
}
function safeWithdraw(IWETH weth, uint256 amount) internal {
bytes4 selector = IWETH.withdraw.selector;
assembly ("memory-safe") {
mstore(0, selector)
mstore(4, amount)
if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
safeWithdraw(weth, amount);
if (to != address(this)) {
assembly ("memory-safe") {
if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
}
}
type Address is uint256;
library AddressLib {
uint256 private constant _LOW_160_BIT_MASK = (1 << 160) - 1;
function get(Address a) internal pure returns (address) {
return address(uint160(Address.unwrap(a) & _LOW_160_BIT_MASK));
}
function getFlag(Address a, uint256 flag) internal pure returns (bool) {
return (Address.unwrap(a) & flag) != 0;
}
function getUint32(
Address a,
uint256 offset
) internal pure returns (uint32) {
return uint32(Address.unwrap(a) >> offset);
}
function getUint64(
Address a,
uint256 offset
) internal pure returns (uint64) {
return uint64(Address.unwrap(a) >> offset);
}
}
type MakerTraits is uint256;
library MakerTraitsLib {
uint256 private constant _ALLOWED_SENDER_MASK = type(uint80).max;
uint256 private constant _EXPIRATION_OFFSET = 80;
uint256 private constant _EXPIRATION_MASK = type(uint40).max;
uint256 private constant _NONCE_OR_EPOCH_OFFSET = 120;
uint256 private constant _NONCE_OR_EPOCH_MASK = type(uint40).max;
uint256 private constant _SERIES_OFFSET = 160;
uint256 private constant _SERIES_MASK = type(uint40).max;
uint256 private constant _NO_PARTIAL_FILLS_FLAG = 1 << 255;
uint256 private constant _ALLOW_MULTIPLE_FILLS_FLAG = 1 << 254;
uint256 private constant _PRE_INTERACTION_CALL_FLAG = 1 << 252;
uint256 private constant _POST_INTERACTION_CALL_FLAG = 1 << 251;
uint256 private constant _NEED_CHECK_EPOCH_MANAGER_FLAG = 1 << 250;
uint256 private constant _HAS_EXTENSION_FLAG = 1 << 249;
uint256 private constant _USE_PERMIT2_FLAG = 1 << 248;
uint256 private constant _UNWRAP_WETH_FLAG = 1 << 247;
function hasExtension(
MakerTraits makerTraits
) internal pure returns (bool) {
return (MakerTraits.unwrap(makerTraits) & _HAS_EXTENSION_FLAG) != 0;
}
function isAllowedSender(
MakerTraits makerTraits,
address sender
) internal pure returns (bool) {
uint160 allowedSender = uint160(
MakerTraits.unwrap(makerTraits) & _ALLOWED_SENDER_MASK
);
return
allowedSender == 0 ||
allowedSender == uint160(sender) & _ALLOWED_SENDER_MASK;
}
function isExpired(MakerTraits makerTraits) internal view returns (bool) {
uint256 expiration = (MakerTraits.unwrap(makerTraits) >>
_EXPIRATION_OFFSET) & _EXPIRATION_MASK;
return expiration != 0 && expiration < block.timestamp;
}
function nonceOrEpoch(
MakerTraits makerTraits
) internal pure returns (uint256) {
return
(MakerTraits.unwrap(makerTraits) >> _NONCE_OR_EPOCH_OFFSET) &
_NONCE_OR_EPOCH_MASK;
}
function series(MakerTraits makerTraits) internal pure returns (uint256) {
return
(MakerTraits.unwrap(makerTraits) >> _SERIES_OFFSET) & _SERIES_MASK;
}
function allowPartialFills(
MakerTraits makerTraits
) internal pure returns (bool) {
return (MakerTraits.unwrap(makerTraits) & _NO_PARTIAL_FILLS_FLAG) == 0;
}
function needPreInteractionCall(
MakerTraits makerTraits
) internal pure returns (bool) {
return
(MakerTraits.unwrap(makerTraits) & _PRE_INTERACTION_CALL_FLAG) != 0;
}
function needPostInteractionCall(
MakerTraits makerTraits
) internal pure returns (bool) {
return
(MakerTraits.unwrap(makerTraits) & _POST_INTERACTION_CALL_FLAG) !=
0;
}
function allowMultipleFills(
MakerTraits makerTraits
) internal pure returns (bool) {
return
(MakerTraits.unwrap(makerTraits) & _ALLOW_MULTIPLE_FILLS_FLAG) != 0;
}
function useBitInvalidator(
MakerTraits makerTraits
) internal pure returns (bool) {
return
!allowPartialFills(makerTraits) || !allowMultipleFills(makerTraits);
}
function needCheckEpochManager(
MakerTraits makerTraits
) internal pure returns (bool) {
return
(MakerTraits.unwrap(makerTraits) &
_NEED_CHECK_EPOCH_MANAGER_FLAG) != 0;
}
function usePermit2(MakerTraits makerTraits) internal pure returns (bool) {
return MakerTraits.unwrap(makerTraits) & _USE_PERMIT2_FLAG != 0;
}
function unwrapWeth(MakerTraits makerTraits) internal pure returns (bool) {
return MakerTraits.unwrap(makerTraits) & _UNWRAP_WETH_FLAG != 0;
}
}
type TakerTraits is uint256;
library TakerTraitsLib {
uint256 private constant _MAKER_AMOUNT_FLAG = 1 << 255;
uint256 private constant _UNWRAP_WETH_FLAG = 1 << 254;
uint256 private constant _SKIP_ORDER_PERMIT_FLAG = 1 << 253;
uint256 private constant _USE_PERMIT2_FLAG = 1 << 252;
uint256 private constant _ARGS_HAS_TARGET = 1 << 251;
uint256 private constant _ARGS_EXTENSION_LENGTH_OFFSET = 224;
uint256 private constant _ARGS_EXTENSION_LENGTH_MASK = 0xffffff;
uint256 private constant _ARGS_INTERACTION_LENGTH_OFFSET = 200;
uint256 private constant _ARGS_INTERACTION_LENGTH_MASK = 0xffffff;
uint256 private constant _AMOUNT_MASK =
0x000000000000000000ffffffffffffffffffffffffffffffffffffffffffffff;
function argsHasTarget(
TakerTraits takerTraits
) internal pure returns (bool) {
return (TakerTraits.unwrap(takerTraits) & _ARGS_HAS_TARGET) != 0;
}
function argsExtensionLength(
TakerTraits takerTraits
) internal pure returns (uint256) {
return
(TakerTraits.unwrap(takerTraits) >> _ARGS_EXTENSION_LENGTH_OFFSET) &
_ARGS_EXTENSION_LENGTH_MASK;
}
function argsInteractionLength(
TakerTraits takerTraits
) internal pure returns (uint256) {
return
(TakerTraits.unwrap(takerTraits) >>
_ARGS_INTERACTION_LENGTH_OFFSET) &
_ARGS_INTERACTION_LENGTH_MASK;
}
function isMakingAmount(
TakerTraits takerTraits
) internal pure returns (bool) {
return (TakerTraits.unwrap(takerTraits) & _MAKER_AMOUNT_FLAG) != 0;
}
function unwrapWeth(TakerTraits takerTraits) internal pure returns (bool) {
return (TakerTraits.unwrap(takerTraits) & _UNWRAP_WETH_FLAG) != 0;
}
function skipMakerPermit(
TakerTraits takerTraits
) internal pure returns (bool) {
return (TakerTraits.unwrap(takerTraits) & _SKIP_ORDER_PERMIT_FLAG) != 0;
}
function usePermit2(TakerTraits takerTraits) internal pure returns (bool) {
return (TakerTraits.unwrap(takerTraits) & _USE_PERMIT2_FLAG) != 0;
}
function threshold(
TakerTraits takerTraits
) internal pure returns (uint256) {
return TakerTraits.unwrap(takerTraits) & _AMOUNT_MASK;
}
}
type Offsets is uint256;
library OffsetsLib {
error OffsetOutOfBounds();
function get(
Offsets offsets,
bytes calldata concat,
uint256 index
) internal pure returns (bytes calldata result) {
bytes4 exception = OffsetOutOfBounds.selector;
assembly ("memory-safe") {
let bitShift := shl(5, index)
let begin := and(0xffffffff, shr(bitShift, shl(32, offsets)))
let end := and(0xffffffff, shr(bitShift, offsets))
result.offset := add(concat.offset, begin)
result.length := sub(end, begin)
if gt(end, concat.length) {
mstore(0, exception)
revert(0, 4)
}
}
}
}
library ExtensionLib {
using AddressLib for Address;
using OffsetsLib for Offsets;
enum DynamicField {
MakerAssetSuffix,
TakerAssetSuffix,
MakingAmountData,
TakingAmountData,
Predicate,
MakerPermit,
PreInteractionData,
PostInteractionData,
CustomData
}
function makerAssetSuffix(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.MakerAssetSuffix);
}
function takerAssetSuffix(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.TakerAssetSuffix);
}
function makingAmountData(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.MakingAmountData);
}
function takingAmountData(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.TakingAmountData);
}
function predicate(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.Predicate);
}
function makerPermit(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.MakerPermit);
}
function preInteractionTargetAndData(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.PreInteractionData);
}
function postInteractionTargetAndData(
bytes calldata extension
) internal pure returns (bytes calldata) {
return _get(extension, DynamicField.PostInteractionData);
}
function customData(
bytes calldata extension
) internal pure returns (bytes calldata) {
if (extension.length < 0x20) return msg.data[:0];
uint256 offsets = uint256(bytes32(extension));
unchecked {
return extension[0x20 + (offsets >> 224):];
}
}
function _get(
bytes calldata extension,
DynamicField field
) private pure returns (bytes calldata) {
if (extension.length < 0x20) return msg.data[:0];
Offsets offsets;
bytes calldata concat;
assembly ("memory-safe") {
offsets := calldataload(extension.offset)
concat.offset := add(extension.offset, 0x20)
concat.length := sub(extension.length, 0x20)
}
return offsets.get(concat, uint256(field));
}
}
interface IOrderMixin {
struct Order {
uint256 salt;
Address maker;
Address receiver;
Address makerAsset;
Address takerAsset;
uint256 makingAmount;
uint256 takingAmount;
MakerTraits makerTraits;
}
}
library ECDSA {
uint256 private constant _S_BOUNDARY =
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 + 1;
uint256 private constant _COMPACT_S_MASK =
0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
uint256 private constant _COMPACT_V_SHIFT = 255;
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal view returns (address signer) {
assembly ("memory-safe") {
if lt(s, _S_BOUNDARY) {
let ptr := mload(0x40)
mstore(ptr, hash)
mstore(add(ptr, 0x20), v)
mstore(add(ptr, 0x40), r)
mstore(add(ptr, 0x60), s)
mstore(0, 0)
pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20))
signer := mload(0)
}
}
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal view returns (address signer) {
assembly ("memory-safe") {
let s := and(vs, _COMPACT_S_MASK)
if lt(s, _S_BOUNDARY) {
let ptr := mload(0x40)
mstore(ptr, hash)
mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs)))
mstore(add(ptr, 0x40), r)
mstore(add(ptr, 0x60), s)
mstore(0, 0)
pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20))
signer := mload(0)
}
}
}
function recover(
bytes32 hash,
bytes calldata signature
) internal view returns (address signer) {
assembly ("memory-safe") {
let ptr := mload(0x40)
switch signature.length
case 65 {
mstore(
add(ptr, 0x20),
byte(0, calldataload(add(signature.offset, 0x40)))
)
calldatacopy(add(ptr, 0x40), signature.offset, 0x40)
}
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
mstore(add(ptr, 0x20), add(27, shr(_COMPACT_V_SHIFT, vs)))
calldatacopy(add(ptr, 0x40), signature.offset, 0x20)
mstore(add(ptr, 0x60), and(vs, _COMPACT_S_MASK))
}
default {
ptr := 0
}
if ptr {
if lt(mload(add(ptr, 0x60)), _S_BOUNDARY) {
mstore(ptr, hash)
mstore(0, 0)
pop(staticcall(gas(), 0x1, ptr, 0x80, 0, 0x20))
signer := mload(0)
}
}
}
}
function toEthSignedMessageHash(
bytes32 hash
) internal pure returns (bytes32 res) {
assembly ("memory-safe") {
mstore(
0,
0x19457468657265756d205369676e6564204d6573736167653a0a333200000000
)
mstore(28, hash)
res := keccak256(0, 60)
}
}
function toTypedDataHash(
bytes32 domainSeparator,
bytes32 structHash
) internal pure returns (bytes32 res) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(
ptr,
0x1901000000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
res := keccak256(ptr, 66)
}
}
}
library AmountCalculatorLib {
function getMakingAmount(
uint256 orderMakerAmount,
uint256 orderTakerAmount,
uint256 swapTakerAmount
) internal pure returns (uint256) {
if ((swapTakerAmount | orderMakerAmount) >> 128 == 0) {
unchecked {
return (swapTakerAmount * orderMakerAmount) / orderTakerAmount;
}
}
return (swapTakerAmount * orderMakerAmount) / orderTakerAmount;
}
function getTakingAmount(
uint256 orderMakerAmount,
uint256 orderTakerAmount,
uint256 swapMakerAmount
) internal pure returns (uint256) {
if ((swapMakerAmount | orderTakerAmount) >> 128 == 0) {
unchecked {
return
(swapMakerAmount *
orderTakerAmount +
orderMakerAmount -
1) / orderMakerAmount;
}
}
return
(swapMakerAmount * orderTakerAmount + orderMakerAmount - 1) /
orderMakerAmount;
}
}
type RemainingInvalidator is uint256;
library RemainingInvalidatorLib {
error RemainingInvalidatedOrder();
function isNewOrder(
RemainingInvalidator invalidator
) internal pure returns (bool) {
return RemainingInvalidator.unwrap(invalidator) == 0;
}
function remaining(
RemainingInvalidator invalidator
) internal pure returns (uint256) {
uint256 value = RemainingInvalidator.unwrap(invalidator);
if (value == 0) {
revert RemainingInvalidatedOrder();
}
unchecked {
return ~value;
}
}
function remaining(
RemainingInvalidator invalidator,
uint256 orderMakerAmount
) internal pure returns (uint256) {
uint256 value = RemainingInvalidator.unwrap(invalidator);
if (value == 0) {
return orderMakerAmount;
}
unchecked {
return ~value;
}
}
function remains(
uint256 remainingMakingAmount,
uint256 makingAmount
) internal pure returns (RemainingInvalidator) {
unchecked {
return
RemainingInvalidator.wrap(
~(remainingMakingAmount - makingAmount)
);
}
}
function fullyFilled() internal pure returns (RemainingInvalidator) {
return RemainingInvalidator.wrap(type(uint256).max);
}
}
library OrderLib {
using AddressLib for Address;
using MakerTraitsLib for MakerTraits;
using ExtensionLib for bytes;
error MissingOrderExtension();
error UnexpectedOrderExtension();
error InvalidExtensionHash();
bytes32 internal constant _LIMIT_ORDER_TYPEHASH =
keccak256(
"Order("
"uint256 salt,"
"address maker,"
"address receiver,"
"address makerAsset,"
"address takerAsset,"
"uint256 makingAmount,"
"uint256 takingAmount,"
"uint256 makerTraits"
")"
);
uint256 internal constant _ORDER_STRUCT_SIZE = 0x100;
uint256 internal constant _DATA_HASH_SIZE = 0x120;
function hash(
IOrderMixin.Order calldata order
) internal pure returns (bytes32 result) {
bytes32 typehash = _LIMIT_ORDER_TYPEHASH;
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, typehash)
calldatacopy(add(ptr, 0x20), order, _ORDER_STRUCT_SIZE)
result := keccak256(ptr, _DATA_HASH_SIZE)
}
result = ECDSA.toTypedDataHash("0x", result);
}
function getReceiver(
IOrderMixin.Order calldata order
) internal pure returns (address ) {
address receiver = order.receiver.get();
return receiver != address(0) ? receiver : order.maker.get();
}
function isValidExtension(
IOrderMixin.Order calldata order,
bytes calldata extension
) internal pure returns (bool, bytes4) {
if (order.makerTraits.hasExtension()) {
if (extension.length == 0)
return (false, MissingOrderExtension.selector);
if (
uint256(keccak256(extension)) & type(uint160).max !=
order.salt & type(uint160).max
) return (false, InvalidExtensionHash.selector);
} else {
if (extension.length > 0)
return (false, UnexpectedOrderExtension.selector);
}
return (true, 0x00000000);
}
}
interface IPostInteraction {
function postInteraction(
IOrderMixin.Order calldata order,
bytes calldata extension,
bytes32 orderHash,
address taker,
uint256 makingAmount,
uint256 takingAmount,
uint256 remainingMakingAmount,
bytes calldata extraData
) external;
}
interface IPreInteraction {
function preInteraction(
IOrderMixin.Order calldata order,
bytes calldata extension,
bytes32 orderHash,
address taker,
uint256 makingAmount,
uint256 takingAmount,
uint256 remainingMakingAmount,
bytes calldata extraData
) external;
}
contract ChaingeOrder is Controller {
using SafeERC20 for IERC20;
using SafeERC20 for IWETH;
using OrderLib for IOrderMixin.Order;
using ExtensionLib for bytes;
using AddressLib for Address;
using MakerTraitsLib for MakerTraits;
using TakerTraitsLib for TakerTraits;
using RemainingInvalidatorLib for RemainingInvalidator;
IWETH private _WETH;
bool private _paused;
event OrderFilled(bytes32 orderHash, uint256 remainingAmount);
event OrderCancelled(bytes32 orderHash);
mapping(address => mapping(bytes32 => RemainingInvalidator))
private _remainingInvalidator;
constructor(IWETH weth) {
_WETH = weth;
_paused = false;
}
modifier whenNotPaused() {
require(!_paused, "MP: paused");
_;
}
receive() external payable {}
fallback() external payable {}
function pause() external onlyOwner {
_paused = true;
}
function unpause() external onlyOwner {
_paused = false;
}
function setWToken(IWETH weth) external onlyOwner {
_WETH = weth;
}
function cancelOrder(bytes32 orderHash) public {
_remainingInvalidator[msg.sender][orderHash] = RemainingInvalidatorLib
.fullyFilled();
emit OrderCancelled(orderHash);
}
function cancelOrders(bytes32[] calldata orderHashes) external {
unchecked {
for (uint256 i = 0; i < orderHashes.length; i++) {
cancelOrder(orderHashes[i]);
}
}
}
function hashOrder(
IOrderMixin.Order calldata order
) external pure returns (bytes32) {
return order.hash();
}
function fillContractOrderArgs(
IOrderMixin.Order calldata order,
bytes calldata signature,
uint256 amount,
TakerTraits takerTraits,
bytes calldata args
)
external
onlyController
whenNotPaused
returns (
uint256 ,
uint256 ,
bytes32
)
{
(
address target,
bytes calldata extension,
bytes calldata interaction
) = _parseArgs(takerTraits, args);
return
_fillContractOrder(
order,
signature,
amount,
takerTraits,
target,
extension,
interaction
);
}
function _fillContractOrder(
IOrderMixin.Order calldata order,
bytes calldata ,
uint256 amount,
TakerTraits takerTraits,
address target,
bytes calldata extension,
bytes calldata interaction
)
private
returns (uint256 makingAmount, uint256 takingAmount, bytes32 orderHash)
{
orderHash = order.hash();
uint256 remainingMakingAmount = _checkRemainingMakingAmount(
order,
orderHash
);
(makingAmount, takingAmount) = _fill(
order,
orderHash,
remainingMakingAmount,
amount,
takerTraits,
target,
extension,
interaction
);
}
function _fill(
IOrderMixin.Order calldata order,
bytes32 orderHash,
uint256 remainingMakingAmount,
uint256 amount,
TakerTraits takerTraits,
address target,
bytes calldata extension,
bytes calldata
) private returns (uint256 makingAmount, uint256 takingAmount) {
require(!order.makerTraits.isExpired(), "OrderExpired");
if (takerTraits.isMakingAmount()) {
makingAmount = amount < remainingMakingAmount
? amount
: remainingMakingAmount;
takingAmount = AmountCalculatorLib.getTakingAmount(
order.makingAmount,
order.takingAmount,
remainingMakingAmount
);
uint256 threshold = takerTraits.threshold();
if (threshold > 0) {
if (amount == makingAmount) {
require(takingAmount <= threshold, "TakingAmountTooHigh");
} else {
require(
takingAmount * amount <= threshold * makingAmount,
"TakingAmountTooHigh"
);
}
}
} else {
takingAmount = amount;
makingAmount = AmountCalculatorLib.getMakingAmount(
order.makingAmount,
order.takingAmount,
takingAmount
);
if (makingAmount > remainingMakingAmount) {
makingAmount = remainingMakingAmount;
takingAmount = AmountCalculatorLib.getTakingAmount(
order.makingAmount,
order.takingAmount,
makingAmount
);
require(takingAmount <= amount, "TakingAmountExceeded");
}
uint256 threshold = takerTraits.threshold();
if (threshold > 0) {
if (amount == takingAmount) {
require(makingAmount >= threshold, "MakingAmountTooLow");
} else {
require(
makingAmount * amount >= threshold * takingAmount,
"MakingAmountTooLow"
);
}
}
}
if (!order.makerTraits.allowPartialFills()) {
require(
makingAmount == order.makingAmount,
"PartialFillNotAllowed"
);
}
require(makingAmount * takingAmount > 0, "SwapWithZeroAmount");
{
if (order.makerTraits.needPreInteractionCall()) {
bytes calldata data = extension.preInteractionTargetAndData();
address listener = order.maker.get();
if (data.length > 19) {
listener = address(bytes20(data));
data = data[20:];
}
IPreInteraction(listener).preInteraction(
order,
extension,
orderHash,
msg.sender,
makingAmount,
takingAmount,
remainingMakingAmount,
data
);
}
}
{
bool needUnwrap = order.makerAsset.get() == address(_WETH) &&
takerTraits.unwrapWeth();
address receiver = needUnwrap ? address(this) : target;
bool success = _callTransferFromWithSuffix(
order.makerAsset.get(),
order.maker.get(),
receiver,
makingAmount,
extension.makerAssetSuffix()
);
require(success, "TransferFromMakerToTakerFailed");
if (needUnwrap) {
_WETH.safeWithdrawTo(makingAmount, target);
}
}
if (order.takerAsset.get() == address(_WETH) && msg.value > 0) {
require(msg.value >= takingAmount, "InvalidMsgValue");
if (msg.value > takingAmount) {
unchecked {
(bool success, ) = msg.sender.call{
value: msg.value - takingAmount
}("");
require(success, "ETHTransferFailed");
}
}
if (order.makerTraits.unwrapWeth()) {
(bool success, ) = order.getReceiver().call{
value: takingAmount
}("");
require(success, "ETHTransferFailed");
} else {
_WETH.safeDeposit(takingAmount);
_WETH.safeTransfer(order.getReceiver(), takingAmount);
}
} else {
require(msg.value == 0, "InvalidMsgValue");
bool needUnwrap = order.takerAsset.get() == address(_WETH) &&
order.makerTraits.unwrapWeth();
address receiver = needUnwrap ? address(this) : order.getReceiver();
require(
_callTransferFromWithSuffix(
order.takerAsset.get(),
msg.sender,
receiver,
takingAmount,
extension.takerAssetSuffix()
),
"TransferFromTakerToMakerFailed"
);
if (needUnwrap) {
_WETH.safeWithdrawTo(takingAmount, order.getReceiver());
}
}
if (order.makerTraits.needPostInteractionCall()) {
bytes calldata data = extension.postInteractionTargetAndData();
address listener = order.maker.get();
if (data.length > 19) {
listener = address(bytes20(data));
data = data[20:];
}
IPostInteraction(listener).postInteraction(
order,
extension,
orderHash,
msg.sender,
makingAmount,
takingAmount,
remainingMakingAmount,
data
);
}
emit OrderFilled(orderHash, remainingMakingAmount - makingAmount);
}
function _parseArgs(
TakerTraits takerTraits,
bytes calldata args
)
private
view
returns (
address target,
bytes calldata extension,
bytes calldata interaction
)
{
if (takerTraits.argsHasTarget()) {
target = address(bytes20(args));
args = args[20:];
} else {
target = msg.sender;
}
uint256 extensionLength = takerTraits.argsExtensionLength();
if (extensionLength > 0) {
extension = args[:extensionLength];
args = args[extensionLength:];
} else {
extension = msg.data[:0];
}
uint256 interactionLength = takerTraits.argsInteractionLength();
if (interactionLength > 0) {
interaction = args[:interactionLength];
} else {
interaction = msg.data[:0];
}
}
function _checkRemainingMakingAmount(
IOrderMixin.Order calldata order,
bytes32 orderHash
) private view returns (uint256 remainingMakingAmount) {
remainingMakingAmount = _remainingInvalidator[order.maker.get()][
orderHash
].remaining(order.makingAmount);
require(remainingMakingAmount > 0, "InvalidatedOrder");
}
function _callTransferFromWithSuffix(
address asset,
address from,
address to,
uint256 amount,
bytes calldata suffix
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ("memory-safe") {
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
if suffix.length {
calldatacopy(add(data, 0x64), suffix.offset, suffix.length)
}
let status := call(
gas(),
asset,
0,
data,
add(0x64, suffix.length),
0x0,
0x20
)
success := and(
status,
or(
iszero(returndatasize()),
and(gt(returndatasize(), 31), eq(mload(0), 1))
)
)
}
}
}