From a3a34d72656601c436efe67cac25b65cdf760cfd Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 14:19:38 +0800 Subject: [PATCH 01/41] Copy ILimitOrder -> IPionexContract --- contracts/interfaces/IPionexContract.sol | 140 +++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 contracts/interfaces/IPionexContract.sol diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol new file mode 100644 index 00000000..ec383a18 --- /dev/null +++ b/contracts/interfaces/IPionexContract.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0; +pragma abicoder v2; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "./IStrategyBase.sol"; +import "../utils/LimitOrderLibEIP712.sol"; + +/// @title IPionexContract Interface +/// @author imToken Labs +interface IPionexContract is IStrategyBase { + /// @notice Emitted when coordinator address is updated + /// @param newCoordinator The address of the new coordinator + event UpgradeCoordinator(address newCoordinator); + + /// @notice Emitted when fee factors are updated + /// @param makerFeeFactor The new fee factor for maker + /// @param takerFeeFactor The new fee factor for taker + /// @param profitFeeFactor The new fee factor for relayer profit + event FactorsUpdated(uint16 makerFeeFactor, uint16 takerFeeFactor, uint16 profitFeeFactor); + + /// @notice Emitted when fee collector address is updated + /// @param newFeeCollector The address of the new fee collector + event SetFeeCollector(address newFeeCollector); + + /// @notice Emitted when an order is filled by a trader + /// @param orderHash The EIP-712 hash of the target order + /// @param maker The address of the maker + /// @param taker The address of the taker (trader) + /// @param allowFillHash The EIP-712 hash of the fill permit granted by coordinator + /// @param recipient The address of the recipient which will receive tokens from maker + /// @param fillReceipt Contains details of this single fill + event LimitOrderFilledByTrader( + bytes32 indexed orderHash, + address indexed maker, + address indexed taker, + bytes32 allowFillHash, + address recipient, + FillReceipt fillReceipt + ); + + /// @notice Emitted when an order is filled by interacting with an external protocol + /// @param orderHash The EIP-712 hash of the target order + /// @param maker The address of the maker + /// @param taker The address of the taker (trader) + /// @param allowFillHash The EIP-712 hash of the fill permit granted by coordinator + /// @param relayer The address of the relayer + /// @param profitRecipient The address of the recipient which receives relaying profit + /// @param fillReceipt Contains details of this single fill + /// @param relayerTakerTokenProfit Profit that relayer makes from this fill + /// @param relayerTakerTokenProfitFee Protocol fee charged on the relaying profit + event LimitOrderFilledByProtocol( + bytes32 indexed orderHash, + address indexed maker, + address indexed taker, + bytes32 allowFillHash, + address relayer, + address profitRecipient, + FillReceipt fillReceipt, + uint256 relayerTakerTokenProfit, + uint256 relayerTakerTokenProfitFee + ); + + /// @notice Emitted when order is cancelled + /// @param orderHash The EIP-712 hash of the target order + /// @param maker The address of the maker + event OrderCancelled(bytes32 orderHash, address maker); + + struct FillReceipt { + address makerToken; + address takerToken; + uint256 makerTokenFilledAmount; + uint256 takerTokenFilledAmount; + uint256 remainingAmount; + uint256 makerTokenFee; + uint256 takerTokenFee; + } + + struct CoordinatorParams { + bytes sig; + uint256 salt; + uint64 expiry; + } + + struct TraderParams { + address taker; + address recipient; + uint256 takerTokenAmount; + uint256 salt; + uint64 expiry; + bytes takerSig; + } + + /// @notice Fill an order by a trader + /// @notice Only user proxy can call + /// @param _order The order that is going to be filled + /// @param _orderMakerSig The signature of the order from maker + /// @param _params Trader specific filling parameters + /// @param _crdParams Contains details of the fill permit + function fillLimitOrderByTrader( + LimitOrderLibEIP712.Order calldata _order, + bytes calldata _orderMakerSig, + TraderParams calldata _params, + CoordinatorParams calldata _crdParams + ) external returns (uint256, uint256); + + enum Protocol { + UniswapV3, + Sushiswap + } + + struct ProtocolParams { + Protocol protocol; + bytes data; + address profitRecipient; + uint256 takerTokenAmount; + uint256 protocolOutMinimum; + uint64 expiry; + } + + /// @notice Fill an order by interacting with an external protocol + /// @notice Only user proxy can call + /// @param _order The order that is going to be filled + /// @param _orderMakerSig The signature of the order from maker + /// @param _params Protocol specific filling parameters + /// @param _crdParams Contains details of the fill permit + function fillLimitOrderByProtocol( + LimitOrderLibEIP712.Order calldata _order, + bytes calldata _orderMakerSig, + ProtocolParams calldata _params, + CoordinatorParams calldata _crdParams + ) external returns (uint256); + + /// @notice Cancel an order + /// @notice Only user proxy can call + /// @param _order The order that is going to be cancelled + /// @param _cancelMakerSig The cancelling signature signed by maker + function cancelLimitOrder(LimitOrderLibEIP712.Order calldata _order, bytes calldata _cancelMakerSig) external; +} From 0b1d587acbe843287e462321709ef468cb8dea8e Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 14:25:04 +0800 Subject: [PATCH 02/41] Add makerTokenAmount to IPionex TraderParam --- contracts/interfaces/IPionexContract.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index ec383a18..3b6e9728 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -86,6 +86,7 @@ interface IPionexContract is IStrategyBase { struct TraderParams { address taker; address recipient; + uint256 makerTokenAmount; uint256 takerTokenAmount; uint256 salt; uint64 expiry; From e34635eb785df6f33fc685ed00a9b9300886ece3 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 14:40:52 +0800 Subject: [PATCH 03/41] Copy LimitOrderLibEIP712 -> PionexContractLibEIP712 --- contracts/utils/PionexContractLibEIP712.sol | 100 ++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 contracts/utils/PionexContractLibEIP712.sol diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/PionexContractLibEIP712.sol new file mode 100644 index 00000000..23556531 --- /dev/null +++ b/contracts/utils/PionexContractLibEIP712.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "../interfaces/IPionexContract.sol"; + +library PionexContractLibEIP712 { + struct Order { + IERC20 makerToken; + IERC20 takerToken; + uint256 makerTokenAmount; + uint256 takerTokenAmount; + address maker; + address taker; + uint256 salt; + uint64 expiry; + } + + /* + keccak256( + abi.encodePacked( + "Order(", + "address makerToken,", + "address takerToken,", + "uint256 makerTokenAmount,", + "uint256 takerTokenAmount,", + "address maker,", + "address taker,", + "uint256 salt,", + "uint64 expiry", + ")" + ) + ); + */ + bytes32 private constant ORDER_TYPEHASH = 0x025174f0ee45736f4e018e96c368bd4baf3dce8d278860936559209f568c8ecb; + + function _getOrderStructHash(Order memory _order) internal pure returns (bytes32) { + return + keccak256( + abi.encode( + ORDER_TYPEHASH, + address(_order.makerToken), + address(_order.takerToken), + _order.makerTokenAmount, + _order.takerTokenAmount, + _order.maker, + _order.taker, + _order.salt, + _order.expiry + ) + ); + } + + struct Fill { + bytes32 orderHash; // EIP712 hash + address taker; + address recipient; + uint256 takerTokenAmount; + uint256 takerSalt; + uint64 expiry; + } + + /* + keccak256( + abi.encodePacked( + "Fill(", + "bytes32 orderHash,", + "address taker,", + "address recipient,", + "uint256 takerTokenAmount,", + "uint256 takerSalt,", + "uint64 expiry", + ")" + ) + ); + */ + bytes32 private constant FILL_TYPEHASH = 0x4ef294060cea2f973f7fe2a6d78624328586118efb1c4d640855aac3ba70e9c9; + + function _getFillStructHash(Fill memory _fill) internal pure returns (bytes32) { + return keccak256(abi.encode(FILL_TYPEHASH, _fill.orderHash, _fill.taker, _fill.recipient, _fill.takerTokenAmount, _fill.takerSalt, _fill.expiry)); + } + + struct AllowFill { + bytes32 orderHash; // EIP712 hash + address executor; + uint256 fillAmount; + uint256 salt; + uint64 expiry; + } + + /* + keccak256(abi.encodePacked("AllowFill(", "bytes32 orderHash,", "address executor,", "uint256 fillAmount,", "uint256 salt,", "uint64 expiry", ")")); + */ + bytes32 private constant ALLOW_FILL_TYPEHASH = 0xa471a3189b88889758f25ee2ce05f58964c40b03edc9cc9066079fd2b547f074; + + function _getAllowFillStructHash(AllowFill memory _allowFill) internal pure returns (bytes32) { + return keccak256(abi.encode(ALLOW_FILL_TYPEHASH, _allowFill.orderHash, _allowFill.executor, _allowFill.fillAmount, _allowFill.salt, _allowFill.expiry)); + } +} From 59b03420c3a4d219d434398a7613ff94970cb212 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 14:45:27 +0800 Subject: [PATCH 04/41] Add makerTokenAmount to Fill --- contracts/interfaces/IPionexContract.sol | 8 ++++---- contracts/utils/PionexContractLibEIP712.sol | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 3b6e9728..411242da 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -5,7 +5,7 @@ pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IStrategyBase.sol"; -import "../utils/LimitOrderLibEIP712.sol"; +import "../utils/PionexContractLibEIP712.sol"; /// @title IPionexContract Interface /// @author imToken Labs @@ -100,7 +100,7 @@ interface IPionexContract is IStrategyBase { /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit function fillLimitOrderByTrader( - LimitOrderLibEIP712.Order calldata _order, + PionexContractLibEIP712.Order calldata _order, bytes calldata _orderMakerSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams @@ -127,7 +127,7 @@ interface IPionexContract is IStrategyBase { /// @param _params Protocol specific filling parameters /// @param _crdParams Contains details of the fill permit function fillLimitOrderByProtocol( - LimitOrderLibEIP712.Order calldata _order, + PionexContractLibEIP712.Order calldata _order, bytes calldata _orderMakerSig, ProtocolParams calldata _params, CoordinatorParams calldata _crdParams @@ -137,5 +137,5 @@ interface IPionexContract is IStrategyBase { /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled /// @param _cancelMakerSig The cancelling signature signed by maker - function cancelLimitOrder(LimitOrderLibEIP712.Order calldata _order, bytes calldata _cancelMakerSig) external; + function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelMakerSig) external; } diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/PionexContractLibEIP712.sol index 23556531..b98c0b09 100644 --- a/contracts/utils/PionexContractLibEIP712.sol +++ b/contracts/utils/PionexContractLibEIP712.sol @@ -56,6 +56,7 @@ library PionexContractLibEIP712 { bytes32 orderHash; // EIP712 hash address taker; address recipient; + uint256 makerTokenAmount; uint256 takerTokenAmount; uint256 takerSalt; uint64 expiry; @@ -68,6 +69,7 @@ library PionexContractLibEIP712 { "bytes32 orderHash,", "address taker,", "address recipient,", + "uint256 makerTokenAmount,", "uint256 takerTokenAmount,", "uint256 takerSalt,", "uint64 expiry", @@ -75,10 +77,10 @@ library PionexContractLibEIP712 { ) ); */ - bytes32 private constant FILL_TYPEHASH = 0x4ef294060cea2f973f7fe2a6d78624328586118efb1c4d640855aac3ba70e9c9; + bytes32 private constant FILL_TYPEHASH = 0x205396fa1b68e5a32114505757ea3414ca863515127de397dd50fc79342ce917; function _getFillStructHash(Fill memory _fill) internal pure returns (bytes32) { - return keccak256(abi.encode(FILL_TYPEHASH, _fill.orderHash, _fill.taker, _fill.recipient, _fill.takerTokenAmount, _fill.takerSalt, _fill.expiry)); + return keccak256(abi.encode(FILL_TYPEHASH, _fill.orderHash, _fill.taker, _fill.recipient, _fill.makerTokenAmount, _fill.takerTokenAmount, _fill.takerSalt, _fill.expiry)); } struct AllowFill { From fc1e0cc83ca536d26b74877323f7187c8ce08cc5 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 18:22:31 +0800 Subject: [PATCH 05/41] Copy LimitOrder -> PionexContract --- contracts/PionexContract.sol | 588 +++++++++++++++++++++++++++++++++++ 1 file changed, 588 insertions(+) create mode 100644 contracts/PionexContract.sol diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol new file mode 100644 index 00000000..67810d17 --- /dev/null +++ b/contracts/PionexContract.sol @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; +pragma abicoder v2; + +import "@openzeppelin/contracts/math/Math.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; + +import "./interfaces/IPionexContract.sol"; +import "./interfaces/IPermanentStorage.sol"; +import "./interfaces/ISpender.sol"; +import "./interfaces/IWeth.sol"; +import "./utils/StrategyBase.sol"; +import "./utils/BaseLibEIP712.sol"; +import "./utils/LibConstant.sol"; +import "./utils/LibUniswapV2.sol"; +import "./utils/LibUniswapV3.sol"; +import "./utils/LibOrderStorage.sol"; +import "./utils/PionexContractLibEIP712.sol"; +import "./utils/SignatureValidator.sol"; + +/// @title PionexContract Contract +/// @author imToken Labs +contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { + using SafeMath for uint256; + using SafeERC20 for IERC20; + + uint256 public immutable factorActivateDelay; + + // AMM + address public immutable uniswapV3RouterAddress; + address public immutable sushiswapRouterAddress; + + // Below are the variables which consume storage slots. + address public coordinator; + address public feeCollector; + + // Factors + uint256 public factorsTimeLock; + uint16 public makerFeeFactor = 0; + uint16 public pendingMakerFeeFactor; + uint16 public takerFeeFactor = 0; + uint16 public pendingTakerFeeFactor; + uint16 public profitFeeFactor = 0; + uint16 public pendingProfitFeeFactor; + + constructor( + address _owner, + address _userProxy, + address _weth, + address _permStorage, + address _spender, + address _coordinator, + uint256 _factorActivateDelay, + address _uniswapV3RouterAddress, + address _sushiswapRouterAddress, + address _feeCollector + ) StrategyBase(_owner, _userProxy, _weth, _permStorage, _spender) { + coordinator = _coordinator; + factorActivateDelay = _factorActivateDelay; + uniswapV3RouterAddress = _uniswapV3RouterAddress; + sushiswapRouterAddress = _sushiswapRouterAddress; + feeCollector = _feeCollector; + } + + receive() external payable {} + + /// @notice Only owner can call + /// @param _newCoordinator The new address of coordinator + function upgradeCoordinator(address _newCoordinator) external onlyOwner { + require(_newCoordinator != address(0), "LimitOrder: coordinator can not be zero address"); + coordinator = _newCoordinator; + + emit UpgradeCoordinator(_newCoordinator); + } + + /// @notice Only owner can call + /// @param _makerFeeFactor The new fee factor for maker + /// @param _takerFeeFactor The new fee factor for taker + /// @param _profitFeeFactor The new fee factor for relayer profit + function setFactors( + uint16 _makerFeeFactor, + uint16 _takerFeeFactor, + uint16 _profitFeeFactor + ) external onlyOwner { + require(_makerFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid maker fee factor"); + require(_takerFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid taker fee factor"); + require(_profitFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid profit fee factor"); + + pendingMakerFeeFactor = _makerFeeFactor; + pendingTakerFeeFactor = _takerFeeFactor; + pendingProfitFeeFactor = _profitFeeFactor; + + factorsTimeLock = block.timestamp + factorActivateDelay; + } + + /// @notice Only owner can call + function activateFactors() external onlyOwner { + require(factorsTimeLock != 0, "LimitOrder: no pending fee factors"); + require(block.timestamp >= factorsTimeLock, "LimitOrder: fee factors timelocked"); + factorsTimeLock = 0; + makerFeeFactor = pendingMakerFeeFactor; + takerFeeFactor = pendingTakerFeeFactor; + profitFeeFactor = pendingProfitFeeFactor; + pendingMakerFeeFactor = 0; + pendingTakerFeeFactor = 0; + pendingProfitFeeFactor = 0; + + emit FactorsUpdated(makerFeeFactor, takerFeeFactor, profitFeeFactor); + } + + /// @notice Only owner can call + /// @param _newFeeCollector The new address of fee collector + function setFeeCollector(address _newFeeCollector) external onlyOwner { + require(_newFeeCollector != address(0), "LimitOrder: fee collector can not be zero address"); + feeCollector = _newFeeCollector; + + emit SetFeeCollector(_newFeeCollector); + } + + /// @inheritdoc IPionexContract + function fillLimitOrderByTrader( + PionexContractLibEIP712.Order calldata _order, + bytes calldata _orderMakerSig, + TraderParams calldata _params, + CoordinatorParams calldata _crdParams + ) external override onlyUserProxy nonReentrant returns (uint256, uint256) { + bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); + + _validateOrder(_order, orderHash, _orderMakerSig); + bytes32 allowFillHash = _validateFillPermission(orderHash, _params.takerTokenAmount, _params.taker, _crdParams); + _validateOrderTaker(_order, _params.taker); + + { + PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ + orderHash: orderHash, + taker: _params.taker, + recipient: _params.recipient, + takerTokenAmount: _params.takerTokenAmount, + takerSalt: _params.salt, + expiry: _params.expiry + }); + _validateTraderFill(fill, _params.takerSig); + } + + (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrder(_order, orderHash, _params.takerTokenAmount); + + uint256 makerTokenOut = _settleForTrader( + TraderSettlement({ + orderHash: orderHash, + allowFillHash: allowFillHash, + trader: _params.taker, + recipient: _params.recipient, + maker: _order.maker, + taker: _order.taker, + makerToken: _order.makerToken, + takerToken: _order.takerToken, + makerTokenAmount: makerTokenAmount, + takerTokenAmount: takerTokenAmount, + remainingAmount: remainingAmount + }) + ); + + _recordOrderFilled(orderHash, takerTokenAmount); + + return (takerTokenAmount, makerTokenOut); + } + + function _validateTraderFill(PionexContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { + require(_fill.expiry > uint64(block.timestamp), "LimitOrder: Fill request is expired"); + require(_fill.recipient != address(0), "LimitOrder: recipient can not be zero address"); + + bytes32 fillHash = getEIP712Hash(PionexContractLibEIP712._getFillStructHash(_fill)); + require(isValidSignature(_fill.taker, fillHash, bytes(""), _fillTakerSig), "LimitOrder: Fill is not signed by taker"); + + // Set fill seen to avoid replay attack. + // PermanentStorage would throw error if fill is already seen. + permStorage.setLimitOrderTransactionSeen(fillHash); + } + + function _validateFillPermission( + bytes32 _orderHash, + uint256 _fillAmount, + address _executor, + CoordinatorParams memory _crdParams + ) internal returns (bytes32) { + require(_crdParams.expiry > uint64(block.timestamp), "LimitOrder: Fill permission is expired"); + + bytes32 allowFillHash = getEIP712Hash( + PionexContractLibEIP712._getAllowFillStructHash( + PionexContractLibEIP712.AllowFill({ + orderHash: _orderHash, + executor: _executor, + fillAmount: _fillAmount, + salt: _crdParams.salt, + expiry: _crdParams.expiry + }) + ) + ); + require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "LimitOrder: AllowFill is not signed by coordinator"); + + // Set allow fill seen to avoid replay attack + // PermanentStorage would throw error if allow fill is already seen. + permStorage.setLimitOrderAllowFillSeen(allowFillHash); + + return allowFillHash; + } + + struct TraderSettlement { + bytes32 orderHash; + bytes32 allowFillHash; + address trader; + address recipient; + address maker; + address taker; + IERC20 makerToken; + IERC20 takerToken; + uint256 makerTokenAmount; + uint256 takerTokenAmount; + uint256 remainingAmount; + } + + function _settleForTrader(TraderSettlement memory _settlement) internal returns (uint256) { + // memory cache + ISpender _spender = spender; + address _feeCollector = feeCollector; + + // Calculate maker fee (maker receives taker token so fee is charged in taker token) + uint256 takerTokenFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); + uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(takerTokenFee); + + // Calculate taker fee (taker receives maker token so fee is charged in maker token) + uint256 makerTokenFee = _mulFactor(_settlement.makerTokenAmount, takerFeeFactor); + uint256 makerTokenForTrader = _settlement.makerTokenAmount.sub(makerTokenFee); + + // trader -> maker + _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _settlement.maker, takerTokenForMaker); + + // maker -> recipient + _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _settlement.recipient, makerTokenForTrader); + + // Collect maker fee (charged in taker token) + if (takerTokenFee > 0) { + _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _feeCollector, takerTokenFee); + } + // Collect taker fee (charged in maker token) + if (makerTokenFee > 0) { + _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _feeCollector, makerTokenFee); + } + + // bypass stack too deep error + _emitLimitOrderFilledByTrader( + LimitOrderFilledByTraderParams({ + orderHash: _settlement.orderHash, + maker: _settlement.maker, + taker: _settlement.trader, + allowFillHash: _settlement.allowFillHash, + recipient: _settlement.recipient, + makerToken: address(_settlement.makerToken), + takerToken: address(_settlement.takerToken), + makerTokenFilledAmount: _settlement.makerTokenAmount, + takerTokenFilledAmount: _settlement.takerTokenAmount, + remainingAmount: _settlement.remainingAmount, + makerTokenFee: makerTokenFee, + takerTokenFee: takerTokenFee + }) + ); + + return makerTokenForTrader; + } + + /// @inheritdoc IPionexContract + function fillLimitOrderByProtocol( + PionexContractLibEIP712.Order calldata _order, + bytes calldata _orderMakerSig, + ProtocolParams calldata _params, + CoordinatorParams calldata _crdParams + ) external override onlyUserProxy nonReentrant returns (uint256) { + bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); + + _validateOrder(_order, orderHash, _orderMakerSig); + bytes32 allowFillHash = _validateFillPermission(orderHash, _params.takerTokenAmount, tx.origin, _crdParams); + + address protocolAddress = _getProtocolAddress(_params.protocol); + _validateOrderTaker(_order, protocolAddress); + + (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrder(_order, orderHash, _params.takerTokenAmount); + + uint256 relayerTakerTokenProfit = _settleForProtocol( + ProtocolSettlement({ + orderHash: orderHash, + allowFillHash: allowFillHash, + protocolAddress: protocolAddress, + protocol: _params.protocol, + data: _params.data, + relayer: tx.origin, + profitRecipient: _params.profitRecipient, + maker: _order.maker, + taker: _order.taker, + makerToken: _order.makerToken, + takerToken: _order.takerToken, + makerTokenAmount: makerTokenAmount, + takerTokenAmount: takerTokenAmount, + remainingAmount: remainingAmount, + protocolOutMinimum: _params.protocolOutMinimum, + expiry: _params.expiry + }) + ); + + _recordOrderFilled(orderHash, takerTokenAmount); + + return relayerTakerTokenProfit; + } + + function _getProtocolAddress(Protocol protocol) internal view returns (address) { + if (protocol == Protocol.UniswapV3) { + return uniswapV3RouterAddress; + } + if (protocol == Protocol.Sushiswap) { + return sushiswapRouterAddress; + } + revert("LimitOrder: Unknown protocol"); + } + + struct ProtocolSettlement { + bytes32 orderHash; + bytes32 allowFillHash; + address protocolAddress; + Protocol protocol; + bytes data; + address relayer; + address profitRecipient; + address maker; + address taker; + IERC20 makerToken; + IERC20 takerToken; + uint256 makerTokenAmount; + uint256 takerTokenAmount; + uint256 remainingAmount; + uint256 protocolOutMinimum; + uint64 expiry; + } + + function _settleForProtocol(ProtocolSettlement memory _settlement) internal returns (uint256) { + require(_settlement.profitRecipient != address(0), "LimitOrder: profitRecipient can not be zero address"); + + // Collect maker token from maker in order to swap through protocol + spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), address(this), _settlement.makerTokenAmount); + + uint256 takerTokenOut = _swapByProtocol(_settlement); + + require(takerTokenOut >= _settlement.takerTokenAmount, "LimitOrder: Insufficient token amount out from protocol"); + + uint256 ammOutputExtra = takerTokenOut.sub(_settlement.takerTokenAmount); + uint256 relayerTakerTokenProfitFee = _mulFactor(ammOutputExtra, profitFeeFactor); + uint256 relayerTakerTokenProfit = ammOutputExtra.sub(relayerTakerTokenProfitFee); + // Distribute taker token profit to profit recipient assigned by relayer + _settlement.takerToken.safeTransfer(_settlement.profitRecipient, relayerTakerTokenProfit); + + // Calculate maker fee (maker receives taker token so fee is charged in taker token) + uint256 takerTokenFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); + uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(takerTokenFee); + + // Distribute taker token to maker + _settlement.takerToken.safeTransfer(_settlement.maker, takerTokenForMaker); + + // Collect fee in taker token if any + uint256 feeTotal = takerTokenFee.add(relayerTakerTokenProfitFee); + if (feeTotal > 0) { + _settlement.takerToken.safeTransfer(feeCollector, feeTotal); + } + + // Bypass stack too deep error + _emitLimitOrderFilledByProtocol( + LimitOrderFilledByProtocolParams({ + orderHash: _settlement.orderHash, + maker: _settlement.maker, + taker: _settlement.protocolAddress, + allowFillHash: _settlement.allowFillHash, + relayer: _settlement.relayer, + profitRecipient: _settlement.profitRecipient, + makerToken: address(_settlement.makerToken), + takerToken: address(_settlement.takerToken), + makerTokenFilledAmount: _settlement.makerTokenAmount, + takerTokenFilledAmount: _settlement.takerTokenAmount, + remainingAmount: _settlement.remainingAmount, + makerTokenFee: 0, + takerTokenFee: takerTokenFee, + relayerTakerTokenProfit: relayerTakerTokenProfit, + relayerTakerTokenProfitFee: relayerTakerTokenProfitFee + }) + ); + + return relayerTakerTokenProfit; + } + + function _swapByProtocol(ProtocolSettlement memory _settlement) internal returns (uint256 amountOut) { + _settlement.makerToken.safeApprove(_settlement.protocolAddress, _settlement.makerTokenAmount); + + // UniswapV3 + if (_settlement.protocol == Protocol.UniswapV3) { + amountOut = LibUniswapV3.exactInput( + _settlement.protocolAddress, + LibUniswapV3.ExactInputParams({ + tokenIn: address(_settlement.makerToken), + tokenOut: address(_settlement.takerToken), + path: _settlement.data, + recipient: address(this), + deadline: _settlement.expiry, + amountIn: _settlement.makerTokenAmount, + amountOutMinimum: _settlement.protocolOutMinimum + }) + ); + } else { + // Sushiswap + address[] memory path = abi.decode(_settlement.data, (address[])); + amountOut = LibUniswapV2.swapExactTokensForTokens( + _settlement.protocolAddress, + LibUniswapV2.SwapExactTokensForTokensParams({ + tokenIn: address(_settlement.makerToken), + tokenInAmount: _settlement.makerTokenAmount, + tokenOut: address(_settlement.takerToken), + tokenOutAmountMin: _settlement.protocolOutMinimum, + path: path, + to: address(this), + deadline: _settlement.expiry + }) + ); + } + + _settlement.makerToken.safeApprove(_settlement.protocolAddress, 0); + } + + /// @inheritdoc IPionexContract + function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderMakerSig) external override onlyUserProxy nonReentrant { + require(_order.expiry > uint64(block.timestamp), "LimitOrder: Order is expired"); + bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); + bool isCancelled = LibOrderStorage.getStorage().orderHashToCancelled[orderHash]; + require(!isCancelled, "LimitOrder: Order is cancelled already"); + { + PionexContractLibEIP712.Order memory cancelledOrder = _order; + cancelledOrder.takerTokenAmount = 0; + + bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); + require(isValidSignature(_order.maker, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "LimitOrder: Cancel request is not signed by maker"); + } + + // Set cancelled state to storage + LibOrderStorage.getStorage().orderHashToCancelled[orderHash] = true; + emit OrderCancelled(orderHash, _order.maker); + } + + /* order utils */ + + function _validateOrder( + PionexContractLibEIP712.Order memory _order, + bytes32 _orderHash, + bytes memory _orderMakerSig + ) internal view { + require(_order.expiry > uint64(block.timestamp), "LimitOrder: Order is expired"); + bool isCancelled = LibOrderStorage.getStorage().orderHashToCancelled[_orderHash]; + require(!isCancelled, "LimitOrder: Order is cancelled"); + + require(isValidSignature(_order.maker, _orderHash, bytes(""), _orderMakerSig), "LimitOrder: Order is not signed by maker"); + } + + function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _taker) internal pure { + if (_order.taker != address(0)) { + require(_order.taker == _taker, "LimitOrder: Order cannot be filled by this taker"); + } + } + + function _quoteOrder( + PionexContractLibEIP712.Order memory _order, + bytes32 _orderHash, + uint256 _takerTokenAmount + ) + internal + view + returns ( + uint256, + uint256, + uint256 + ) + { + uint256 takerTokenFilledAmount = LibOrderStorage.getStorage().orderHashToTakerTokenFilledAmount[_orderHash]; + + require(takerTokenFilledAmount < _order.takerTokenAmount, "LimitOrder: Order is filled"); + + uint256 takerTokenFillableAmount = _order.takerTokenAmount.sub(takerTokenFilledAmount); + uint256 takerTokenQuota = Math.min(_takerTokenAmount, takerTokenFillableAmount); + uint256 makerTokenQuota = takerTokenQuota.mul(_order.makerTokenAmount).div(_order.takerTokenAmount); + uint256 remainingAfterFill = takerTokenFillableAmount.sub(takerTokenQuota); + + require(makerTokenQuota != 0 && takerTokenQuota != 0, "LimitOrder: zero token amount"); + return (makerTokenQuota, takerTokenQuota, remainingAfterFill); + } + + function _recordOrderFilled(bytes32 _orderHash, uint256 _takerTokenAmount) internal { + LibOrderStorage.Storage storage stor = LibOrderStorage.getStorage(); + uint256 takerTokenFilledAmount = stor.orderHashToTakerTokenFilledAmount[_orderHash]; + stor.orderHashToTakerTokenFilledAmount[_orderHash] = takerTokenFilledAmount.add(_takerTokenAmount); + } + + /* math utils */ + + function _mulFactor(uint256 amount, uint256 factor) internal pure returns (uint256) { + return amount.mul(factor).div(LibConstant.BPS_MAX); + } + + /* event utils */ + + struct LimitOrderFilledByTraderParams { + bytes32 orderHash; + address maker; + address taker; + bytes32 allowFillHash; + address recipient; + address makerToken; + address takerToken; + uint256 makerTokenFilledAmount; + uint256 takerTokenFilledAmount; + uint256 remainingAmount; + uint256 makerTokenFee; + uint256 takerTokenFee; + } + + function _emitLimitOrderFilledByTrader(LimitOrderFilledByTraderParams memory _params) internal { + emit LimitOrderFilledByTrader( + _params.orderHash, + _params.maker, + _params.taker, + _params.allowFillHash, + _params.recipient, + FillReceipt({ + makerToken: _params.makerToken, + takerToken: _params.takerToken, + makerTokenFilledAmount: _params.makerTokenFilledAmount, + takerTokenFilledAmount: _params.takerTokenFilledAmount, + remainingAmount: _params.remainingAmount, + makerTokenFee: _params.makerTokenFee, + takerTokenFee: _params.takerTokenFee + }) + ); + } + + struct LimitOrderFilledByProtocolParams { + bytes32 orderHash; + address maker; + address taker; + bytes32 allowFillHash; + address relayer; + address profitRecipient; + address makerToken; + address takerToken; + uint256 makerTokenFilledAmount; + uint256 takerTokenFilledAmount; + uint256 remainingAmount; + uint256 makerTokenFee; + uint256 takerTokenFee; + uint256 relayerTakerTokenProfit; + uint256 relayerTakerTokenProfitFee; + } + + function _emitLimitOrderFilledByProtocol(LimitOrderFilledByProtocolParams memory _params) internal { + emit LimitOrderFilledByProtocol( + _params.orderHash, + _params.maker, + _params.taker, + _params.allowFillHash, + _params.relayer, + _params.profitRecipient, + FillReceipt({ + makerToken: _params.makerToken, + takerToken: _params.takerToken, + makerTokenFilledAmount: _params.makerTokenFilledAmount, + takerTokenFilledAmount: _params.takerTokenFilledAmount, + remainingAmount: _params.remainingAmount, + makerTokenFee: _params.makerTokenFee, + takerTokenFee: _params.takerTokenFee + }), + _params.relayerTakerTokenProfit, + _params.relayerTakerTokenProfitFee + ); + } +} From 1f8b067d09d8f91f13af9fe117b068696a7b5c0b Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 18:23:35 +0800 Subject: [PATCH 06/41] Check takerToken/makerToken ratio in fillLimitOrderByTrader --- contracts/PionexContract.sol | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 67810d17..d2485f58 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -21,7 +21,9 @@ import "./utils/LibOrderStorage.sol"; import "./utils/PionexContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; -/// @title PionexContract Contract +/// @title Pionex Contract +/// @notice Modified from LimitOrder contract. Maker is user, taker is Pionex agent. +/// @notice Order can be filled as long as the provided takerToken/makerToken ratio is better than or equal to maker's specfied takerToken/makerToken ratio. /// @author imToken Labs contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { using SafeMath for uint256; @@ -133,11 +135,16 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes32 allowFillHash = _validateFillPermission(orderHash, _params.takerTokenAmount, _params.taker, _crdParams); _validateOrderTaker(_order, _params.taker); + // Check provided takerToken/makerToken ratio is better than or equal to maker's specfied takerToken/makerToken ratio + // -> _params.takerTokenAmount/_params.makerTokenAmount >= _order.takerTokenAmount/_order.makerTokenAmount + require(_params.takerTokenAmount.mul(_order.makerTokenAmount) >= _order.takerTokenAmount.mul(_params.makerTokenAmount), "LimitOrder: taker/maker token ratio not good enough"); + { PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ orderHash: orderHash, taker: _params.taker, recipient: _params.recipient, + makerTokenAmount: _params.makerTokenAmount, takerTokenAmount: _params.takerTokenAmount, takerSalt: _params.salt, expiry: _params.expiry @@ -146,6 +153,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrder(_order, orderHash, _params.takerTokenAmount); + // Adjust makerTokenAmount according to the provided takerToken/makerToken ratio + makerTokenAmount = takerTokenAmount.mul(_params.makerTokenAmount).div(_params.takerTokenAmount); uint256 makerTokenOut = _settleForTrader( TraderSettlement({ From 3f7978aef040e58fc7c05e953d5538ff713a38d3 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 18:28:58 +0800 Subject: [PATCH 07/41] Copy LimitOrder tests -> PionexContract tests --- test/forkMainnet/PionexContract.t.sol | 1483 +++++++++++++++++++++++++ 1 file changed, 1483 insertions(+) create mode 100644 test/forkMainnet/PionexContract.t.sol diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol new file mode 100644 index 00000000..9ed14980 --- /dev/null +++ b/test/forkMainnet/PionexContract.t.sol @@ -0,0 +1,1483 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; +pragma abicoder v2; + +import "@openzeppelin/contracts/cryptography/ECDSA.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; + +import "contracts/PionexContract.sol"; +import "contracts/interfaces/IPionexContract.sol"; +import "contracts/utils/SignatureValidator.sol"; +import "contracts/utils/PionexContractLibEIP712.sol"; +import "contracts/utils/LibConstant.sol"; + +import "test/mocks/MockERC1271Wallet.sol"; +import "test/utils/BalanceSnapshot.sol"; +import "test/utils/StrategySharedSetup.sol"; +import "test/utils/UniswapV3Util.sol"; +import "test/utils/SushiswapUtil.sol"; +import { computeMainnetEIP712DomainSeparator, getEIP712Hash } from "test/utils/Sig.sol"; + +contract PionexContractTest is StrategySharedSetup { + using SafeMath for uint256; + using BalanceSnapshot for BalanceSnapshot.Snapshot; + + event LimitOrderFilledByTrader( + bytes32 indexed orderHash, + address indexed maker, + address indexed taker, + bytes32 allowFillHash, + address recipient, + IPionexContract.FillReceipt fillReceipt + ); + event LimitOrderFilledByProtocol( + bytes32 indexed orderHash, + address indexed maker, + address indexed taker, + bytes32 allowFillHash, + address relayer, + address profitRecipient, + IPionexContract.FillReceipt fillReceipt, + uint256 relayerTakerTokenProfit, + uint256 relayerTakerTokenProfitFee + ); + + uint256 userPrivateKey = uint256(1); + uint256 makerPrivateKey = uint256(2); + uint256 coordinatorPrivateKey = uint256(3); + + address user = vm.addr(userPrivateKey); + address maker = vm.addr(makerPrivateKey); + address coordinator = vm.addr(coordinatorPrivateKey); + address owner = makeAddr("owner"); + address feeCollector = makeAddr("feeCollector"); + address receiver = makeAddr("receiver"); + MockERC1271Wallet mockERC1271Wallet = new MockERC1271Wallet(user); + address[] wallet = [user, maker, coordinator, address(mockERC1271Wallet)]; + address[] allowanceAddrs; + + address[] DEFAULT_AMM_PATH; + PionexContractLibEIP712.Order DEFAULT_ORDER; + bytes32 DEFAULT_ORDER_HASH; + bytes DEFAULT_ORDER_MAKER_SIG; + PionexContractLibEIP712.Fill DEFAULT_FILL; + PionexContractLibEIP712.AllowFill DEFAULT_ALLOW_FILL; + IPionexContract.TraderParams DEFAULT_TRADER_PARAMS; + IPionexContract.ProtocolParams DEFAULT_PROTOCOL_PARAMS; + IPionexContract.CoordinatorParams DEFAULT_CRD_PARAMS; + + PionexContract pionexContract; + uint64 DEADLINE = uint64(block.timestamp + 2 days); + uint256 FACTORSDEALY = 12 hours; + + // effectively a "beforeEach" block + function setUp() public { + // Setup + setUpSystemContracts(); + + DEFAULT_AMM_PATH = [address(dai), address(usdt)]; + allowanceAddrs = DEFAULT_AMM_PATH; + + // Default params + DEFAULT_ORDER = PionexContractLibEIP712.Order( + dai, // makerToken + usdt, // takerToken + 100 * 1e18, // makerTokenAmount + 90 * 1e6, // takerTokenAmount + maker, // maker + address(0), // taker + uint256(1001), // salt + DEADLINE // expiry + ); + DEFAULT_ORDER_HASH = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); + DEFAULT_ORDER_MAKER_SIG = _signOrder(makerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); + DEFAULT_FILL = PionexContractLibEIP712.Fill(DEFAULT_ORDER_HASH, user, receiver, DEFAULT_ORDER.makerTokenAmount, DEFAULT_ORDER.takerTokenAmount, uint256(1002), DEADLINE); + DEFAULT_TRADER_PARAMS = IPionexContract.TraderParams( + user, // taker + receiver, // recipient + DEFAULT_FILL.makerTokenAmount, // makerTokenAmount + DEFAULT_FILL.takerTokenAmount, // takerTokenAmount + DEFAULT_FILL.takerSalt, // salt + DEADLINE, // expiry + _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // takerSig + ); + DEFAULT_PROTOCOL_PARAMS = IPionexContract.ProtocolParams( + IPionexContract.Protocol.UniswapV3, // protocol + hex"6b175474e89094c44da98b954eedeac495271d0f0001f4dac17f958d2ee523a2206206994597c13d831ec7", // Uniswap v3 protocol data + receiver, // profitRecipient + DEFAULT_FILL.takerTokenAmount, // takerTokenAmount + 0, // protocolOutMinimum + DEADLINE // expiry + ); + DEFAULT_ALLOW_FILL = PionexContractLibEIP712.AllowFill( + DEFAULT_ORDER_HASH, // orderHash + user, // executor + DEFAULT_FILL.takerTokenAmount, // fillAmount + uint256(1003), // salt + DEADLINE // expiry + ); + DEFAULT_CRD_PARAMS = IPionexContract.CoordinatorParams( + _signAllowFill(coordinatorPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712), + DEFAULT_ALLOW_FILL.salt, + DEFAULT_ALLOW_FILL.expiry + ); + + // Deal 100 ETH to each account + dealWallet(wallet, 100 ether); + // Set token balance and approve + tokens = [weth, usdt, dai]; + setEOABalanceAndApprove(user, tokens, 10000); + setEOABalanceAndApprove(maker, tokens, 10000); + setEOABalanceAndApprove(address(mockERC1271Wallet), tokens, 10000); + + // Label addresses for easier debugging + vm.label(user, "User"); + vm.label(maker, "Maker"); + vm.label(coordinator, "Coordinator"); + vm.label(receiver, "Receiver"); + vm.label(feeCollector, "FeeCollector"); + vm.label(address(this), "TestingContract"); + vm.label(address(pionexContract), "LimitOrderContract"); + vm.label(address(mockERC1271Wallet), "MockERC1271Wallet"); + } + + function _deployStrategyAndUpgrade() internal override returns (address) { + pionexContract = new PionexContract( + owner, + address(userProxy), + address(weth), + address(permanentStorage), + address(spender), + coordinator, + FACTORSDEALY, + UNISWAP_V3_ADDRESS, + SUSHISWAP_ADDRESS, + feeCollector + ); + // Setup + userProxy.upgradeLimitOrder(address(pionexContract), true); + vm.startPrank(psOperator, psOperator); + permanentStorage.upgradeLimitOrder(address(pionexContract)); + permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(pionexContract), true); + permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(pionexContract), true); + vm.stopPrank(); + return address(pionexContract); + } + + function _setupDeployedStrategy() internal override { + pionexContract = PionexContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); + + // prank owner and update coordinator address + owner = pionexContract.owner(); + vm.prank(owner, owner); + pionexContract.upgradeCoordinator(coordinator); + // update local feeCollector address + feeCollector = pionexContract.feeCollector(); + } + + /********************************* + * Test: setup * + *********************************/ + + function testSetupLimitOrder() public { + assertEq(pionexContract.owner(), owner); + assertEq(pionexContract.coordinator(), coordinator); + assertEq(pionexContract.userProxy(), address(userProxy)); + assertEq(address(pionexContract.spender()), address(spender)); + assertEq(address(pionexContract.permStorage()), address(permanentStorage)); + assertEq(address(pionexContract.weth()), address(weth)); + assertEq(pionexContract.uniswapV3RouterAddress(), UNISWAP_V3_ADDRESS); + assertEq(pionexContract.sushiswapRouterAddress(), SUSHISWAP_ADDRESS); + + assertEq(uint256(pionexContract.makerFeeFactor()), 0); + assertEq(uint256(pionexContract.takerFeeFactor()), 0); + assertEq(uint256(pionexContract.profitFeeFactor()), 0); + } + + /********************************* + * Test: transferOwnership * + *********************************/ + + function testCannotTransferOwnershipByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.nominateNewOwner(user); + } + + function testCannotAcceptOwnershipIfNotNominated() public { + vm.expectRevert("not nominated"); + vm.prank(user); + pionexContract.acceptOwnership(); + } + + function testTransferOwnership() public { + vm.prank(owner, owner); + pionexContract.nominateNewOwner(user); + vm.prank(user); + pionexContract.acceptOwnership(); + assertEq(pionexContract.owner(), user); + } + + /********************************* + * Test: upgradeSpender * + *********************************/ + + function testCannotUpgradeSpenderByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.upgradeSpender(user); + } + + function testCannotUpgradeSpenderToZeroAddr() public { + vm.expectRevert("Strategy: spender can not be zero address"); + vm.prank(owner, owner); + pionexContract.upgradeSpender(address(0)); + } + + function testUpgradeSpender() public { + vm.prank(owner, owner); + pionexContract.upgradeSpender(user); + assertEq(address(pionexContract.spender()), user); + } + + /********************************* + * Test: upgradeCoordinator * + *********************************/ + + function testCannotUpgradeCoordinatorByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.upgradeCoordinator(user); + } + + function testCannotUpgradeCoordinatorToZeroAddr() public { + vm.expectRevert("LimitOrder: coordinator can not be zero address"); + vm.prank(owner, owner); + pionexContract.upgradeCoordinator(address(0)); + } + + function testUpgradeCoordinator() public { + vm.prank(owner, owner); + pionexContract.upgradeCoordinator(user); + assertEq(address(pionexContract.coordinator()), user); + } + + /********************************* + * Test: set/close allowance * + *********************************/ + + function testCannotSetAllowanceByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + } + + function testCannotCloseAllowanceByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + } + + function testSetAndCloseAllowance() public { + // Set allowance + vm.prank(owner, owner); + pionexContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + assertEq(usdt.allowance(address(pionexContract), address(allowanceTarget)), LibConstant.MAX_UINT); + assertEq(dai.allowance(address(pionexContract), address(allowanceTarget)), LibConstant.MAX_UINT); + + // Close allowance + vm.prank(owner, owner); + pionexContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + assertEq(usdt.allowance(address(pionexContract), address(allowanceTarget)), 0); + assertEq(dai.allowance(address(pionexContract), address(allowanceTarget)), 0); + } + + /********************************* + * Test: depoitETH * + *********************************/ + + function testCannotDepositETHByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.depositETH(); + } + + function testDepositETH() public { + // Send ether to limit order contract + uint256 amount = 1234 ether; + deal(address(pionexContract), amount); + vm.prank(owner, owner); + pionexContract.depositETH(); + assertEq(weth.balanceOf(address(pionexContract)), amount); + } + + /********************************* + * Test: setFactors * + *********************************/ + + function testCannotSetFactorsIfLargerThanBpsMax() public { + vm.expectRevert("LimitOrder: Invalid maker fee factor"); + vm.prank(owner, owner); + pionexContract.setFactors(LibConstant.BPS_MAX + 1, 1, 1); + + vm.expectRevert("LimitOrder: Invalid taker fee factor"); + vm.prank(owner, owner); + pionexContract.setFactors(1, LibConstant.BPS_MAX + 1, 1); + + vm.expectRevert("LimitOrder: Invalid profit fee factor"); + vm.prank(owner, owner); + pionexContract.setFactors(1, 1, LibConstant.BPS_MAX + 1); + } + + function testSetFactors() public { + vm.startPrank(owner, owner); + pionexContract.setFactors(1, 2, 3); + // fee factors should stay same before new ones activate + assertEq(uint256(pionexContract.makerFeeFactor()), 0); + assertEq(uint256(pionexContract.takerFeeFactor()), 0); + assertEq(uint256(pionexContract.profitFeeFactor()), 0); + vm.warp(block.timestamp + pionexContract.factorActivateDelay()); + + // fee factors should be updated now + pionexContract.activateFactors(); + vm.stopPrank(); + assertEq(uint256(pionexContract.makerFeeFactor()), 1); + assertEq(uint256(pionexContract.takerFeeFactor()), 2); + assertEq(uint256(pionexContract.profitFeeFactor()), 3); + } + + /********************************* + * Test: setFeeCollector * + *********************************/ + + function testCannotSetFeeCollectorByNotOwner() public { + vm.expectRevert("not owner"); + vm.prank(user); + pionexContract.setFeeCollector(feeCollector); + } + + function testCannotSetFeeCollectorToZeroAddr() public { + vm.expectRevert("LimitOrder: fee collector can not be zero address"); + vm.prank(owner, owner); + pionexContract.setFeeCollector(address(0)); + } + + function testSetFeeCollector() public { + vm.prank(owner, owner); + pionexContract.setFeeCollector(user); + assertEq(address(pionexContract.feeCollector()), user); + } + + /********************************* + * Test: fillLimitOrderByTrader * + *********************************/ + + function testCannotFillByTraderIfNotFromUserProxy() public { + vm.expectRevert("Strategy: not from UserProxy contract"); + // Call limit order contract directly will get reverted since msg.sender is not from UserProxy + pionexContract.fillLimitOrderByTrader(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + } + + function testCannotFillFilledOrderByTrader() public { + // Fullly fill the default order first + bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload1); + + // Try to fill the default order, should fail + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.takerSalt = uint256(8001); + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.salt = fill.takerSalt; + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.salt = uint256(8002); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + crdParams.salt = allowFill.salt; + + bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.expectRevert("LimitOrder: Order is filled"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload2); + } + + function testCannotFillExpiredOrderByTrader() public { + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.expiry = uint64(block.timestamp - 1); + + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = orderHash; + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); + vm.expectRevert("LimitOrder: Order is expired"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithWrongMakerSig() public { + bytes memory wrongMakerSig = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: Order is not signed by maker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithWrongTakerSig() public { + IPionexContract.TraderParams memory wrongTraderParams = DEFAULT_TRADER_PARAMS; + wrongTraderParams.takerSig = _signFill(makerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: Fill is not signed by taker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithTakerOtherThanOrderSpecified() public { + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + // order specify taker address + order.taker = coordinator; + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = orderHash; + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + // user try to fill this order + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); + vm.expectRevert("LimitOrder: Order cannot be filled by this taker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithExpiredFill() public { + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.expiry = uint64(block.timestamp - 1); + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.expiry = fill.expiry; + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: Fill request is expired"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotReplayFill() public { + // Fill with DEFAULT_FILL + bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload1); + + // Try to fill with same fill request with differnt allowFill (otherwise will revert by dup allowFill) + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.salt = uint256(9001); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + crdParams.salt = allowFill.salt; + + bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); + vm.expectRevert("PermanentStorage: transaction seen before"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload2); + } + + function testCannotFillByTraderWithAlteredTakerTokenAmount() public { + // Replace takerTokenAmount in traderParams without corresponded signature + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerTokenAmount = DEFAULT_TRADER_PARAMS.takerTokenAmount.div(2); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = traderParams.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.expectRevert("LimitOrder: Fill is not signed by taker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithAlteredRecipient() public { + // Replace recipient in traderParams without corresponded signature + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.recipient = coordinator; + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: Fill is not signed by taker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithExpiredAllowFill() public { + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.expiry = uint64(block.timestamp - 1); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + crdParams.expiry = allowFill.expiry; + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); + vm.expectRevert("LimitOrder: Fill permission is expired"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithAlteredOrderHash() public { + // Replace orderHash in allowFill + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = bytes32(0); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithAlteredExecutor() public { + // Set the executor to maker (not user) + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.executor = maker; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + // Fill order using user (not executor) + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithAlteredFillAmount() public { + // Change fill amount in allow fill + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = DEFAULT_ALLOW_FILL.fillAmount.div(2); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithAllowFillNotSignedByCoordinator() public { + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + // Sign allow fill using user's private key + crdParams.sig = _signAllowFill(userPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByTraderWithReplayedAllowFill() public { + // Fill with default allow fill + bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload1); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.takerSalt = uint256(8001); + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("PermanentStorage: allow fill seen before"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload2); + } + + function testCannotFillByZeroTrader() public { + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.recipient = address(0); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: recipient can not be zero address"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testFullyFillByTrader() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); + + // makerFeeFactor/takerFeeFactor : 10% + // profitFeeFactor : 20% + vm.startPrank(owner, owner); + pionexContract.setFactors(1000, 1000, 2000); + vm.warp(block.timestamp + pionexContract.factorActivateDelay()); + pionexContract.activateFactors(); + vm.stopPrank(); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.expectEmit(true, true, true, true); + emit LimitOrderFilledByTrader( + DEFAULT_ORDER_HASH, + DEFAULT_ORDER.maker, + user, + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + DEFAULT_TRADER_PARAMS.recipient, + IPionexContract.FillReceipt( + address(DEFAULT_ORDER.makerToken), + address(DEFAULT_ORDER.takerToken), + DEFAULT_ORDER.makerTokenAmount, + DEFAULT_ORDER.takerTokenAmount, + 0, // remainingAmount should be zero after order fully filled + DEFAULT_ORDER.makerTokenAmount.mul(10).div(100), // makerTokenFee = 10% makerTokenAmount + DEFAULT_ORDER.takerTokenAmount.mul(10).div(100) // takerTokenFee = 10% takerTokenAmount + ) + ); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + + userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.mul(90).div(100))); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(90).div(100))); + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + fcMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.mul(10).div(100))); + fcTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(10).div(100))); + } + + function testFullyFillByContractWalletTrader() public { + // Contract mockERC1271Wallet as taker which always return valid ERC-1271 magic value no matter what. + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.taker = address(mockERC1271Wallet); + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.taker = address(mockERC1271Wallet); + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.executor = address(mockERC1271Wallet); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testFillBySpecificTaker() public { + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + // order specify taker address + order.taker = user; + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = orderHash; + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testFillBySpecificTakerWithOldEIP712Method() public { + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + // order specify taker address + order.taker = user; + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrderWithOldEIP712Method(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = orderHash; + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerSig = _signFillWithOldEIP712Method(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFillWithOldEIP712Method(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testOverFillByTrader() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + // set the fill amount to 2x of order quota + fill.takerTokenAmount = DEFAULT_ORDER.takerTokenAmount.mul(2); + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerTokenAmount = fill.takerTokenAmount; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = fill.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + + // Balance change should be bound by order amount (not affected by 2x fill amount) + userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount)); + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + } + + function testFillByTraderMultipleTimes() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + + // First fill amount : 9 USDT + PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + fill1.takerTokenAmount = 9 * 1e6; + IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; + traderParams1.takerTokenAmount = fill1.takerTokenAmount; + traderParams1.takerSig = _signFill(userPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; + allowFill1.fillAmount = fill1.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; + crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); + + bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload1); + + // Second fill amount : 36 USDT + PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + fill2.takerTokenAmount = 36 * 1e6; + + IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; + traderParams2.takerTokenAmount = fill2.takerTokenAmount; + traderParams2.takerSig = _signFill(userPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; + allowFill2.fillAmount = fill2.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; + crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); + + bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload2); + + // Half of the order filled after 2 txs + userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.div(2))); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.div(2))); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.div(2))); + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); + } + + /********************************* + *Test: fillLimitOrderByProtocol * + *********************************/ + + function testCannotFillByUniswapV3LessThanProtocolOutMinimum() public { + // get quote from AMM + uint256 ammTakerTokenOut = quoteUniswapV3ExactInput(UNISWAP_V3_QUOTER_ADDRESS, DEFAULT_PROTOCOL_PARAMS.data, DEFAULT_ORDER.makerTokenAmount); + + IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; + protocolParams.protocolOutMinimum = ammTakerTokenOut.mul(2); // require 2x output from AMM + + // Allow fill is bound by tx.origin in protocol case. + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("Too little received"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillBySushiSwapLessThanProtocolOutMinimum() public { + // get quote from AMM + uint256[] memory amountOuts = getSushiAmountsOut(SUSHISWAP_ADDRESS, DEFAULT_ORDER.makerTokenAmount, DEFAULT_AMM_PATH); + + address[] memory path = DEFAULT_AMM_PATH; + IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; + protocolParams.protocol = IPionexContract.Protocol.Sushiswap; + protocolParams.protocolOutMinimum = amountOuts[1].mul(2); // require 2x output from AMM + protocolParams.data = abi.encode(path); + + // Allow fill is bound by tx.origin in protocol case. + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolIfNotFromUserProxy() public { + vm.expectRevert("Strategy: not from UserProxy contract"); + // Call limit order contract directly will get reverted since msg.sender is not from UserProxy + pionexContract.fillLimitOrderByProtocol(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); + } + + function testCannotFillFilledOrderByProtocol() public { + // Fullly fill the default order first + vm.startPrank(user, user); + bytes memory payload1 = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); + userProxy.toLimitOrder(payload1); + vm.stopPrank(); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.salt = uint256(8002); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + crdParams.salt = allowFill.salt; + + vm.startPrank(user, user); + bytes memory payload2 = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: Order is filled"); + userProxy.toLimitOrder(payload2); + vm.stopPrank(); + } + + function testCannotFillExpiredOrderByProtocol() public { + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.expiry = uint64(block.timestamp - 1); + + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = orderHash; + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByProtocolPayload(order, orderMakerSig, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: Order is expired"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByProtocolWithWrongMakerSig() public { + bytes memory wrongMakerSig = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: Order is not signed by maker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotFillByProtocolWithTakerOtherThanOrderSpecified() public { + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + // order specify taker address + order.taker = SUSHISWAP_ADDRESS; + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(order, orderMakerSig, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: Order cannot be filled by this taker"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolWithExpiredFill() public { + IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; + protocolParams.expiry = uint64(block.timestamp - 1); + + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); + // Revert caused by Uniswap V3 + vm.expectRevert("Transaction too old"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolIfPriceNotMatch() public { + // Order with unreasonable price + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.takerTokenAmount = 9000 * 1e6; + + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(order, orderMakerSig, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: Insufficient token amount out from protocol"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolWithWrongAllowFill() public { + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + // Set the executor to maker (not user) + allowFill.executor = maker; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + // Fill order using user (not executor) + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocoWithAlteredOrderHash() public { + // Replace orderHash in allowFill + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = bytes32(0); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + // Allow fill is bound by tx.origin in protocol case. + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocoWithAlteredExecutor() public { + // Set the executor to maker (not user) + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.executor = maker; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + // Fill order using user (not executor) + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocoWithAlteredFillAmount() public { + // Change fill amount in allow fill + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = DEFAULT_ALLOW_FILL.fillAmount.div(2); + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + // Allow fill is bound by tx.origin in protocol case. + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolWithAllowFillNotSignedByCoordinator() public { + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + // Sign allow fill using user's private key + crdParams.sig = _signAllowFill(userPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); + + vm.startPrank(user, user); + + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); + vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolWithReplayedAllowFill() public { + // Fill with default allow fill + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); + userProxy.toLimitOrder(payload); + + vm.expectRevert("PermanentStorage: allow fill seen before"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testCannotFillByProtocolWithZeroProfitRecipient() public { + IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; + protocolParams.profitRecipient = address(0); + + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: profitRecipient can not be zero address"); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + } + + function testFullyFillByUniswapV3WithEvent() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverTakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); + + // makerFeeFactor/takerFeeFactor : 10% + // profitFeeFactor : 20% + vm.startPrank(owner, owner); + pionexContract.setFactors(1000, 1000, 2000); + vm.warp(block.timestamp + pionexContract.factorActivateDelay()); + pionexContract.activateFactors(); + vm.stopPrank(); + + // get quote from AMM + uint256 ammTakerTokenOut = quoteUniswapV3ExactInput(UNISWAP_V3_QUOTER_ADDRESS, DEFAULT_PROTOCOL_PARAMS.data, DEFAULT_ORDER.makerTokenAmount); + uint256 ammOutputExtra = ammTakerTokenOut.sub(DEFAULT_ORDER.takerTokenAmount); + uint256 relayerTakerTokenProfitFee = ammOutputExtra.mul(20).div(100); + + // Allow fill is bound by tx.origin in protocol case. + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); + vm.expectEmit(true, true, true, true); + emit LimitOrderFilledByProtocol( + DEFAULT_ORDER_HASH, + DEFAULT_ORDER.maker, + UNISWAP_V3_ADDRESS, + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + user, + receiver, + IPionexContract.FillReceipt( + address(DEFAULT_ORDER.makerToken), + address(DEFAULT_ORDER.takerToken), + DEFAULT_ORDER.makerTokenAmount, + DEFAULT_ORDER.takerTokenAmount, + 0, // remainingAmount should be zero after order fully filled + 0, // makerTokenFee should be zero in protocol case + DEFAULT_ORDER.takerTokenAmount.mul(10).div(100) // takerTokenFee = 10% takerTokenAmount + ), + ammOutputExtra.sub(relayerTakerTokenProfitFee), // relayerTakerTokenProfit + relayerTakerTokenProfitFee // relayerTakerTokenProfitFee + ); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + + userTakerAsset.assertChange(0); + // To avoid precision issue, use great than instead + receiverTakerAsset.assertChangeGt(int256(ammOutputExtra.mul(80).div(100))); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(90).div(100))); + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + + // fee = taker fee + relayer profit fee + uint256 fee = DEFAULT_ORDER.takerTokenAmount.mul(10).div(100); + fee = fee.add(relayerTakerTokenProfitFee); + fcTakerAsset.assertChangeGt(int256(fee)); + } + + function testFillByProtocolRelayerProfit() public { + address relayer = 0x52D82cD20F092DB55fb1e006a2C2773AB17F6Ff2; + BalanceSnapshot.Snapshot memory relayerTakerAsset = BalanceSnapshot.take(relayer, address(DEFAULT_ORDER.takerToken)); + + // set order with extreme low price leaving huge profit for relayer + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.takerTokenAmount = 1 * 1e6; + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory makerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + // update protocolParams + IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; + protocolParams.takerTokenAmount = order.takerTokenAmount; + protocolParams.profitRecipient = relayer; + + // update allowFill + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + allowFill.executor = relayer; + allowFill.fillAmount = order.takerTokenAmount; + + // update crdParams + IPionexContract.CoordinatorParams memory crdParams = IPionexContract.CoordinatorParams( + _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712), + allowFill.salt, + allowFill.expiry + ); + + // get expected profit for relayer + uint256 ammOutputExtra = quoteUniswapV3ExactInput(UNISWAP_V3_QUOTER_ADDRESS, protocolParams.data, order.makerTokenAmount).sub(order.takerTokenAmount); + + vm.startPrank(relayer, relayer); + vm.expectEmit(true, true, true, true); + IPionexContract.FillReceipt memory fillReceipt = IPionexContract.FillReceipt( + address(order.makerToken), + address(order.takerToken), + order.makerTokenAmount, + order.takerTokenAmount, + 0, // remainingAmount should be zero after order fully filled + 0, // makerTokenFee should be zero in protocol case + 0 // takerTokenFee = 0 since feeFactor = 0 + ); + emit LimitOrderFilledByProtocol( + orderHash, + order.maker, + UNISWAP_V3_ADDRESS, + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + relayer, // relayer + relayer, // profitRecipient + fillReceipt, + ammOutputExtra, // relayerTakerTokenProfit + 0 // profit fee = 0 + ); + userProxy.toLimitOrder(_genFillByProtocolPayload(order, makerSig, protocolParams, crdParams)); + vm.stopPrank(); + + // whole profit should be given to relayer + relayerTakerAsset.assertChange(int256(ammOutputExtra)); + // no token should left in pionexContract + assertEq(order.makerToken.balanceOf(address(pionexContract)), 0); + assertEq(order.takerToken.balanceOf(address(pionexContract)), 0); + } + + function testFullyFillBySushiSwap() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverTakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + + PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.makerTokenAmount = 10 * 1e18; + order.takerTokenAmount = 8 * 1e6; + + // get quote from AMM + address[] memory path = DEFAULT_AMM_PATH; + uint256[] memory amountOuts = getSushiAmountsOut(SUSHISWAP_ADDRESS, order.makerTokenAmount, path); + // Since profitFeeFactor is zero, so the extra token from AMM is the profit for relayer. + uint256 profit = amountOuts[amountOuts.length - 1].sub(order.takerTokenAmount); + + bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes memory orderMakerHash = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; + protocolParams.protocol = IPionexContract.Protocol.Sushiswap; + protocolParams.takerTokenAmount = order.takerTokenAmount; + protocolParams.data = abi.encode(path); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = orderHash; + allowFill.fillAmount = protocolParams.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + // Allow fill is bound by tx.origin in protocol case. + vm.startPrank(user, user); + bytes memory payload = _genFillByProtocolPayload(order, orderMakerHash, protocolParams, crdParams); + userProxy.toLimitOrder(payload); + vm.stopPrank(); + + userTakerAsset.assertChange(0); + receiverTakerAsset.assertChange(int256(profit)); + makerTakerAsset.assertChange(int256(order.takerTokenAmount)); + makerMakerAsset.assertChange(-int256(order.makerTokenAmount)); + } + + /********************************* + * cancelLimitOrder * + *********************************/ + + function testCannotFillCanceledOrder() public { + PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + zeroOrder.takerTokenAmount = 0; + + bytes memory cancelPayload = _genCancelLimitOrderPayload( + DEFAULT_ORDER, + _signOrder(makerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) + ); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(cancelPayload); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: Order is cancelled"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotCancelIfNotMaker() public { + PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + zeroOrder.takerTokenAmount = 0; + + bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); + vm.expectRevert("LimitOrder: Cancel request is not signed by maker"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(cancelPayload); + } + + function testCannotCancelExpiredOrder() public { + PionexContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; + expiredOrder.expiry = 0; + + bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(userPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); + vm.expectRevert("LimitOrder: Order is expired"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testCannotCancelTwice() public { + PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + zeroOrder.takerTokenAmount = 0; + + bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(makerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + vm.expectRevert("LimitOrder: Order is cancelled already"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + + /********************************* + * Test: signing * + *********************************/ + + function testLimitOrderEIP712Sig() public { + string memory limitOrderPayloadJson = vm.readFile("test/signing/payload/pionexContract.json"); + + PionexContractLibEIP712.Order memory order = PionexContractLibEIP712.Order( + IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerToken"), (address))), + IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerToken"), (address))), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerTokenAmount"), (uint256)), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerTokenAmount"), (uint256)), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.maker"), (address)), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.taker"), (address)), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.salt"), (uint256)), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expiry"), (uint64)) + ); + + address limitOrderAddr = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.LimitOrder"), (address)); + uint256 signingKey = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.signingKey"), (uint256)); + + bytes memory orderSig = _signOrderEIP712(limitOrderAddr, signingKey, order); + bytes memory expectedOrderSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedOrderSig"), (bytes)); + require(keccak256(orderSig) == keccak256(expectedOrderSig), "Not expected LimitOrder order sig"); + + PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill( + getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), + order.taker, + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.recipient"), (address)), + order.makerTokenAmount, + order.takerTokenAmount, + order.salt, + order.expiry + ); + + bytes memory fillSig = _signFillEIP712(limitOrderAddr, signingKey, fill); + bytes memory expectedFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedFillSig"), (bytes)); + require(keccak256(fillSig) == keccak256(expectedFillSig), "Not expected LimitOrder fill sig"); + + PionexContractLibEIP712.AllowFill memory allowFill = PionexContractLibEIP712.AllowFill( + getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), + abi.decode(vm.parseJson(limitOrderPayloadJson, "$.executor"), (address)), + order.takerTokenAmount, + order.salt, + order.expiry + ); + + bytes memory allowFillSig = _signAllowFillEIP712(limitOrderAddr, signingKey, allowFill); + bytes memory expectedAllowFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedAllowFillSig"), (bytes)); + require(keccak256(allowFillSig) == keccak256(expectedAllowFillSig), "Not expected LimitOrder allow fill sig"); + } + + function _signOrderEIP712( + address limitOrderAddr, + uint256 privateKey, + PionexContractLibEIP712.Order memory order + ) internal returns (bytes memory sig) { + bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); + bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), orderHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); + } + + function _signFillEIP712( + address limitOrderAddr, + uint256 privateKey, + PionexContractLibEIP712.Fill memory fill + ) internal returns (bytes memory sig) { + bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); + bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), fillHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); + } + + function _signAllowFillEIP712( + address limitOrderAddr, + uint256 privateKey, + PionexContractLibEIP712.AllowFill memory allowFill + ) internal returns (bytes memory sig) { + bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), allowFillHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); + } + + /********************************* + * Helpers * + *********************************/ + + function _signOrder( + uint256 privateKey, + PionexContractLibEIP712.Order memory order, + SignatureValidator.SignatureType sigType + ) internal returns (bytes memory sig) { + bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); + bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), orderHash); + + if (sigType == SignatureValidator.SignatureType.EIP712) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, uint8(sigType)); + } else if (sigType == SignatureValidator.SignatureType.Wallet) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, ECDSA.toEthSignedMessageHash(EIP712SignDigest)); + sig = abi.encodePacked(v, r, s, uint8(sigType)); + } else { + revert("Invalid signature type"); + } + } + + function _signOrderWithOldEIP712Method( + uint256 privateKey, + PionexContractLibEIP712.Order memory order, + SignatureValidator.SignatureType sigType + ) internal returns (bytes memory sig) { + bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); + bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), orderHash); + require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); + } + + function _signFill( + uint256 privateKey, + PionexContractLibEIP712.Fill memory fill, + SignatureValidator.SignatureType sigType + ) internal returns (bytes memory sig) { + bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); + bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), fillHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, uint8(sigType)); + } + + function _signFillWithOldEIP712Method( + uint256 privateKey, + PionexContractLibEIP712.Fill memory fill, + SignatureValidator.SignatureType sigType + ) internal returns (bytes memory sig) { + bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); + bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), fillHash); + require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); + } + + function _signAllowFill( + uint256 privateKey, + PionexContractLibEIP712.AllowFill memory allowFill, + SignatureValidator.SignatureType sigType + ) internal returns (bytes memory sig) { + bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, uint8(sigType)); + } + + function _signAllowFillWithOldEIP712Method( + uint256 privateKey, + PionexContractLibEIP712.AllowFill memory allowFill, + SignatureValidator.SignatureType sigType + ) internal returns (bytes memory sig) { + bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); + require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); + sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); + } + + function _genFillByTraderPayload( + PionexContractLibEIP712.Order memory order, + bytes memory orderMakerSig, + IPionexContract.TraderParams memory params, + IPionexContract.CoordinatorParams memory crdParams + ) internal view returns (bytes memory payload) { + return abi.encodeWithSelector(pionexContract.fillLimitOrderByTrader.selector, order, orderMakerSig, params, crdParams); + } + + function _genFillByProtocolPayload( + PionexContractLibEIP712.Order memory order, + bytes memory orderMakerSig, + IPionexContract.ProtocolParams memory params, + IPionexContract.CoordinatorParams memory crdParams + ) internal view returns (bytes memory payload) { + return abi.encodeWithSelector(pionexContract.fillLimitOrderByProtocol.selector, order, orderMakerSig, params, crdParams); + } + + function _genCancelLimitOrderPayload(PionexContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) + internal + view + returns (bytes memory payload) + { + return abi.encodeWithSelector(pionexContract.cancelLimitOrder.selector, order, cancelOrderMakerSig); + } +} From 23d32d299058b8b9027a268ee92e3b2974e4c2c0 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 17 May 2023 18:29:51 +0800 Subject: [PATCH 08/41] Adjust tests --- test/forkMainnet/PionexContract.t.sol | 102 ++++++++++++++------------ 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 9ed14980..aa996c6a 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -513,7 +513,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillByTraderWithAlteredTakerTokenAmount() public { // Replace takerTokenAmount in traderParams without corresponded signature IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerTokenAmount = DEFAULT_TRADER_PARAMS.takerTokenAmount.div(2); + traderParams.takerTokenAmount = DEFAULT_TRADER_PARAMS.takerTokenAmount.mul(2); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.takerTokenAmount; @@ -754,9 +754,11 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota + fill.makerTokenAmount = DEFAULT_ORDER.makerTokenAmount.mul(2); fill.takerTokenAmount = DEFAULT_ORDER.takerTokenAmount.mul(2); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.makerTokenAmount = fill.makerTokenAmount; traderParams.takerTokenAmount = fill.takerTokenAmount; traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); @@ -785,8 +787,10 @@ contract PionexContractTest is StrategySharedSetup { // First fill amount : 9 USDT PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + fill1.makerTokenAmount = 10 * 1e18; fill1.takerTokenAmount = 9 * 1e6; IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; + traderParams1.makerTokenAmount = fill1.makerTokenAmount; traderParams1.takerTokenAmount = fill1.takerTokenAmount; traderParams1.takerSig = _signFill(userPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); @@ -802,9 +806,11 @@ contract PionexContractTest is StrategySharedSetup { // Second fill amount : 36 USDT PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + fill2.makerTokenAmount = 40 * 1e18; fill2.takerTokenAmount = 36 * 1e6; IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; + traderParams2.makerTokenAmount = fill2.makerTokenAmount; traderParams2.takerTokenAmount = fill2.takerTokenAmount; traderParams2.takerSig = _signFill(userPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); @@ -1293,53 +1299,53 @@ contract PionexContractTest is StrategySharedSetup { * Test: signing * *********************************/ - function testLimitOrderEIP712Sig() public { - string memory limitOrderPayloadJson = vm.readFile("test/signing/payload/pionexContract.json"); - - PionexContractLibEIP712.Order memory order = PionexContractLibEIP712.Order( - IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerToken"), (address))), - IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerToken"), (address))), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerTokenAmount"), (uint256)), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerTokenAmount"), (uint256)), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.maker"), (address)), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.taker"), (address)), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.salt"), (uint256)), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expiry"), (uint64)) - ); - - address limitOrderAddr = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.LimitOrder"), (address)); - uint256 signingKey = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.signingKey"), (uint256)); - - bytes memory orderSig = _signOrderEIP712(limitOrderAddr, signingKey, order); - bytes memory expectedOrderSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedOrderSig"), (bytes)); - require(keccak256(orderSig) == keccak256(expectedOrderSig), "Not expected LimitOrder order sig"); - - PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill( - getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), - order.taker, - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.recipient"), (address)), - order.makerTokenAmount, - order.takerTokenAmount, - order.salt, - order.expiry - ); - - bytes memory fillSig = _signFillEIP712(limitOrderAddr, signingKey, fill); - bytes memory expectedFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedFillSig"), (bytes)); - require(keccak256(fillSig) == keccak256(expectedFillSig), "Not expected LimitOrder fill sig"); - - PionexContractLibEIP712.AllowFill memory allowFill = PionexContractLibEIP712.AllowFill( - getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), - abi.decode(vm.parseJson(limitOrderPayloadJson, "$.executor"), (address)), - order.takerTokenAmount, - order.salt, - order.expiry - ); - - bytes memory allowFillSig = _signAllowFillEIP712(limitOrderAddr, signingKey, allowFill); - bytes memory expectedAllowFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedAllowFillSig"), (bytes)); - require(keccak256(allowFillSig) == keccak256(expectedAllowFillSig), "Not expected LimitOrder allow fill sig"); - } + // function testLimitOrderEIP712Sig() public { + // string memory limitOrderPayloadJson = vm.readFile("test/signing/payload/limitOrder.json"); + + // PionexContractLibEIP712.Order memory order = PionexContractLibEIP712.Order( + // IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerToken"), (address))), + // IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerToken"), (address))), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerTokenAmount"), (uint256)), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerTokenAmount"), (uint256)), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.maker"), (address)), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.taker"), (address)), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.salt"), (uint256)), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expiry"), (uint64)) + // ); + + // address limitOrderAddr = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.LimitOrder"), (address)); + // uint256 signingKey = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.signingKey"), (uint256)); + + // bytes memory orderSig = _signOrderEIP712(limitOrderAddr, signingKey, order); + // bytes memory expectedOrderSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedOrderSig"), (bytes)); + // require(keccak256(orderSig) == keccak256(expectedOrderSig), "Not expected LimitOrder order sig"); + + // PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill( + // getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), + // order.taker, + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.recipient"), (address)), + // order.makerTokenAmount, + // order.takerTokenAmount, + // order.salt, + // order.expiry + // ); + + // bytes memory fillSig = _signFillEIP712(limitOrderAddr, signingKey, fill); + // bytes memory expectedFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedFillSig"), (bytes)); + // require(keccak256(fillSig) == keccak256(expectedFillSig), "Not expected LimitOrder fill sig"); + + // PionexContractLibEIP712.AllowFill memory allowFill = PionexContractLibEIP712.AllowFill( + // getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), + // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.executor"), (address)), + // order.takerTokenAmount, + // order.salt, + // order.expiry + // ); + + // bytes memory allowFillSig = _signAllowFillEIP712(limitOrderAddr, signingKey, allowFill); + // bytes memory expectedAllowFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedAllowFillSig"), (bytes)); + // require(keccak256(allowFillSig) == keccak256(expectedAllowFillSig), "Not expected LimitOrder allow fill sig"); + // } function _signOrderEIP712( address limitOrderAddr, From a57573977b0d563819ff9244460b5b9d2a357244 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Thu, 18 May 2023 18:15:04 +0800 Subject: [PATCH 09/41] Change to quote from maker token instead --- contracts/PionexContract.sol | 48 ++++++++++++++++++++++++----- contracts/utils/LibOrderStorage.sol | 2 ++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index d2485f58..a25e528a 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -152,9 +152,9 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _validateTraderFill(fill, _params.takerSig); } - (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrder(_order, orderHash, _params.takerTokenAmount); - // Adjust makerTokenAmount according to the provided takerToken/makerToken ratio - makerTokenAmount = takerTokenAmount.mul(_params.makerTokenAmount).div(_params.takerTokenAmount); + (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.makerTokenAmount); + // Adjust takerTokenAmount according to the provided takerToken/makerToken ratio + takerTokenAmount = makerTokenAmount.mul(_params.takerTokenAmount).div(_params.makerTokenAmount); uint256 makerTokenOut = _settleForTrader( TraderSettlement({ @@ -172,7 +172,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu }) ); - _recordOrderFilled(orderHash, takerTokenAmount); + _recordMakerTokenFilled(orderHash, makerTokenAmount); return (takerTokenAmount, makerTokenOut); } @@ -295,7 +295,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address protocolAddress = _getProtocolAddress(_params.protocol); _validateOrderTaker(_order, protocolAddress); - (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrder(_order, orderHash, _params.takerTokenAmount); + (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrderFromTakerToken(_order, orderHash, _params.takerTokenAmount); uint256 relayerTakerTokenProfit = _settleForProtocol( ProtocolSettlement({ @@ -318,7 +318,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu }) ); - _recordOrderFilled(orderHash, takerTokenAmount); + _recordTakerTokenFilled(orderHash, takerTokenAmount); return relayerTakerTokenProfit; } @@ -481,7 +481,33 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } } - function _quoteOrder( + function _quoteOrderFromMakerToken( + PionexContractLibEIP712.Order memory _order, + bytes32 _orderHash, + uint256 _makerTokenAmount + ) + internal + view + returns ( + uint256, + uint256, + uint256 + ) + { + uint256 makerTokenFilledAmount = LibOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; + + require(makerTokenFilledAmount < _order.makerTokenAmount, "LimitOrder: Order is filled"); + + uint256 makerTokenFillableAmount = _order.makerTokenAmount.sub(makerTokenFilledAmount); + uint256 makerTokenQuota = Math.min(_makerTokenAmount, makerTokenFillableAmount); + uint256 takerTokenQuota = makerTokenQuota.mul(_order.takerTokenAmount).div(_order.makerTokenAmount); + uint256 remainingAfterFill = makerTokenFillableAmount.sub(makerTokenQuota); + + require(makerTokenQuota != 0 && takerTokenQuota != 0, "LimitOrder: zero token amount"); + return (makerTokenQuota, takerTokenQuota, remainingAfterFill); + } + + function _quoteOrderFromTakerToken( PionexContractLibEIP712.Order memory _order, bytes32 _orderHash, uint256 _takerTokenAmount @@ -507,7 +533,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu return (makerTokenQuota, takerTokenQuota, remainingAfterFill); } - function _recordOrderFilled(bytes32 _orderHash, uint256 _takerTokenAmount) internal { + function _recordMakerTokenFilled(bytes32 _orderHash, uint256 _makerTokenAmount) internal { + LibOrderStorage.Storage storage stor = LibOrderStorage.getStorage(); + uint256 makerTokenFilledAmount = stor.orderHashToMakerTokenFilledAmount[_orderHash]; + stor.orderHashToMakerTokenFilledAmount[_orderHash] = makerTokenFilledAmount.add(_makerTokenAmount); + } + + function _recordTakerTokenFilled(bytes32 _orderHash, uint256 _takerTokenAmount) internal { LibOrderStorage.Storage storage stor = LibOrderStorage.getStorage(); uint256 takerTokenFilledAmount = stor.orderHashToTakerTokenFilledAmount[_orderHash]; stor.orderHashToTakerTokenFilledAmount[_orderHash] = takerTokenFilledAmount.add(_takerTokenAmount); diff --git a/contracts/utils/LibOrderStorage.sol b/contracts/utils/LibOrderStorage.sol index 30148db1..fbbea580 100644 --- a/contracts/utils/LibOrderStorage.sol +++ b/contracts/utils/LibOrderStorage.sol @@ -9,6 +9,8 @@ library LibOrderStorage { mapping(bytes32 => uint256) orderHashToTakerTokenFilledAmount; // Whether order is cancelled or not. mapping(bytes32 => bool) orderHashToCancelled; + // How much maker token has been filled in order. + mapping(bytes32 => uint256) orderHashToMakerTokenFilledAmount; } /// @dev Get the storage bucket for this contract. From ca57e62f6dcc47b5dd41bda4bb6753ed09bc6f0b Mon Sep 17 00:00:00 2001 From: NIC619 Date: Thu, 18 May 2023 18:15:31 +0800 Subject: [PATCH 10/41] Add better/worse takerToken/makerToken ratio tests --- test/forkMainnet/PionexContract.t.sol | 151 ++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index aa996c6a..e19559a1 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -633,6 +633,21 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); } + function testCannotFillByTraderWithWorseTakerMakerTokenRatio() public { + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + // Increase maker token amount so the takerToken/makerToken ratio is worse than order's takerToken/makerToken ratio + fill.makerTokenAmount = DEFAULT_FILL.makerTokenAmount.add(1); + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.makerTokenAmount = fill.makerTokenAmount; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("LimitOrder: taker/maker token ratio not good enough"); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + } + function testFullyFillByTrader() public { BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); @@ -678,6 +693,57 @@ contract PionexContractTest is StrategySharedSetup { fcTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(10).div(100))); } + function testFullyFillByTraderWithBetterTakerMakerTokenRatio() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + // Increase taker token amount so the takerToken/makerToken ratio is better than order's takerToken/makerToken ratio + fill.takerTokenAmount = DEFAULT_FILL.takerTokenAmount.mul(11).div(10); // 10% more + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.takerTokenAmount = fill.takerTokenAmount; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = traderParams.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.expectEmit(true, true, true, true); + emit LimitOrderFilledByTrader( + DEFAULT_ORDER_HASH, + DEFAULT_ORDER.maker, + user, + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + traderParams.recipient, + IPionexContract.FillReceipt( + address(DEFAULT_ORDER.makerToken), + address(DEFAULT_ORDER.takerToken), + DEFAULT_ORDER.makerTokenAmount, + fill.takerTokenAmount, + 0, // remainingAmount should be zero after order fully filled + 0, + 0 + ) + ); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + + userTakerAsset.assertChange(-int256(fill.takerTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); + makerTakerAsset.assertChange(int256(fill.takerTokenAmount)); // 10% more + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + fcMakerAsset.assertChange(0); + fcTakerAsset.assertChange(0); + } + function testFullyFillByContractWalletTrader() public { // Contract mockERC1271Wallet as taker which always return valid ERC-1271 magic value no matter what. PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -779,6 +845,39 @@ contract PionexContractTest is StrategySharedSetup { makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); } + function testOverFillByTraderWithBetterTakerMakerTokenRatio() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + // set the fill amount to 2x of order quota + fill.makerTokenAmount = DEFAULT_ORDER.makerTokenAmount.mul(2); + fill.takerTokenAmount = DEFAULT_ORDER.takerTokenAmount.mul(2).mul(11).div(10); // 10% more + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.makerTokenAmount = fill.makerTokenAmount; + traderParams.takerTokenAmount = fill.takerTokenAmount; + traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = fill.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload); + + // Balance change should be bound by order amount (not affected by 2x fill amount) + userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + } + function testFillByTraderMultipleTimes() public { BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); @@ -831,6 +930,58 @@ contract PionexContractTest is StrategySharedSetup { makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); } + function testFillByTraderMultipleTimesWithBetterTakerMakerTokenRatio() public { + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + + // First fill amount : 9 USDT and same takerToken/makerToken ratio + PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + fill1.makerTokenAmount = 10 * 1e18; + fill1.takerTokenAmount = 9 * 1e6; + IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; + traderParams1.makerTokenAmount = fill1.makerTokenAmount; + traderParams1.takerTokenAmount = fill1.takerTokenAmount; + traderParams1.takerSig = _signFill(userPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; + allowFill1.fillAmount = fill1.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; + crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); + + bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload1); + + // Second fill amount : 36 USDT and better takerToken/makerToken ratio + PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + fill2.makerTokenAmount = 40 * 1e18; + fill2.takerTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more + + IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; + traderParams2.makerTokenAmount = fill2.makerTokenAmount; + traderParams2.takerTokenAmount = fill2.takerTokenAmount; + traderParams2.takerSig = _signFill(userPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; + allowFill2.fillAmount = fill2.takerTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; + crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); + + bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); + vm.prank(user, user); // Only EOA + userProxy.toLimitOrder(payload2); + + // Half of the order filled after 2 txs + userTakerAsset.assertChange(-int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.div(2))); + makerTakerAsset.assertChange(int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); + makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); + } + /********************************* *Test: fillLimitOrderByProtocol * *********************************/ From c53f662cd9e34019de7c070414207b5e6b11ef1a Mon Sep 17 00:00:00 2001 From: NIC619 Date: Thu, 18 May 2023 18:16:46 +0800 Subject: [PATCH 11/41] Lint --- contracts/PionexContract.sol | 5 ++++- contracts/utils/PionexContractLibEIP712.sol | 14 +++++++++++++- test/forkMainnet/PionexContract.t.sol | 14 +++++++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index a25e528a..4c249212 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -137,7 +137,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // Check provided takerToken/makerToken ratio is better than or equal to maker's specfied takerToken/makerToken ratio // -> _params.takerTokenAmount/_params.makerTokenAmount >= _order.takerTokenAmount/_order.makerTokenAmount - require(_params.takerTokenAmount.mul(_order.makerTokenAmount) >= _order.takerTokenAmount.mul(_params.makerTokenAmount), "LimitOrder: taker/maker token ratio not good enough"); + require( + _params.takerTokenAmount.mul(_order.makerTokenAmount) >= _order.takerTokenAmount.mul(_params.makerTokenAmount), + "LimitOrder: taker/maker token ratio not good enough" + ); { PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/PionexContractLibEIP712.sol index b98c0b09..aefbc8d1 100644 --- a/contracts/utils/PionexContractLibEIP712.sol +++ b/contracts/utils/PionexContractLibEIP712.sol @@ -80,7 +80,19 @@ library PionexContractLibEIP712 { bytes32 private constant FILL_TYPEHASH = 0x205396fa1b68e5a32114505757ea3414ca863515127de397dd50fc79342ce917; function _getFillStructHash(Fill memory _fill) internal pure returns (bytes32) { - return keccak256(abi.encode(FILL_TYPEHASH, _fill.orderHash, _fill.taker, _fill.recipient, _fill.makerTokenAmount, _fill.takerTokenAmount, _fill.takerSalt, _fill.expiry)); + return + keccak256( + abi.encode( + FILL_TYPEHASH, + _fill.orderHash, + _fill.taker, + _fill.recipient, + _fill.makerTokenAmount, + _fill.takerTokenAmount, + _fill.takerSalt, + _fill.expiry + ) + ); } struct AllowFill { diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index e19559a1..92973d46 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -92,7 +92,15 @@ contract PionexContractTest is StrategySharedSetup { ); DEFAULT_ORDER_HASH = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); DEFAULT_ORDER_MAKER_SIG = _signOrder(makerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); - DEFAULT_FILL = PionexContractLibEIP712.Fill(DEFAULT_ORDER_HASH, user, receiver, DEFAULT_ORDER.makerTokenAmount, DEFAULT_ORDER.takerTokenAmount, uint256(1002), DEADLINE); + DEFAULT_FILL = PionexContractLibEIP712.Fill( + DEFAULT_ORDER_HASH, + user, + receiver, + DEFAULT_ORDER.makerTokenAmount, + DEFAULT_ORDER.takerTokenAmount, + uint256(1002), + DEADLINE + ); DEFAULT_TRADER_PARAMS = IPionexContract.TraderParams( user, // taker receiver, // recipient @@ -872,9 +880,9 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more + userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); } From 7da8bba42c0f8954e2eab12bc1af4b35f4296638 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 19 May 2023 16:52:19 +0800 Subject: [PATCH 12/41] Skip takerTokenAmount in quoteOrder --- contracts/PionexContract.sol | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 4c249212..86111a83 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -155,9 +155,9 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _validateTraderFill(fill, _params.takerSig); } - (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.makerTokenAmount); - // Adjust takerTokenAmount according to the provided takerToken/makerToken ratio - takerTokenAmount = makerTokenAmount.mul(_params.takerTokenAmount).div(_params.makerTokenAmount); + (uint256 makerTokenAmount, uint256 remainingAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.makerTokenAmount); + // Calculate takerTokenAmount according to the provided takerToken/makerToken ratio + uint256 takerTokenAmount = makerTokenAmount.mul(_params.takerTokenAmount).div(_params.makerTokenAmount); uint256 makerTokenOut = _settleForTrader( TraderSettlement({ @@ -492,7 +492,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu internal view returns ( - uint256, uint256, uint256 ) @@ -503,11 +502,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 makerTokenFillableAmount = _order.makerTokenAmount.sub(makerTokenFilledAmount); uint256 makerTokenQuota = Math.min(_makerTokenAmount, makerTokenFillableAmount); - uint256 takerTokenQuota = makerTokenQuota.mul(_order.takerTokenAmount).div(_order.makerTokenAmount); uint256 remainingAfterFill = makerTokenFillableAmount.sub(makerTokenQuota); - require(makerTokenQuota != 0 && takerTokenQuota != 0, "LimitOrder: zero token amount"); - return (makerTokenQuota, takerTokenQuota, remainingAfterFill); + require(makerTokenQuota != 0, "LimitOrder: zero token amount"); + return (makerTokenQuota, remainingAfterFill); } function _quoteOrderFromTakerToken( From dfbec2a15f192b58d849ac1c9ae3abc854f166d8 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 19 May 2023 16:52:59 +0800 Subject: [PATCH 13/41] Remove signing test --- test/forkMainnet/PionexContract.t.sol | 52 --------------------------- 1 file changed, 52 deletions(-) diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 92973d46..cfa05ab7 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -1454,58 +1454,6 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); } - /********************************* - * Test: signing * - *********************************/ - - // function testLimitOrderEIP712Sig() public { - // string memory limitOrderPayloadJson = vm.readFile("test/signing/payload/limitOrder.json"); - - // PionexContractLibEIP712.Order memory order = PionexContractLibEIP712.Order( - // IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerToken"), (address))), - // IERC20(abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerToken"), (address))), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.makerTokenAmount"), (uint256)), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.takerTokenAmount"), (uint256)), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.maker"), (address)), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.taker"), (address)), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.salt"), (uint256)), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expiry"), (uint64)) - // ); - - // address limitOrderAddr = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.LimitOrder"), (address)); - // uint256 signingKey = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.signingKey"), (uint256)); - - // bytes memory orderSig = _signOrderEIP712(limitOrderAddr, signingKey, order); - // bytes memory expectedOrderSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedOrderSig"), (bytes)); - // require(keccak256(orderSig) == keccak256(expectedOrderSig), "Not expected LimitOrder order sig"); - - // PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill( - // getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), - // order.taker, - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.recipient"), (address)), - // order.makerTokenAmount, - // order.takerTokenAmount, - // order.salt, - // order.expiry - // ); - - // bytes memory fillSig = _signFillEIP712(limitOrderAddr, signingKey, fill); - // bytes memory expectedFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedFillSig"), (bytes)); - // require(keccak256(fillSig) == keccak256(expectedFillSig), "Not expected LimitOrder fill sig"); - - // PionexContractLibEIP712.AllowFill memory allowFill = PionexContractLibEIP712.AllowFill( - // getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), PionexContractLibEIP712._getOrderStructHash(order)), - // abi.decode(vm.parseJson(limitOrderPayloadJson, "$.executor"), (address)), - // order.takerTokenAmount, - // order.salt, - // order.expiry - // ); - - // bytes memory allowFillSig = _signAllowFillEIP712(limitOrderAddr, signingKey, allowFill); - // bytes memory expectedAllowFillSig = abi.decode(vm.parseJson(limitOrderPayloadJson, "$.expectedAllowFillSig"), (bytes)); - // require(keccak256(allowFillSig) == keccak256(expectedAllowFillSig), "Not expected LimitOrder allow fill sig"); - // } - function _signOrderEIP712( address limitOrderAddr, uint256 privateKey, From f8b2d2696232cde5988d1a3b1de762fd2a2bef70 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 19 May 2023 18:17:57 +0800 Subject: [PATCH 14/41] Remove fillLimitOrderByProtocol from PionexContract --- contracts/PionexContract.sol | 265 +---------- contracts/interfaces/IPionexContract.sol | 49 -- contracts/utils/LibOrderStorage.sol | 2 - .../utils/LibPionexContractOrderStorage.sol | 25 + test/forkMainnet/PionexContract.t.sol | 446 ------------------ 5 files changed, 32 insertions(+), 755 deletions(-) create mode 100644 contracts/utils/LibPionexContractOrderStorage.sol diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 86111a83..77d952f1 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -15,9 +15,7 @@ import "./interfaces/IWeth.sol"; import "./utils/StrategyBase.sol"; import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; -import "./utils/LibUniswapV2.sol"; -import "./utils/LibUniswapV3.sol"; -import "./utils/LibOrderStorage.sol"; +import "./utils/LibPionexContractOrderStorage.sol"; import "./utils/PionexContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; @@ -31,10 +29,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 public immutable factorActivateDelay; - // AMM - address public immutable uniswapV3RouterAddress; - address public immutable sushiswapRouterAddress; - // Below are the variables which consume storage slots. address public coordinator; address public feeCollector; @@ -56,14 +50,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address _spender, address _coordinator, uint256 _factorActivateDelay, - address _uniswapV3RouterAddress, - address _sushiswapRouterAddress, address _feeCollector ) StrategyBase(_owner, _userProxy, _weth, _permStorage, _spender) { coordinator = _coordinator; factorActivateDelay = _factorActivateDelay; - uniswapV3RouterAddress = _uniswapV3RouterAddress; - sushiswapRouterAddress = _sushiswapRouterAddress; feeCollector = _feeCollector; } @@ -283,173 +273,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu return makerTokenForTrader; } - /// @inheritdoc IPionexContract - function fillLimitOrderByProtocol( - PionexContractLibEIP712.Order calldata _order, - bytes calldata _orderMakerSig, - ProtocolParams calldata _params, - CoordinatorParams calldata _crdParams - ) external override onlyUserProxy nonReentrant returns (uint256) { - bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); - - _validateOrder(_order, orderHash, _orderMakerSig); - bytes32 allowFillHash = _validateFillPermission(orderHash, _params.takerTokenAmount, tx.origin, _crdParams); - - address protocolAddress = _getProtocolAddress(_params.protocol); - _validateOrderTaker(_order, protocolAddress); - - (uint256 makerTokenAmount, uint256 takerTokenAmount, uint256 remainingAmount) = _quoteOrderFromTakerToken(_order, orderHash, _params.takerTokenAmount); - - uint256 relayerTakerTokenProfit = _settleForProtocol( - ProtocolSettlement({ - orderHash: orderHash, - allowFillHash: allowFillHash, - protocolAddress: protocolAddress, - protocol: _params.protocol, - data: _params.data, - relayer: tx.origin, - profitRecipient: _params.profitRecipient, - maker: _order.maker, - taker: _order.taker, - makerToken: _order.makerToken, - takerToken: _order.takerToken, - makerTokenAmount: makerTokenAmount, - takerTokenAmount: takerTokenAmount, - remainingAmount: remainingAmount, - protocolOutMinimum: _params.protocolOutMinimum, - expiry: _params.expiry - }) - ); - - _recordTakerTokenFilled(orderHash, takerTokenAmount); - - return relayerTakerTokenProfit; - } - - function _getProtocolAddress(Protocol protocol) internal view returns (address) { - if (protocol == Protocol.UniswapV3) { - return uniswapV3RouterAddress; - } - if (protocol == Protocol.Sushiswap) { - return sushiswapRouterAddress; - } - revert("LimitOrder: Unknown protocol"); - } - - struct ProtocolSettlement { - bytes32 orderHash; - bytes32 allowFillHash; - address protocolAddress; - Protocol protocol; - bytes data; - address relayer; - address profitRecipient; - address maker; - address taker; - IERC20 makerToken; - IERC20 takerToken; - uint256 makerTokenAmount; - uint256 takerTokenAmount; - uint256 remainingAmount; - uint256 protocolOutMinimum; - uint64 expiry; - } - - function _settleForProtocol(ProtocolSettlement memory _settlement) internal returns (uint256) { - require(_settlement.profitRecipient != address(0), "LimitOrder: profitRecipient can not be zero address"); - - // Collect maker token from maker in order to swap through protocol - spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), address(this), _settlement.makerTokenAmount); - - uint256 takerTokenOut = _swapByProtocol(_settlement); - - require(takerTokenOut >= _settlement.takerTokenAmount, "LimitOrder: Insufficient token amount out from protocol"); - - uint256 ammOutputExtra = takerTokenOut.sub(_settlement.takerTokenAmount); - uint256 relayerTakerTokenProfitFee = _mulFactor(ammOutputExtra, profitFeeFactor); - uint256 relayerTakerTokenProfit = ammOutputExtra.sub(relayerTakerTokenProfitFee); - // Distribute taker token profit to profit recipient assigned by relayer - _settlement.takerToken.safeTransfer(_settlement.profitRecipient, relayerTakerTokenProfit); - - // Calculate maker fee (maker receives taker token so fee is charged in taker token) - uint256 takerTokenFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); - uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(takerTokenFee); - - // Distribute taker token to maker - _settlement.takerToken.safeTransfer(_settlement.maker, takerTokenForMaker); - - // Collect fee in taker token if any - uint256 feeTotal = takerTokenFee.add(relayerTakerTokenProfitFee); - if (feeTotal > 0) { - _settlement.takerToken.safeTransfer(feeCollector, feeTotal); - } - - // Bypass stack too deep error - _emitLimitOrderFilledByProtocol( - LimitOrderFilledByProtocolParams({ - orderHash: _settlement.orderHash, - maker: _settlement.maker, - taker: _settlement.protocolAddress, - allowFillHash: _settlement.allowFillHash, - relayer: _settlement.relayer, - profitRecipient: _settlement.profitRecipient, - makerToken: address(_settlement.makerToken), - takerToken: address(_settlement.takerToken), - makerTokenFilledAmount: _settlement.makerTokenAmount, - takerTokenFilledAmount: _settlement.takerTokenAmount, - remainingAmount: _settlement.remainingAmount, - makerTokenFee: 0, - takerTokenFee: takerTokenFee, - relayerTakerTokenProfit: relayerTakerTokenProfit, - relayerTakerTokenProfitFee: relayerTakerTokenProfitFee - }) - ); - - return relayerTakerTokenProfit; - } - - function _swapByProtocol(ProtocolSettlement memory _settlement) internal returns (uint256 amountOut) { - _settlement.makerToken.safeApprove(_settlement.protocolAddress, _settlement.makerTokenAmount); - - // UniswapV3 - if (_settlement.protocol == Protocol.UniswapV3) { - amountOut = LibUniswapV3.exactInput( - _settlement.protocolAddress, - LibUniswapV3.ExactInputParams({ - tokenIn: address(_settlement.makerToken), - tokenOut: address(_settlement.takerToken), - path: _settlement.data, - recipient: address(this), - deadline: _settlement.expiry, - amountIn: _settlement.makerTokenAmount, - amountOutMinimum: _settlement.protocolOutMinimum - }) - ); - } else { - // Sushiswap - address[] memory path = abi.decode(_settlement.data, (address[])); - amountOut = LibUniswapV2.swapExactTokensForTokens( - _settlement.protocolAddress, - LibUniswapV2.SwapExactTokensForTokensParams({ - tokenIn: address(_settlement.makerToken), - tokenInAmount: _settlement.makerTokenAmount, - tokenOut: address(_settlement.takerToken), - tokenOutAmountMin: _settlement.protocolOutMinimum, - path: path, - to: address(this), - deadline: _settlement.expiry - }) - ); - } - - _settlement.makerToken.safeApprove(_settlement.protocolAddress, 0); - } - /// @inheritdoc IPionexContract function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderMakerSig) external override onlyUserProxy nonReentrant { require(_order.expiry > uint64(block.timestamp), "LimitOrder: Order is expired"); bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); - bool isCancelled = LibOrderStorage.getStorage().orderHashToCancelled[orderHash]; + bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; require(!isCancelled, "LimitOrder: Order is cancelled already"); { PionexContractLibEIP712.Order memory cancelledOrder = _order; @@ -460,7 +288,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } // Set cancelled state to storage - LibOrderStorage.getStorage().orderHashToCancelled[orderHash] = true; + LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash] = true; emit OrderCancelled(orderHash, _order.maker); } @@ -472,7 +300,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes memory _orderMakerSig ) internal view { require(_order.expiry > uint64(block.timestamp), "LimitOrder: Order is expired"); - bool isCancelled = LibOrderStorage.getStorage().orderHashToCancelled[_orderHash]; + bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[_orderHash]; require(!isCancelled, "LimitOrder: Order is cancelled"); require(isValidSignature(_order.maker, _orderHash, bytes(""), _orderMakerSig), "LimitOrder: Order is not signed by maker"); @@ -488,15 +316,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu PionexContractLibEIP712.Order memory _order, bytes32 _orderHash, uint256 _makerTokenAmount - ) - internal - view - returns ( - uint256, - uint256 - ) - { - uint256 makerTokenFilledAmount = LibOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; + ) internal view returns (uint256, uint256) { + uint256 makerTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; require(makerTokenFilledAmount < _order.makerTokenAmount, "LimitOrder: Order is filled"); @@ -508,44 +329,12 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu return (makerTokenQuota, remainingAfterFill); } - function _quoteOrderFromTakerToken( - PionexContractLibEIP712.Order memory _order, - bytes32 _orderHash, - uint256 _takerTokenAmount - ) - internal - view - returns ( - uint256, - uint256, - uint256 - ) - { - uint256 takerTokenFilledAmount = LibOrderStorage.getStorage().orderHashToTakerTokenFilledAmount[_orderHash]; - - require(takerTokenFilledAmount < _order.takerTokenAmount, "LimitOrder: Order is filled"); - - uint256 takerTokenFillableAmount = _order.takerTokenAmount.sub(takerTokenFilledAmount); - uint256 takerTokenQuota = Math.min(_takerTokenAmount, takerTokenFillableAmount); - uint256 makerTokenQuota = takerTokenQuota.mul(_order.makerTokenAmount).div(_order.takerTokenAmount); - uint256 remainingAfterFill = takerTokenFillableAmount.sub(takerTokenQuota); - - require(makerTokenQuota != 0 && takerTokenQuota != 0, "LimitOrder: zero token amount"); - return (makerTokenQuota, takerTokenQuota, remainingAfterFill); - } - function _recordMakerTokenFilled(bytes32 _orderHash, uint256 _makerTokenAmount) internal { - LibOrderStorage.Storage storage stor = LibOrderStorage.getStorage(); + LibPionexContractOrderStorage.Storage storage stor = LibPionexContractOrderStorage.getStorage(); uint256 makerTokenFilledAmount = stor.orderHashToMakerTokenFilledAmount[_orderHash]; stor.orderHashToMakerTokenFilledAmount[_orderHash] = makerTokenFilledAmount.add(_makerTokenAmount); } - function _recordTakerTokenFilled(bytes32 _orderHash, uint256 _takerTokenAmount) internal { - LibOrderStorage.Storage storage stor = LibOrderStorage.getStorage(); - uint256 takerTokenFilledAmount = stor.orderHashToTakerTokenFilledAmount[_orderHash]; - stor.orderHashToTakerTokenFilledAmount[_orderHash] = takerTokenFilledAmount.add(_takerTokenAmount); - } - /* math utils */ function _mulFactor(uint256 amount, uint256 factor) internal pure returns (uint256) { @@ -587,44 +376,4 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu }) ); } - - struct LimitOrderFilledByProtocolParams { - bytes32 orderHash; - address maker; - address taker; - bytes32 allowFillHash; - address relayer; - address profitRecipient; - address makerToken; - address takerToken; - uint256 makerTokenFilledAmount; - uint256 takerTokenFilledAmount; - uint256 remainingAmount; - uint256 makerTokenFee; - uint256 takerTokenFee; - uint256 relayerTakerTokenProfit; - uint256 relayerTakerTokenProfitFee; - } - - function _emitLimitOrderFilledByProtocol(LimitOrderFilledByProtocolParams memory _params) internal { - emit LimitOrderFilledByProtocol( - _params.orderHash, - _params.maker, - _params.taker, - _params.allowFillHash, - _params.relayer, - _params.profitRecipient, - FillReceipt({ - makerToken: _params.makerToken, - takerToken: _params.takerToken, - makerTokenFilledAmount: _params.makerTokenFilledAmount, - takerTokenFilledAmount: _params.takerTokenFilledAmount, - remainingAmount: _params.remainingAmount, - makerTokenFee: _params.makerTokenFee, - takerTokenFee: _params.takerTokenFee - }), - _params.relayerTakerTokenProfit, - _params.relayerTakerTokenProfitFee - ); - } } diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 411242da..90269e67 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -40,28 +40,6 @@ interface IPionexContract is IStrategyBase { FillReceipt fillReceipt ); - /// @notice Emitted when an order is filled by interacting with an external protocol - /// @param orderHash The EIP-712 hash of the target order - /// @param maker The address of the maker - /// @param taker The address of the taker (trader) - /// @param allowFillHash The EIP-712 hash of the fill permit granted by coordinator - /// @param relayer The address of the relayer - /// @param profitRecipient The address of the recipient which receives relaying profit - /// @param fillReceipt Contains details of this single fill - /// @param relayerTakerTokenProfit Profit that relayer makes from this fill - /// @param relayerTakerTokenProfitFee Protocol fee charged on the relaying profit - event LimitOrderFilledByProtocol( - bytes32 indexed orderHash, - address indexed maker, - address indexed taker, - bytes32 allowFillHash, - address relayer, - address profitRecipient, - FillReceipt fillReceipt, - uint256 relayerTakerTokenProfit, - uint256 relayerTakerTokenProfitFee - ); - /// @notice Emitted when order is cancelled /// @param orderHash The EIP-712 hash of the target order /// @param maker The address of the maker @@ -106,33 +84,6 @@ interface IPionexContract is IStrategyBase { CoordinatorParams calldata _crdParams ) external returns (uint256, uint256); - enum Protocol { - UniswapV3, - Sushiswap - } - - struct ProtocolParams { - Protocol protocol; - bytes data; - address profitRecipient; - uint256 takerTokenAmount; - uint256 protocolOutMinimum; - uint64 expiry; - } - - /// @notice Fill an order by interacting with an external protocol - /// @notice Only user proxy can call - /// @param _order The order that is going to be filled - /// @param _orderMakerSig The signature of the order from maker - /// @param _params Protocol specific filling parameters - /// @param _crdParams Contains details of the fill permit - function fillLimitOrderByProtocol( - PionexContractLibEIP712.Order calldata _order, - bytes calldata _orderMakerSig, - ProtocolParams calldata _params, - CoordinatorParams calldata _crdParams - ) external returns (uint256); - /// @notice Cancel an order /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled diff --git a/contracts/utils/LibOrderStorage.sol b/contracts/utils/LibOrderStorage.sol index fbbea580..30148db1 100644 --- a/contracts/utils/LibOrderStorage.sol +++ b/contracts/utils/LibOrderStorage.sol @@ -9,8 +9,6 @@ library LibOrderStorage { mapping(bytes32 => uint256) orderHashToTakerTokenFilledAmount; // Whether order is cancelled or not. mapping(bytes32 => bool) orderHashToCancelled; - // How much maker token has been filled in order. - mapping(bytes32 => uint256) orderHashToMakerTokenFilledAmount; } /// @dev Get the storage bucket for this contract. diff --git a/contracts/utils/LibPionexContractOrderStorage.sol b/contracts/utils/LibPionexContractOrderStorage.sol new file mode 100644 index 00000000..f465d957 --- /dev/null +++ b/contracts/utils/LibPionexContractOrderStorage.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; + +library LibPionexContractOrderStorage { + bytes32 private constant STORAGE_SLOT = 0x95a5390854dc73a7f7b647527d9be60908d60f6434dd66098c304c2918e6d1a1; + /// @dev Storage bucket for this feature. + struct Storage { + // How much maker token has been filled in order. + mapping(bytes32 => uint256) orderHashToMakerTokenFilledAmount; + // Whether order is cancelled or not. + mapping(bytes32 => bool) orderHashToCancelled; + } + + /// @dev Get the storage bucket for this contract. + function getStorage() internal pure returns (Storage storage stor) { + assert(STORAGE_SLOT == bytes32(uint256(keccak256("pionexcontract.order.storage")) - 1)); + + // Dip into assembly to change the slot pointed to by the local + // variable `stor`. + // See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries + assembly { + stor.slot := STORAGE_SLOT + } + } +} diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index cfa05ab7..57ac4f26 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -15,8 +15,6 @@ import "contracts/utils/LibConstant.sol"; import "test/mocks/MockERC1271Wallet.sol"; import "test/utils/BalanceSnapshot.sol"; import "test/utils/StrategySharedSetup.sol"; -import "test/utils/UniswapV3Util.sol"; -import "test/utils/SushiswapUtil.sol"; import { computeMainnetEIP712DomainSeparator, getEIP712Hash } from "test/utils/Sig.sol"; contract PionexContractTest is StrategySharedSetup { @@ -31,17 +29,6 @@ contract PionexContractTest is StrategySharedSetup { address recipient, IPionexContract.FillReceipt fillReceipt ); - event LimitOrderFilledByProtocol( - bytes32 indexed orderHash, - address indexed maker, - address indexed taker, - bytes32 allowFillHash, - address relayer, - address profitRecipient, - IPionexContract.FillReceipt fillReceipt, - uint256 relayerTakerTokenProfit, - uint256 relayerTakerTokenProfitFee - ); uint256 userPrivateKey = uint256(1); uint256 makerPrivateKey = uint256(2); @@ -64,7 +51,6 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Fill DEFAULT_FILL; PionexContractLibEIP712.AllowFill DEFAULT_ALLOW_FILL; IPionexContract.TraderParams DEFAULT_TRADER_PARAMS; - IPionexContract.ProtocolParams DEFAULT_PROTOCOL_PARAMS; IPionexContract.CoordinatorParams DEFAULT_CRD_PARAMS; PionexContract pionexContract; @@ -110,14 +96,6 @@ contract PionexContractTest is StrategySharedSetup { DEADLINE, // expiry _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // takerSig ); - DEFAULT_PROTOCOL_PARAMS = IPionexContract.ProtocolParams( - IPionexContract.Protocol.UniswapV3, // protocol - hex"6b175474e89094c44da98b954eedeac495271d0f0001f4dac17f958d2ee523a2206206994597c13d831ec7", // Uniswap v3 protocol data - receiver, // profitRecipient - DEFAULT_FILL.takerTokenAmount, // takerTokenAmount - 0, // protocolOutMinimum - DEADLINE // expiry - ); DEFAULT_ALLOW_FILL = PionexContractLibEIP712.AllowFill( DEFAULT_ORDER_HASH, // orderHash user, // executor @@ -159,8 +137,6 @@ contract PionexContractTest is StrategySharedSetup { address(spender), coordinator, FACTORSDEALY, - UNISWAP_V3_ADDRESS, - SUSHISWAP_ADDRESS, feeCollector ); // Setup @@ -195,8 +171,6 @@ contract PionexContractTest is StrategySharedSetup { assertEq(address(pionexContract.spender()), address(spender)); assertEq(address(pionexContract.permStorage()), address(permanentStorage)); assertEq(address(pionexContract.weth()), address(weth)); - assertEq(pionexContract.uniswapV3RouterAddress(), UNISWAP_V3_ADDRESS); - assertEq(pionexContract.sushiswapRouterAddress(), SUSHISWAP_ADDRESS); assertEq(uint256(pionexContract.makerFeeFactor()), 0); assertEq(uint256(pionexContract.takerFeeFactor()), 0); @@ -990,417 +964,6 @@ contract PionexContractTest is StrategySharedSetup { makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); } - /********************************* - *Test: fillLimitOrderByProtocol * - *********************************/ - - function testCannotFillByUniswapV3LessThanProtocolOutMinimum() public { - // get quote from AMM - uint256 ammTakerTokenOut = quoteUniswapV3ExactInput(UNISWAP_V3_QUOTER_ADDRESS, DEFAULT_PROTOCOL_PARAMS.data, DEFAULT_ORDER.makerTokenAmount); - - IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; - protocolParams.protocolOutMinimum = ammTakerTokenOut.mul(2); // require 2x output from AMM - - // Allow fill is bound by tx.origin in protocol case. - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("Too little received"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillBySushiSwapLessThanProtocolOutMinimum() public { - // get quote from AMM - uint256[] memory amountOuts = getSushiAmountsOut(SUSHISWAP_ADDRESS, DEFAULT_ORDER.makerTokenAmount, DEFAULT_AMM_PATH); - - address[] memory path = DEFAULT_AMM_PATH; - IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; - protocolParams.protocol = IPionexContract.Protocol.Sushiswap; - protocolParams.protocolOutMinimum = amountOuts[1].mul(2); // require 2x output from AMM - protocolParams.data = abi.encode(path); - - // Allow fill is bound by tx.origin in protocol case. - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolIfNotFromUserProxy() public { - vm.expectRevert("Strategy: not from UserProxy contract"); - // Call limit order contract directly will get reverted since msg.sender is not from UserProxy - pionexContract.fillLimitOrderByProtocol(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); - } - - function testCannotFillFilledOrderByProtocol() public { - // Fullly fill the default order first - vm.startPrank(user, user); - bytes memory payload1 = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); - userProxy.toLimitOrder(payload1); - vm.stopPrank(); - - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.salt = uint256(8002); - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - crdParams.salt = allowFill.salt; - - vm.startPrank(user, user); - bytes memory payload2 = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: Order is filled"); - userProxy.toLimitOrder(payload2); - vm.stopPrank(); - } - - function testCannotFillExpiredOrderByProtocol() public { - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - order.expiry = uint64(block.timestamp - 1); - - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); - - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.orderHash = orderHash; - - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = orderHash; - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - bytes memory payload = _genFillByProtocolPayload(order, orderMakerSig, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: Order is expired"); - vm.prank(user, user); // Only EOA - userProxy.toLimitOrder(payload); - } - - function testCannotFillByProtocolWithWrongMakerSig() public { - bytes memory wrongMakerSig = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); - - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Order is not signed by maker"); - vm.prank(user, user); // Only EOA - userProxy.toLimitOrder(payload); - } - - function testCannotFillByProtocolWithTakerOtherThanOrderSpecified() public { - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify taker address - order.taker = SUSHISWAP_ADDRESS; - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); - - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = orderHash; - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(order, orderMakerSig, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: Order cannot be filled by this taker"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolWithExpiredFill() public { - IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; - protocolParams.expiry = uint64(block.timestamp - 1); - - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); - // Revert caused by Uniswap V3 - vm.expectRevert("Transaction too old"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolIfPriceNotMatch() public { - // Order with unreasonable price - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - order.takerTokenAmount = 9000 * 1e6; - - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); - - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = orderHash; - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(order, orderMakerSig, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: Insufficient token amount out from protocol"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolWithWrongAllowFill() public { - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - // Set the executor to maker (not user) - allowFill.executor = maker; - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - // Fill order using user (not executor) - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocoWithAlteredOrderHash() public { - // Replace orderHash in allowFill - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = bytes32(0); - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - // Allow fill is bound by tx.origin in protocol case. - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocoWithAlteredExecutor() public { - // Set the executor to maker (not user) - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.executor = maker; - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - // Fill order using user (not executor) - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocoWithAlteredFillAmount() public { - // Change fill amount in allow fill - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = DEFAULT_ALLOW_FILL.fillAmount.div(2); - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - // Allow fill is bound by tx.origin in protocol case. - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolWithAllowFillNotSignedByCoordinator() public { - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - // Sign allow fill using user's private key - crdParams.sig = _signAllowFill(userPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); - - vm.startPrank(user, user); - - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolWithReplayedAllowFill() public { - // Fill with default allow fill - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); - userProxy.toLimitOrder(payload); - - vm.expectRevert("PermanentStorage: allow fill seen before"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testCannotFillByProtocolWithZeroProfitRecipient() public { - IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; - protocolParams.profitRecipient = address(0); - - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, protocolParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: profitRecipient can not be zero address"); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - } - - function testFullyFillByUniswapV3WithEvent() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverTakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); - - // makerFeeFactor/takerFeeFactor : 10% - // profitFeeFactor : 20% - vm.startPrank(owner, owner); - pionexContract.setFactors(1000, 1000, 2000); - vm.warp(block.timestamp + pionexContract.factorActivateDelay()); - pionexContract.activateFactors(); - vm.stopPrank(); - - // get quote from AMM - uint256 ammTakerTokenOut = quoteUniswapV3ExactInput(UNISWAP_V3_QUOTER_ADDRESS, DEFAULT_PROTOCOL_PARAMS.data, DEFAULT_ORDER.makerTokenAmount); - uint256 ammOutputExtra = ammTakerTokenOut.sub(DEFAULT_ORDER.takerTokenAmount); - uint256 relayerTakerTokenProfitFee = ammOutputExtra.mul(20).div(100); - - // Allow fill is bound by tx.origin in protocol case. - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_PROTOCOL_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectEmit(true, true, true, true); - emit LimitOrderFilledByProtocol( - DEFAULT_ORDER_HASH, - DEFAULT_ORDER.maker, - UNISWAP_V3_ADDRESS, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), - user, - receiver, - IPionexContract.FillReceipt( - address(DEFAULT_ORDER.makerToken), - address(DEFAULT_ORDER.takerToken), - DEFAULT_ORDER.makerTokenAmount, - DEFAULT_ORDER.takerTokenAmount, - 0, // remainingAmount should be zero after order fully filled - 0, // makerTokenFee should be zero in protocol case - DEFAULT_ORDER.takerTokenAmount.mul(10).div(100) // takerTokenFee = 10% takerTokenAmount - ), - ammOutputExtra.sub(relayerTakerTokenProfitFee), // relayerTakerTokenProfit - relayerTakerTokenProfitFee // relayerTakerTokenProfitFee - ); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - - userTakerAsset.assertChange(0); - // To avoid precision issue, use great than instead - receiverTakerAsset.assertChangeGt(int256(ammOutputExtra.mul(80).div(100))); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(90).div(100))); - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); - - // fee = taker fee + relayer profit fee - uint256 fee = DEFAULT_ORDER.takerTokenAmount.mul(10).div(100); - fee = fee.add(relayerTakerTokenProfitFee); - fcTakerAsset.assertChangeGt(int256(fee)); - } - - function testFillByProtocolRelayerProfit() public { - address relayer = 0x52D82cD20F092DB55fb1e006a2C2773AB17F6Ff2; - BalanceSnapshot.Snapshot memory relayerTakerAsset = BalanceSnapshot.take(relayer, address(DEFAULT_ORDER.takerToken)); - - // set order with extreme low price leaving huge profit for relayer - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - order.takerTokenAmount = 1 * 1e6; - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory makerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); - - // update protocolParams - IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; - protocolParams.takerTokenAmount = order.takerTokenAmount; - protocolParams.profitRecipient = relayer; - - // update allowFill - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = orderHash; - allowFill.executor = relayer; - allowFill.fillAmount = order.takerTokenAmount; - - // update crdParams - IPionexContract.CoordinatorParams memory crdParams = IPionexContract.CoordinatorParams( - _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712), - allowFill.salt, - allowFill.expiry - ); - - // get expected profit for relayer - uint256 ammOutputExtra = quoteUniswapV3ExactInput(UNISWAP_V3_QUOTER_ADDRESS, protocolParams.data, order.makerTokenAmount).sub(order.takerTokenAmount); - - vm.startPrank(relayer, relayer); - vm.expectEmit(true, true, true, true); - IPionexContract.FillReceipt memory fillReceipt = IPionexContract.FillReceipt( - address(order.makerToken), - address(order.takerToken), - order.makerTokenAmount, - order.takerTokenAmount, - 0, // remainingAmount should be zero after order fully filled - 0, // makerTokenFee should be zero in protocol case - 0 // takerTokenFee = 0 since feeFactor = 0 - ); - emit LimitOrderFilledByProtocol( - orderHash, - order.maker, - UNISWAP_V3_ADDRESS, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), - relayer, // relayer - relayer, // profitRecipient - fillReceipt, - ammOutputExtra, // relayerTakerTokenProfit - 0 // profit fee = 0 - ); - userProxy.toLimitOrder(_genFillByProtocolPayload(order, makerSig, protocolParams, crdParams)); - vm.stopPrank(); - - // whole profit should be given to relayer - relayerTakerAsset.assertChange(int256(ammOutputExtra)); - // no token should left in pionexContract - assertEq(order.makerToken.balanceOf(address(pionexContract)), 0); - assertEq(order.takerToken.balanceOf(address(pionexContract)), 0); - } - - function testFullyFillBySushiSwap() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverTakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); - - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - order.makerTokenAmount = 10 * 1e18; - order.takerTokenAmount = 8 * 1e6; - - // get quote from AMM - address[] memory path = DEFAULT_AMM_PATH; - uint256[] memory amountOuts = getSushiAmountsOut(SUSHISWAP_ADDRESS, order.makerTokenAmount, path); - // Since profitFeeFactor is zero, so the extra token from AMM is the profit for relayer. - uint256 profit = amountOuts[amountOuts.length - 1].sub(order.takerTokenAmount); - - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerHash = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); - - IPionexContract.ProtocolParams memory protocolParams = DEFAULT_PROTOCOL_PARAMS; - protocolParams.protocol = IPionexContract.Protocol.Sushiswap; - protocolParams.takerTokenAmount = order.takerTokenAmount; - protocolParams.data = abi.encode(path); - - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = orderHash; - allowFill.fillAmount = protocolParams.takerTokenAmount; - - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - - // Allow fill is bound by tx.origin in protocol case. - vm.startPrank(user, user); - bytes memory payload = _genFillByProtocolPayload(order, orderMakerHash, protocolParams, crdParams); - userProxy.toLimitOrder(payload); - vm.stopPrank(); - - userTakerAsset.assertChange(0); - receiverTakerAsset.assertChange(int256(profit)); - makerTakerAsset.assertChange(int256(order.takerTokenAmount)); - makerMakerAsset.assertChange(-int256(order.makerTokenAmount)); - } - /********************************* * cancelLimitOrder * *********************************/ @@ -1577,15 +1140,6 @@ contract PionexContractTest is StrategySharedSetup { return abi.encodeWithSelector(pionexContract.fillLimitOrderByTrader.selector, order, orderMakerSig, params, crdParams); } - function _genFillByProtocolPayload( - PionexContractLibEIP712.Order memory order, - bytes memory orderMakerSig, - IPionexContract.ProtocolParams memory params, - IPionexContract.CoordinatorParams memory crdParams - ) internal view returns (bytes memory payload) { - return abi.encodeWithSelector(pionexContract.fillLimitOrderByProtocol.selector, order, orderMakerSig, params, crdParams); - } - function _genCancelLimitOrderPayload(PionexContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) internal view From edd03822bed76431452a77d2103d006a6317885c Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 23 May 2023 15:51:51 +0800 Subject: [PATCH 15/41] Remove takerFeeFactor --- contracts/PionexContract.sol | 30 ++++-------------------- contracts/interfaces/IPionexContract.sol | 4 +--- test/forkMainnet/PionexContract.t.sol | 25 +++++++------------- 3 files changed, 13 insertions(+), 46 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 77d952f1..c0ae851c 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -37,8 +37,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 public factorsTimeLock; uint16 public makerFeeFactor = 0; uint16 public pendingMakerFeeFactor; - uint16 public takerFeeFactor = 0; - uint16 public pendingTakerFeeFactor; uint16 public profitFeeFactor = 0; uint16 public pendingProfitFeeFactor; @@ -70,19 +68,12 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _makerFeeFactor The new fee factor for maker - /// @param _takerFeeFactor The new fee factor for taker /// @param _profitFeeFactor The new fee factor for relayer profit - function setFactors( - uint16 _makerFeeFactor, - uint16 _takerFeeFactor, - uint16 _profitFeeFactor - ) external onlyOwner { + function setFactors(uint16 _makerFeeFactor, uint16 _profitFeeFactor) external onlyOwner { require(_makerFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid maker fee factor"); - require(_takerFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid taker fee factor"); require(_profitFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid profit fee factor"); pendingMakerFeeFactor = _makerFeeFactor; - pendingTakerFeeFactor = _takerFeeFactor; pendingProfitFeeFactor = _profitFeeFactor; factorsTimeLock = block.timestamp + factorActivateDelay; @@ -94,13 +85,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(block.timestamp >= factorsTimeLock, "LimitOrder: fee factors timelocked"); factorsTimeLock = 0; makerFeeFactor = pendingMakerFeeFactor; - takerFeeFactor = pendingTakerFeeFactor; profitFeeFactor = pendingProfitFeeFactor; pendingMakerFeeFactor = 0; - pendingTakerFeeFactor = 0; pendingProfitFeeFactor = 0; - emit FactorsUpdated(makerFeeFactor, takerFeeFactor, profitFeeFactor); + emit FactorsUpdated(makerFeeFactor, profitFeeFactor); } /// @notice Only owner can call @@ -233,24 +222,16 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 takerTokenFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(takerTokenFee); - // Calculate taker fee (taker receives maker token so fee is charged in maker token) - uint256 makerTokenFee = _mulFactor(_settlement.makerTokenAmount, takerFeeFactor); - uint256 makerTokenForTrader = _settlement.makerTokenAmount.sub(makerTokenFee); - // trader -> maker _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _settlement.maker, takerTokenForMaker); // maker -> recipient - _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _settlement.recipient, makerTokenForTrader); + _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _settlement.recipient, _settlement.makerTokenAmount); // Collect maker fee (charged in taker token) if (takerTokenFee > 0) { _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _feeCollector, takerTokenFee); } - // Collect taker fee (charged in maker token) - if (makerTokenFee > 0) { - _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _feeCollector, makerTokenFee); - } // bypass stack too deep error _emitLimitOrderFilledByTrader( @@ -265,12 +246,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu makerTokenFilledAmount: _settlement.makerTokenAmount, takerTokenFilledAmount: _settlement.takerTokenAmount, remainingAmount: _settlement.remainingAmount, - makerTokenFee: makerTokenFee, takerTokenFee: takerTokenFee }) ); - return makerTokenForTrader; + return _settlement.makerTokenAmount; } /// @inheritdoc IPionexContract @@ -354,7 +334,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 makerTokenFilledAmount; uint256 takerTokenFilledAmount; uint256 remainingAmount; - uint256 makerTokenFee; uint256 takerTokenFee; } @@ -371,7 +350,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu makerTokenFilledAmount: _params.makerTokenFilledAmount, takerTokenFilledAmount: _params.takerTokenFilledAmount, remainingAmount: _params.remainingAmount, - makerTokenFee: _params.makerTokenFee, takerTokenFee: _params.takerTokenFee }) ); diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 90269e67..b236b308 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -16,9 +16,8 @@ interface IPionexContract is IStrategyBase { /// @notice Emitted when fee factors are updated /// @param makerFeeFactor The new fee factor for maker - /// @param takerFeeFactor The new fee factor for taker /// @param profitFeeFactor The new fee factor for relayer profit - event FactorsUpdated(uint16 makerFeeFactor, uint16 takerFeeFactor, uint16 profitFeeFactor); + event FactorsUpdated(uint16 makerFeeFactor, uint16 profitFeeFactor); /// @notice Emitted when fee collector address is updated /// @param newFeeCollector The address of the new fee collector @@ -51,7 +50,6 @@ interface IPionexContract is IStrategyBase { uint256 makerTokenFilledAmount; uint256 takerTokenFilledAmount; uint256 remainingAmount; - uint256 makerTokenFee; uint256 takerTokenFee; } diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 57ac4f26..eed18bad 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -173,7 +173,6 @@ contract PionexContractTest is StrategySharedSetup { assertEq(address(pionexContract.weth()), address(weth)); assertEq(uint256(pionexContract.makerFeeFactor()), 0); - assertEq(uint256(pionexContract.takerFeeFactor()), 0); assertEq(uint256(pionexContract.profitFeeFactor()), 0); } @@ -301,23 +300,18 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetFactorsIfLargerThanBpsMax() public { vm.expectRevert("LimitOrder: Invalid maker fee factor"); vm.prank(owner, owner); - pionexContract.setFactors(LibConstant.BPS_MAX + 1, 1, 1); - - vm.expectRevert("LimitOrder: Invalid taker fee factor"); - vm.prank(owner, owner); - pionexContract.setFactors(1, LibConstant.BPS_MAX + 1, 1); + pionexContract.setFactors(LibConstant.BPS_MAX + 1, 1); vm.expectRevert("LimitOrder: Invalid profit fee factor"); vm.prank(owner, owner); - pionexContract.setFactors(1, 1, LibConstant.BPS_MAX + 1); + pionexContract.setFactors(1, LibConstant.BPS_MAX + 1); } function testSetFactors() public { vm.startPrank(owner, owner); - pionexContract.setFactors(1, 2, 3); + pionexContract.setFactors(1, 2); // fee factors should stay same before new ones activate assertEq(uint256(pionexContract.makerFeeFactor()), 0); - assertEq(uint256(pionexContract.takerFeeFactor()), 0); assertEq(uint256(pionexContract.profitFeeFactor()), 0); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); @@ -325,8 +319,7 @@ contract PionexContractTest is StrategySharedSetup { pionexContract.activateFactors(); vm.stopPrank(); assertEq(uint256(pionexContract.makerFeeFactor()), 1); - assertEq(uint256(pionexContract.takerFeeFactor()), 2); - assertEq(uint256(pionexContract.profitFeeFactor()), 3); + assertEq(uint256(pionexContract.profitFeeFactor()), 2); } /********************************* @@ -638,10 +631,10 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); - // makerFeeFactor/takerFeeFactor : 10% + // makerFeeFactor : 10% // profitFeeFactor : 20% vm.startPrank(owner, owner); - pionexContract.setFactors(1000, 1000, 2000); + pionexContract.setFactors(1000, 2000); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); pionexContract.activateFactors(); vm.stopPrank(); @@ -660,7 +653,6 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER.makerTokenAmount, DEFAULT_ORDER.takerTokenAmount, 0, // remainingAmount should be zero after order fully filled - DEFAULT_ORDER.makerTokenAmount.mul(10).div(100), // makerTokenFee = 10% makerTokenAmount DEFAULT_ORDER.takerTokenAmount.mul(10).div(100) // takerTokenFee = 10% takerTokenAmount ) ); @@ -668,10 +660,10 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.mul(90).div(100))); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(90).div(100))); makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); - fcMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.mul(10).div(100))); + fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(10).div(100))); } @@ -711,7 +703,6 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER.makerTokenAmount, fill.takerTokenAmount, 0, // remainingAmount should be zero after order fully filled - 0, 0 ) ); From a95f4076df6094c39804f8bd47dea993467d06a7 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 23 May 2023 15:53:57 +0800 Subject: [PATCH 16/41] Remove profitFeeFactor --- contracts/PionexContract.sol | 11 ++--------- contracts/interfaces/IPionexContract.sol | 3 +-- test/forkMainnet/PionexContract.t.sol | 14 +++----------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index c0ae851c..e534dab3 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -37,8 +37,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 public factorsTimeLock; uint16 public makerFeeFactor = 0; uint16 public pendingMakerFeeFactor; - uint16 public profitFeeFactor = 0; - uint16 public pendingProfitFeeFactor; constructor( address _owner, @@ -68,13 +66,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _makerFeeFactor The new fee factor for maker - /// @param _profitFeeFactor The new fee factor for relayer profit - function setFactors(uint16 _makerFeeFactor, uint16 _profitFeeFactor) external onlyOwner { + function setFactors(uint16 _makerFeeFactor) external onlyOwner { require(_makerFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid maker fee factor"); - require(_profitFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid profit fee factor"); pendingMakerFeeFactor = _makerFeeFactor; - pendingProfitFeeFactor = _profitFeeFactor; factorsTimeLock = block.timestamp + factorActivateDelay; } @@ -85,11 +80,9 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(block.timestamp >= factorsTimeLock, "LimitOrder: fee factors timelocked"); factorsTimeLock = 0; makerFeeFactor = pendingMakerFeeFactor; - profitFeeFactor = pendingProfitFeeFactor; pendingMakerFeeFactor = 0; - pendingProfitFeeFactor = 0; - emit FactorsUpdated(makerFeeFactor, profitFeeFactor); + emit FactorsUpdated(makerFeeFactor); } /// @notice Only owner can call diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index b236b308..9bf1a159 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -16,8 +16,7 @@ interface IPionexContract is IStrategyBase { /// @notice Emitted when fee factors are updated /// @param makerFeeFactor The new fee factor for maker - /// @param profitFeeFactor The new fee factor for relayer profit - event FactorsUpdated(uint16 makerFeeFactor, uint16 profitFeeFactor); + event FactorsUpdated(uint16 makerFeeFactor); /// @notice Emitted when fee collector address is updated /// @param newFeeCollector The address of the new fee collector diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index eed18bad..6cb8eaf7 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -173,7 +173,6 @@ contract PionexContractTest is StrategySharedSetup { assertEq(address(pionexContract.weth()), address(weth)); assertEq(uint256(pionexContract.makerFeeFactor()), 0); - assertEq(uint256(pionexContract.profitFeeFactor()), 0); } /********************************* @@ -300,26 +299,20 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetFactorsIfLargerThanBpsMax() public { vm.expectRevert("LimitOrder: Invalid maker fee factor"); vm.prank(owner, owner); - pionexContract.setFactors(LibConstant.BPS_MAX + 1, 1); - - vm.expectRevert("LimitOrder: Invalid profit fee factor"); - vm.prank(owner, owner); - pionexContract.setFactors(1, LibConstant.BPS_MAX + 1); + pionexContract.setFactors(LibConstant.BPS_MAX + 1); } function testSetFactors() public { vm.startPrank(owner, owner); - pionexContract.setFactors(1, 2); + pionexContract.setFactors(1); // fee factors should stay same before new ones activate assertEq(uint256(pionexContract.makerFeeFactor()), 0); - assertEq(uint256(pionexContract.profitFeeFactor()), 0); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); // fee factors should be updated now pionexContract.activateFactors(); vm.stopPrank(); assertEq(uint256(pionexContract.makerFeeFactor()), 1); - assertEq(uint256(pionexContract.profitFeeFactor()), 2); } /********************************* @@ -632,9 +625,8 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); // makerFeeFactor : 10% - // profitFeeFactor : 20% vm.startPrank(owner, owner); - pionexContract.setFactors(1000, 2000); + pionexContract.setFactors(1000); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); pionexContract.activateFactors(); vm.stopPrank(); From b0e49411220ffb18cb96eaeed6286417bd026c29 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 23 May 2023 17:12:44 +0800 Subject: [PATCH 17/41] Add Pionex fee factors: gas fee and strategy fee --- contracts/PionexContract.sol | 33 ++++++++++++++++++------ contracts/interfaces/IPionexContract.sol | 5 +++- test/forkMainnet/PionexContract.t.sol | 19 +++++++++++--- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index e534dab3..316d35d6 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -113,6 +113,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _params.takerTokenAmount.mul(_order.makerTokenAmount) >= _order.takerTokenAmount.mul(_params.makerTokenAmount), "LimitOrder: taker/maker token ratio not good enough" ); + // Check gas fee factor and pionex strategy fee factor do not exceed limit + require( + (_params.gasFeeFactor <= LibConstant.BPS_MAX) && + (_params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX) && + (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - makerFeeFactor), + "LimitOrder: Invalid pionex fee factor" + ); { PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ @@ -143,7 +150,9 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu takerToken: _order.takerToken, makerTokenAmount: makerTokenAmount, takerTokenAmount: takerTokenAmount, - remainingAmount: remainingAmount + remainingAmount: remainingAmount, + gasFeeFactor: _params.gasFeeFactor, + pionexStrategyFeeFactor: _params.pionexStrategyFeeFactor }) ); @@ -204,6 +213,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 makerTokenAmount; uint256 takerTokenAmount; uint256 remainingAmount; + uint16 gasFeeFactor; + uint16 pionexStrategyFeeFactor; } function _settleForTrader(TraderSettlement memory _settlement) internal returns (uint256) { @@ -212,8 +223,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address _feeCollector = feeCollector; // Calculate maker fee (maker receives taker token so fee is charged in taker token) - uint256 takerTokenFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); - uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(takerTokenFee); + // 1. Fee for Tokenlon + uint256 tokenlonFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); + // 2. Fee for Pionex, including gas fee and strategy fee + uint256 pionexFee = _mulFactor(_settlement.takerTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); + uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(tokenlonFee).sub(pionexFee); // trader -> maker _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _settlement.maker, takerTokenForMaker); @@ -222,8 +236,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _settlement.recipient, _settlement.makerTokenAmount); // Collect maker fee (charged in taker token) - if (takerTokenFee > 0) { - _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _feeCollector, takerTokenFee); + if (tokenlonFee > 0) { + _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _feeCollector, tokenlonFee); } // bypass stack too deep error @@ -239,7 +253,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu makerTokenFilledAmount: _settlement.makerTokenAmount, takerTokenFilledAmount: _settlement.takerTokenAmount, remainingAmount: _settlement.remainingAmount, - takerTokenFee: takerTokenFee + tokenlonFee: tokenlonFee, + pionexFee: pionexFee }) ); @@ -327,7 +342,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 makerTokenFilledAmount; uint256 takerTokenFilledAmount; uint256 remainingAmount; - uint256 takerTokenFee; + uint256 tokenlonFee; + uint256 pionexFee; } function _emitLimitOrderFilledByTrader(LimitOrderFilledByTraderParams memory _params) internal { @@ -343,7 +359,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu makerTokenFilledAmount: _params.makerTokenFilledAmount, takerTokenFilledAmount: _params.takerTokenFilledAmount, remainingAmount: _params.remainingAmount, - takerTokenFee: _params.takerTokenFee + tokenlonFee: _params.tokenlonFee, + pionexFee: _params.pionexFee }) ); } diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 9bf1a159..8b1dc850 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -49,7 +49,8 @@ interface IPionexContract is IStrategyBase { uint256 makerTokenFilledAmount; uint256 takerTokenFilledAmount; uint256 remainingAmount; - uint256 takerTokenFee; + uint256 tokenlonFee; + uint256 pionexFee; } struct CoordinatorParams { @@ -63,6 +64,8 @@ interface IPionexContract is IStrategyBase { address recipient; uint256 makerTokenAmount; uint256 takerTokenAmount; + uint16 gasFeeFactor; + uint16 pionexStrategyFeeFactor; uint256 salt; uint64 expiry; bytes takerSig; diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 6cb8eaf7..c8355992 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -50,6 +50,8 @@ contract PionexContractTest is StrategySharedSetup { bytes DEFAULT_ORDER_MAKER_SIG; PionexContractLibEIP712.Fill DEFAULT_FILL; PionexContractLibEIP712.AllowFill DEFAULT_ALLOW_FILL; + uint16 DEFAULT_GAS_FEE_FACTOR = 0; + uint16 DEFAULT_PIONEX_STRATEGY_FEE_FACTOR = 0; IPionexContract.TraderParams DEFAULT_TRADER_PARAMS; IPionexContract.CoordinatorParams DEFAULT_CRD_PARAMS; @@ -92,6 +94,8 @@ contract PionexContractTest is StrategySharedSetup { receiver, // recipient DEFAULT_FILL.makerTokenAmount, // makerTokenAmount DEFAULT_FILL.takerTokenAmount, // takerTokenAmount + DEFAULT_GAS_FEE_FACTOR, // gas fee factor + DEFAULT_PIONEX_STRATEGY_FEE_FACTOR, // pionex strategy fee factor DEFAULT_FILL.takerSalt, // salt DEADLINE, // expiry _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // takerSig @@ -631,7 +635,12 @@ contract PionexContractTest is StrategySharedSetup { pionexContract.activateFactors(); vm.stopPrank(); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% + traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% + traderParams.takerSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectEmit(true, true, true, true); emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, @@ -645,15 +654,16 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER.makerTokenAmount, DEFAULT_ORDER.takerTokenAmount, 0, // remainingAmount should be zero after order fully filled - DEFAULT_ORDER.takerTokenAmount.mul(10).div(100) // takerTokenFee = 10% takerTokenAmount + DEFAULT_ORDER.takerTokenAmount.mul(10).div(100), // tokenlonFee = 10% takerTokenAmount + DEFAULT_ORDER.takerTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% takerTokenAmount ) ); vm.prank(user, user); // Only EOA userProxy.toLimitOrder(payload); - userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); + userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(97).div(100))); // 3% fee is deducted from takerTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(90).div(100))); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(87).div(100))); makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(10).div(100))); @@ -695,6 +705,7 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER.makerTokenAmount, fill.takerTokenAmount, 0, // remainingAmount should be zero after order fully filled + 0, 0 ) ); From 17c44207718d36c9936e42d6646f9d6123d47aa9 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 23 May 2023 17:14:51 +0800 Subject: [PATCH 18/41] Rename user to pionex in tests --- test/forkMainnet/PionexContract.t.sol | 219 +++++++++++++------------- 1 file changed, 111 insertions(+), 108 deletions(-) diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index c8355992..2fa216c0 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -30,18 +30,18 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.FillReceipt fillReceipt ); - uint256 userPrivateKey = uint256(1); + uint256 pionexPrivateKey = uint256(1); uint256 makerPrivateKey = uint256(2); uint256 coordinatorPrivateKey = uint256(3); - address user = vm.addr(userPrivateKey); + address pionex = vm.addr(pionexPrivateKey); address maker = vm.addr(makerPrivateKey); address coordinator = vm.addr(coordinatorPrivateKey); address owner = makeAddr("owner"); address feeCollector = makeAddr("feeCollector"); address receiver = makeAddr("receiver"); - MockERC1271Wallet mockERC1271Wallet = new MockERC1271Wallet(user); - address[] wallet = [user, maker, coordinator, address(mockERC1271Wallet)]; + MockERC1271Wallet mockERC1271Wallet = new MockERC1271Wallet(pionex); + address[] wallet = [pionex, maker, coordinator, address(mockERC1271Wallet)]; address[] allowanceAddrs; address[] DEFAULT_AMM_PATH; @@ -82,7 +82,7 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER_MAKER_SIG = _signOrder(makerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); DEFAULT_FILL = PionexContractLibEIP712.Fill( DEFAULT_ORDER_HASH, - user, + pionex, receiver, DEFAULT_ORDER.makerTokenAmount, DEFAULT_ORDER.takerTokenAmount, @@ -90,7 +90,7 @@ contract PionexContractTest is StrategySharedSetup { DEADLINE ); DEFAULT_TRADER_PARAMS = IPionexContract.TraderParams( - user, // taker + pionex, // taker receiver, // recipient DEFAULT_FILL.makerTokenAmount, // makerTokenAmount DEFAULT_FILL.takerTokenAmount, // takerTokenAmount @@ -98,11 +98,11 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_PIONEX_STRATEGY_FEE_FACTOR, // pionex strategy fee factor DEFAULT_FILL.takerSalt, // salt DEADLINE, // expiry - _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // takerSig + _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // takerSig ); DEFAULT_ALLOW_FILL = PionexContractLibEIP712.AllowFill( DEFAULT_ORDER_HASH, // orderHash - user, // executor + pionex, // executor DEFAULT_FILL.takerTokenAmount, // fillAmount uint256(1003), // salt DEADLINE // expiry @@ -117,12 +117,12 @@ contract PionexContractTest is StrategySharedSetup { dealWallet(wallet, 100 ether); // Set token balance and approve tokens = [weth, usdt, dai]; - setEOABalanceAndApprove(user, tokens, 10000); + setEOABalanceAndApprove(pionex, tokens, 10000); setEOABalanceAndApprove(maker, tokens, 10000); setEOABalanceAndApprove(address(mockERC1271Wallet), tokens, 10000); // Label addresses for easier debugging - vm.label(user, "User"); + vm.label(pionex, "Pionex"); vm.label(maker, "Maker"); vm.label(coordinator, "Coordinator"); vm.label(receiver, "Receiver"); @@ -185,22 +185,22 @@ contract PionexContractTest is StrategySharedSetup { function testCannotTransferOwnershipByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); - pionexContract.nominateNewOwner(user); + vm.prank(pionex); + pionexContract.nominateNewOwner(pionex); } function testCannotAcceptOwnershipIfNotNominated() public { vm.expectRevert("not nominated"); - vm.prank(user); + vm.prank(pionex); pionexContract.acceptOwnership(); } function testTransferOwnership() public { vm.prank(owner, owner); - pionexContract.nominateNewOwner(user); - vm.prank(user); + pionexContract.nominateNewOwner(pionex); + vm.prank(pionex); pionexContract.acceptOwnership(); - assertEq(pionexContract.owner(), user); + assertEq(pionexContract.owner(), pionex); } /********************************* @@ -209,8 +209,8 @@ contract PionexContractTest is StrategySharedSetup { function testCannotUpgradeSpenderByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); - pionexContract.upgradeSpender(user); + vm.prank(pionex); + pionexContract.upgradeSpender(pionex); } function testCannotUpgradeSpenderToZeroAddr() public { @@ -221,8 +221,8 @@ contract PionexContractTest is StrategySharedSetup { function testUpgradeSpender() public { vm.prank(owner, owner); - pionexContract.upgradeSpender(user); - assertEq(address(pionexContract.spender()), user); + pionexContract.upgradeSpender(pionex); + assertEq(address(pionexContract.spender()), pionex); } /********************************* @@ -231,8 +231,8 @@ contract PionexContractTest is StrategySharedSetup { function testCannotUpgradeCoordinatorByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); - pionexContract.upgradeCoordinator(user); + vm.prank(pionex); + pionexContract.upgradeCoordinator(pionex); } function testCannotUpgradeCoordinatorToZeroAddr() public { @@ -243,8 +243,8 @@ contract PionexContractTest is StrategySharedSetup { function testUpgradeCoordinator() public { vm.prank(owner, owner); - pionexContract.upgradeCoordinator(user); - assertEq(address(pionexContract.coordinator()), user); + pionexContract.upgradeCoordinator(pionex); + assertEq(address(pionexContract.coordinator()), pionex); } /********************************* @@ -253,13 +253,13 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetAllowanceByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); + vm.prank(pionex); pionexContract.setAllowance(allowanceAddrs, address(allowanceTarget)); } function testCannotCloseAllowanceByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); + vm.prank(pionex); pionexContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); } @@ -283,7 +283,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotDepositETHByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); + vm.prank(pionex); pionexContract.depositETH(); } @@ -325,7 +325,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetFeeCollectorByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(user); + vm.prank(pionex); pionexContract.setFeeCollector(feeCollector); } @@ -337,8 +337,8 @@ contract PionexContractTest is StrategySharedSetup { function testSetFeeCollector() public { vm.prank(owner, owner); - pionexContract.setFeeCollector(user); - assertEq(address(pionexContract.feeCollector()), user); + pionexContract.setFeeCollector(pionex); + assertEq(address(pionexContract.feeCollector()), pionex); } /********************************* @@ -354,7 +354,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillFilledOrderByTrader() public { // Fullly fill the default order first bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload1); // Try to fill the default order, should fail @@ -362,7 +362,7 @@ contract PionexContractTest is StrategySharedSetup { fill.takerSalt = uint256(8001); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.salt = fill.takerSalt; PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; @@ -374,7 +374,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectRevert("LimitOrder: Order is filled"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload2); } @@ -389,7 +389,7 @@ contract PionexContractTest is StrategySharedSetup { fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -399,16 +399,16 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); vm.expectRevert("LimitOrder: Order is expired"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWrongMakerSig() public { - bytes memory wrongMakerSig = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); + bytes memory wrongMakerSig = _signOrder(pionexPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: Order is not signed by maker"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -418,7 +418,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: Fill is not signed by taker"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -433,8 +433,8 @@ contract PionexContractTest is StrategySharedSetup { fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - // user try to fill this order - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + // pionex try to fill this order + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -444,7 +444,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); vm.expectRevert("LimitOrder: Order cannot be filled by this taker"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -453,19 +453,19 @@ contract PionexContractTest is StrategySharedSetup { fill.expiry = uint64(block.timestamp - 1); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.expiry = fill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: Fill request is expired"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotReplayFill() public { // Fill with DEFAULT_FILL bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload1); // Try to fill with same fill request with differnt allowFill (otherwise will revert by dup allowFill) @@ -478,7 +478,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PermanentStorage: transaction seen before"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload2); } @@ -495,7 +495,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectRevert("LimitOrder: Fill is not signed by taker"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -505,7 +505,7 @@ contract PionexContractTest is StrategySharedSetup { traderParams.recipient = coordinator; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: Fill is not signed by taker"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -519,7 +519,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("LimitOrder: Fill permission is expired"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -533,22 +533,22 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAlteredExecutor() public { - // Set the executor to maker (not user) + // Set the executor to maker (not pionex) PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = maker; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - // Fill order using user (not executor) + // Fill order using pionex (not executor) bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -562,36 +562,36 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAllowFillNotSignedByCoordinator() public { IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - // Sign allow fill using user's private key - crdParams.sig = _signAllowFill(userPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); + // Sign allow fill using pionex's private key + crdParams.sig = _signAllowFill(pionexPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithReplayedAllowFill() public { // Fill with default allow fill bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload1); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.takerSalt = uint256(8001); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("PermanentStorage: allow fill seen before"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload2); } @@ -601,7 +601,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: recipient can not be zero address"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -612,16 +612,16 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.makerTokenAmount = fill.makerTokenAmount; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: taker/maker token ratio not good enough"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testFullyFillByTrader() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); @@ -638,14 +638,14 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% - traderParams.takerSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectEmit(true, true, true, true); emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.maker, - user, + pionex, getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), DEFAULT_TRADER_PARAMS.recipient, IPionexContract.FillReceipt( @@ -658,10 +658,10 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER.takerTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% takerTokenAmount ) ); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(97).div(100))); // 3% fee is deducted from takerTokenAmount directly + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(97).div(100))); // 3% fee is deducted from takerTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(87).div(100))); makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); @@ -670,7 +670,7 @@ contract PionexContractTest is StrategySharedSetup { } function testFullyFillByTraderWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); @@ -683,7 +683,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.takerTokenAmount = fill.takerTokenAmount; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.takerTokenAmount; @@ -696,7 +696,7 @@ contract PionexContractTest is StrategySharedSetup { emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.maker, - user, + pionex, getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), traderParams.recipient, IPionexContract.FillReceipt( @@ -709,10 +709,10 @@ contract PionexContractTest is StrategySharedSetup { 0 ) ); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - userTakerAsset.assertChange(-int256(fill.takerTokenAmount)); + pionexTakerAsset.assertChange(-int256(fill.takerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); makerTakerAsset.assertChange(int256(fill.takerTokenAmount)); // 10% more makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); @@ -727,7 +727,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.taker = address(mockERC1271Wallet); - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = address(mockERC1271Wallet); @@ -736,14 +736,14 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testFillBySpecificTaker() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify taker address - order.taker = user; + order.taker = pionex; bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); @@ -751,7 +751,7 @@ contract PionexContractTest is StrategySharedSetup { fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -760,14 +760,14 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testFillBySpecificTakerWithOldEIP712Method() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify taker address - order.taker = user; + order.taker = pionex; bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrderWithOldEIP712Method(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); @@ -775,7 +775,7 @@ contract PionexContractTest is StrategySharedSetup { fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFillWithOldEIP712Method(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFillWithOldEIP712Method(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -784,12 +784,12 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFillWithOldEIP712Method(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testOverFillByTrader() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); @@ -802,7 +802,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.makerTokenAmount = fill.makerTokenAmount; traderParams.takerTokenAmount = fill.takerTokenAmount; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = fill.takerTokenAmount; @@ -811,18 +811,18 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount)); makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); } function testOverFillByTraderWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); @@ -835,7 +835,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.makerTokenAmount = fill.makerTokenAmount; traderParams.takerTokenAmount = fill.takerTokenAmount; - traderParams.takerSig = _signFill(userPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = fill.takerTokenAmount; @@ -844,18 +844,18 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); } function testFillByTraderMultipleTimes() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); @@ -867,7 +867,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; traderParams1.makerTokenAmount = fill1.makerTokenAmount; traderParams1.takerTokenAmount = fill1.takerTokenAmount; - traderParams1.takerSig = _signFill(userPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + traderParams1.takerSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; allowFill1.fillAmount = fill1.takerTokenAmount; @@ -876,7 +876,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload1); // Second fill amount : 36 USDT @@ -887,7 +887,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; traderParams2.makerTokenAmount = fill2.makerTokenAmount; traderParams2.takerTokenAmount = fill2.takerTokenAmount; - traderParams2.takerSig = _signFill(userPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + traderParams2.takerSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; allowFill2.fillAmount = fill2.takerTokenAmount; @@ -896,18 +896,18 @@ contract PionexContractTest is StrategySharedSetup { crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - userTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.div(2))); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.div(2))); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.div(2))); makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.div(2))); makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); } function testFillByTraderMultipleTimesWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); @@ -919,7 +919,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; traderParams1.makerTokenAmount = fill1.makerTokenAmount; traderParams1.takerTokenAmount = fill1.takerTokenAmount; - traderParams1.takerSig = _signFill(userPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + traderParams1.takerSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; allowFill1.fillAmount = fill1.takerTokenAmount; @@ -928,7 +928,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload1); // Second fill amount : 36 USDT and better takerToken/makerToken ratio @@ -939,7 +939,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; traderParams2.makerTokenAmount = fill2.makerTokenAmount; traderParams2.takerTokenAmount = fill2.takerTokenAmount; - traderParams2.takerSig = _signFill(userPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + traderParams2.takerSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; allowFill2.fillAmount = fill2.takerTokenAmount; @@ -948,11 +948,11 @@ contract PionexContractTest is StrategySharedSetup { crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - userTakerAsset.assertChange(-int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); + pionexTakerAsset.assertChange(-int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.div(2))); makerTakerAsset.assertChange(int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); @@ -970,12 +970,12 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER, _signOrder(makerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) ); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(cancelPayload); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectRevert("LimitOrder: Order is cancelled"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -983,9 +983,12 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.takerTokenAmount = 0; - bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory cancelPayload = _genCancelLimitOrderPayload( + DEFAULT_ORDER, + _signOrder(pionexPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) + ); vm.expectRevert("LimitOrder: Cancel request is not signed by maker"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(cancelPayload); } @@ -993,9 +996,9 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; expiredOrder.expiry = 0; - bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(userPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(pionexPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); vm.expectRevert("LimitOrder: Order is expired"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -1004,10 +1007,10 @@ contract PionexContractTest is StrategySharedSetup { zeroOrder.takerTokenAmount = 0; bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(makerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); vm.expectRevert("LimitOrder: Order is cancelled already"); - vm.prank(user, user); // Only EOA + vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } From d0781c86da855332577b6cd513952e238ecbb87c Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 23 May 2023 17:16:32 +0800 Subject: [PATCH 19/41] Update comment for fee and balance change check --- test/forkMainnet/PionexContract.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 2fa216c0..bc71fc06 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -661,9 +661,9 @@ contract PionexContractTest is StrategySharedSetup { vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(97).div(100))); // 3% fee is deducted from takerTokenAmount directly + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from takerTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(87).div(100))); + makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(87).div(100))); // 10% fee for Tokenlon and 3% fee for Pionex makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(10).div(100))); From 928094ceae9e03d2b0b84cf49637cea74042d653 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Thu, 25 May 2023 16:34:53 +0800 Subject: [PATCH 20/41] Rename maker -> user; taker -> pionex --- contracts/PionexContract.sol | 176 +++++----- contracts/interfaces/IPionexContract.sol | 40 +-- contracts/utils/PionexContractLibEIP712.sol | 64 ++-- test/forkMainnet/PionexContract.t.sol | 369 ++++++++++---------- 4 files changed, 323 insertions(+), 326 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 316d35d6..d88e68cf 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -20,8 +20,8 @@ import "./utils/PionexContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; /// @title Pionex Contract -/// @notice Modified from LimitOrder contract. Maker is user, taker is Pionex agent. -/// @notice Order can be filled as long as the provided takerToken/makerToken ratio is better than or equal to maker's specfied takerToken/makerToken ratio. +/// @notice Modified from LimitOrder contract. Maker is user, pionex is Pionex agent. +/// @notice Order can be filled as long as the provided pionexToken/userToken ratio is better than or equal to user's specfied pionexToken/userToken ratio. /// @author imToken Labs contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { using SafeMath for uint256; @@ -35,7 +35,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // Factors uint256 public factorsTimeLock; - uint16 public makerFeeFactor = 0; + uint16 public userFeeFactor = 0; uint16 public pendingMakerFeeFactor; constructor( @@ -65,11 +65,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } /// @notice Only owner can call - /// @param _makerFeeFactor The new fee factor for maker - function setFactors(uint16 _makerFeeFactor) external onlyOwner { - require(_makerFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid maker fee factor"); + /// @param _userFeeFactor The new fee factor for user + function setFactors(uint16 _userFeeFactor) external onlyOwner { + require(_userFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid user fee factor"); - pendingMakerFeeFactor = _makerFeeFactor; + pendingMakerFeeFactor = _userFeeFactor; factorsTimeLock = block.timestamp + factorActivateDelay; } @@ -79,10 +79,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(factorsTimeLock != 0, "LimitOrder: no pending fee factors"); require(block.timestamp >= factorsTimeLock, "LimitOrder: fee factors timelocked"); factorsTimeLock = 0; - makerFeeFactor = pendingMakerFeeFactor; + userFeeFactor = pendingMakerFeeFactor; pendingMakerFeeFactor = 0; - emit FactorsUpdated(makerFeeFactor); + emit FactorsUpdated(userFeeFactor); } /// @notice Only owner can call @@ -104,61 +104,61 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); _validateOrder(_order, orderHash, _orderMakerSig); - bytes32 allowFillHash = _validateFillPermission(orderHash, _params.takerTokenAmount, _params.taker, _crdParams); - _validateOrderTaker(_order, _params.taker); + bytes32 allowFillHash = _validateFillPermission(orderHash, _params.pionexTokenAmount, _params.pionex, _crdParams); + _validateOrderTaker(_order, _params.pionex); - // Check provided takerToken/makerToken ratio is better than or equal to maker's specfied takerToken/makerToken ratio - // -> _params.takerTokenAmount/_params.makerTokenAmount >= _order.takerTokenAmount/_order.makerTokenAmount + // Check provided pionexToken/userToken ratio is better than or equal to user's specfied pionexToken/userToken ratio + // -> _params.pionexTokenAmount/_params.userTokenAmount >= _order.pionexTokenAmount/_order.userTokenAmount require( - _params.takerTokenAmount.mul(_order.makerTokenAmount) >= _order.takerTokenAmount.mul(_params.makerTokenAmount), - "LimitOrder: taker/maker token ratio not good enough" + _params.pionexTokenAmount.mul(_order.userTokenAmount) >= _order.pionexTokenAmount.mul(_params.userTokenAmount), + "LimitOrder: pionex/user token ratio not good enough" ); // Check gas fee factor and pionex strategy fee factor do not exceed limit require( (_params.gasFeeFactor <= LibConstant.BPS_MAX) && (_params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX) && - (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - makerFeeFactor), + (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - userFeeFactor), "LimitOrder: Invalid pionex fee factor" ); { PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ orderHash: orderHash, - taker: _params.taker, + pionex: _params.pionex, recipient: _params.recipient, - makerTokenAmount: _params.makerTokenAmount, - takerTokenAmount: _params.takerTokenAmount, - takerSalt: _params.salt, + userTokenAmount: _params.userTokenAmount, + pionexTokenAmount: _params.pionexTokenAmount, + pionexSalt: _params.salt, expiry: _params.expiry }); - _validateTraderFill(fill, _params.takerSig); + _validateTraderFill(fill, _params.pionexSig); } - (uint256 makerTokenAmount, uint256 remainingAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.makerTokenAmount); - // Calculate takerTokenAmount according to the provided takerToken/makerToken ratio - uint256 takerTokenAmount = makerTokenAmount.mul(_params.takerTokenAmount).div(_params.makerTokenAmount); + (uint256 userTokenAmount, uint256 remainingAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.userTokenAmount); + // Calculate pionexTokenAmount according to the provided pionexToken/userToken ratio + uint256 pionexTokenAmount = userTokenAmount.mul(_params.pionexTokenAmount).div(_params.userTokenAmount); - uint256 makerTokenOut = _settleForTrader( + uint256 userTokenOut = _settleForTrader( TraderSettlement({ orderHash: orderHash, allowFillHash: allowFillHash, - trader: _params.taker, + trader: _params.pionex, recipient: _params.recipient, - maker: _order.maker, - taker: _order.taker, - makerToken: _order.makerToken, - takerToken: _order.takerToken, - makerTokenAmount: makerTokenAmount, - takerTokenAmount: takerTokenAmount, + user: _order.user, + pionex: _order.pionex, + userToken: _order.userToken, + pionexToken: _order.pionexToken, + userTokenAmount: userTokenAmount, + pionexTokenAmount: pionexTokenAmount, remainingAmount: remainingAmount, gasFeeFactor: _params.gasFeeFactor, pionexStrategyFeeFactor: _params.pionexStrategyFeeFactor }) ); - _recordMakerTokenFilled(orderHash, makerTokenAmount); + _recordMakerTokenFilled(orderHash, userTokenAmount); - return (takerTokenAmount, makerTokenOut); + return (pionexTokenAmount, userTokenOut); } function _validateTraderFill(PionexContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { @@ -166,7 +166,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(_fill.recipient != address(0), "LimitOrder: recipient can not be zero address"); bytes32 fillHash = getEIP712Hash(PionexContractLibEIP712._getFillStructHash(_fill)); - require(isValidSignature(_fill.taker, fillHash, bytes(""), _fillTakerSig), "LimitOrder: Fill is not signed by taker"); + require(isValidSignature(_fill.pionex, fillHash, bytes(""), _fillTakerSig), "LimitOrder: Fill is not signed by pionex"); // Set fill seen to avoid replay attack. // PermanentStorage would throw error if fill is already seen. @@ -206,12 +206,12 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes32 allowFillHash; address trader; address recipient; - address maker; - address taker; - IERC20 makerToken; - IERC20 takerToken; - uint256 makerTokenAmount; - uint256 takerTokenAmount; + address user; + address pionex; + IERC20 userToken; + IERC20 pionexToken; + uint256 userTokenAmount; + uint256 pionexTokenAmount; uint256 remainingAmount; uint16 gasFeeFactor; uint16 pionexStrategyFeeFactor; @@ -222,43 +222,43 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu ISpender _spender = spender; address _feeCollector = feeCollector; - // Calculate maker fee (maker receives taker token so fee is charged in taker token) + // Calculate user fee (user receives pionex token so fee is charged in pionex token) // 1. Fee for Tokenlon - uint256 tokenlonFee = _mulFactor(_settlement.takerTokenAmount, makerFeeFactor); + uint256 tokenlonFee = _mulFactor(_settlement.pionexTokenAmount, userFeeFactor); // 2. Fee for Pionex, including gas fee and strategy fee - uint256 pionexFee = _mulFactor(_settlement.takerTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); - uint256 takerTokenForMaker = _settlement.takerTokenAmount.sub(tokenlonFee).sub(pionexFee); + uint256 pionexFee = _mulFactor(_settlement.pionexTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); + uint256 pionexTokenForMaker = _settlement.pionexTokenAmount.sub(tokenlonFee).sub(pionexFee); - // trader -> maker - _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _settlement.maker, takerTokenForMaker); + // trader -> user + _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _settlement.user, pionexTokenForMaker); - // maker -> recipient - _spender.spendFromUserTo(_settlement.maker, address(_settlement.makerToken), _settlement.recipient, _settlement.makerTokenAmount); + // user -> recipient + _spender.spendFromUserTo(_settlement.user, address(_settlement.userToken), _settlement.recipient, _settlement.userTokenAmount); - // Collect maker fee (charged in taker token) + // Collect user fee (charged in pionex token) if (tokenlonFee > 0) { - _spender.spendFromUserTo(_settlement.trader, address(_settlement.takerToken), _feeCollector, tokenlonFee); + _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _feeCollector, tokenlonFee); } // bypass stack too deep error _emitLimitOrderFilledByTrader( LimitOrderFilledByTraderParams({ orderHash: _settlement.orderHash, - maker: _settlement.maker, - taker: _settlement.trader, + user: _settlement.user, + pionex: _settlement.trader, allowFillHash: _settlement.allowFillHash, recipient: _settlement.recipient, - makerToken: address(_settlement.makerToken), - takerToken: address(_settlement.takerToken), - makerTokenFilledAmount: _settlement.makerTokenAmount, - takerTokenFilledAmount: _settlement.takerTokenAmount, + userToken: address(_settlement.userToken), + pionexToken: address(_settlement.pionexToken), + userTokenFilledAmount: _settlement.userTokenAmount, + pionexTokenFilledAmount: _settlement.pionexTokenAmount, remainingAmount: _settlement.remainingAmount, tokenlonFee: tokenlonFee, pionexFee: pionexFee }) ); - return _settlement.makerTokenAmount; + return _settlement.userTokenAmount; } /// @inheritdoc IPionexContract @@ -269,15 +269,15 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(!isCancelled, "LimitOrder: Order is cancelled already"); { PionexContractLibEIP712.Order memory cancelledOrder = _order; - cancelledOrder.takerTokenAmount = 0; + cancelledOrder.pionexTokenAmount = 0; bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); - require(isValidSignature(_order.maker, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "LimitOrder: Cancel request is not signed by maker"); + require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "LimitOrder: Cancel request is not signed by user"); } // Set cancelled state to storage LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash] = true; - emit OrderCancelled(orderHash, _order.maker); + emit OrderCancelled(orderHash, _order.user); } /* order utils */ @@ -291,36 +291,36 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[_orderHash]; require(!isCancelled, "LimitOrder: Order is cancelled"); - require(isValidSignature(_order.maker, _orderHash, bytes(""), _orderMakerSig), "LimitOrder: Order is not signed by maker"); + require(isValidSignature(_order.user, _orderHash, bytes(""), _orderMakerSig), "LimitOrder: Order is not signed by user"); } - function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _taker) internal pure { - if (_order.taker != address(0)) { - require(_order.taker == _taker, "LimitOrder: Order cannot be filled by this taker"); + function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _pionex) internal pure { + if (_order.pionex != address(0)) { + require(_order.pionex == _pionex, "LimitOrder: Order cannot be filled by this pionex"); } } function _quoteOrderFromMakerToken( PionexContractLibEIP712.Order memory _order, bytes32 _orderHash, - uint256 _makerTokenAmount + uint256 _userTokenAmount ) internal view returns (uint256, uint256) { - uint256 makerTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; + uint256 userTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; - require(makerTokenFilledAmount < _order.makerTokenAmount, "LimitOrder: Order is filled"); + require(userTokenFilledAmount < _order.userTokenAmount, "LimitOrder: Order is filled"); - uint256 makerTokenFillableAmount = _order.makerTokenAmount.sub(makerTokenFilledAmount); - uint256 makerTokenQuota = Math.min(_makerTokenAmount, makerTokenFillableAmount); - uint256 remainingAfterFill = makerTokenFillableAmount.sub(makerTokenQuota); + uint256 userTokenFillableAmount = _order.userTokenAmount.sub(userTokenFilledAmount); + uint256 userTokenQuota = Math.min(_userTokenAmount, userTokenFillableAmount); + uint256 remainingAfterFill = userTokenFillableAmount.sub(userTokenQuota); - require(makerTokenQuota != 0, "LimitOrder: zero token amount"); - return (makerTokenQuota, remainingAfterFill); + require(userTokenQuota != 0, "LimitOrder: zero token amount"); + return (userTokenQuota, remainingAfterFill); } - function _recordMakerTokenFilled(bytes32 _orderHash, uint256 _makerTokenAmount) internal { + function _recordMakerTokenFilled(bytes32 _orderHash, uint256 _userTokenAmount) internal { LibPionexContractOrderStorage.Storage storage stor = LibPionexContractOrderStorage.getStorage(); - uint256 makerTokenFilledAmount = stor.orderHashToMakerTokenFilledAmount[_orderHash]; - stor.orderHashToMakerTokenFilledAmount[_orderHash] = makerTokenFilledAmount.add(_makerTokenAmount); + uint256 userTokenFilledAmount = stor.orderHashToMakerTokenFilledAmount[_orderHash]; + stor.orderHashToMakerTokenFilledAmount[_orderHash] = userTokenFilledAmount.add(_userTokenAmount); } /* math utils */ @@ -333,14 +333,14 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu struct LimitOrderFilledByTraderParams { bytes32 orderHash; - address maker; - address taker; + address user; + address pionex; bytes32 allowFillHash; address recipient; - address makerToken; - address takerToken; - uint256 makerTokenFilledAmount; - uint256 takerTokenFilledAmount; + address userToken; + address pionexToken; + uint256 userTokenFilledAmount; + uint256 pionexTokenFilledAmount; uint256 remainingAmount; uint256 tokenlonFee; uint256 pionexFee; @@ -349,15 +349,15 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu function _emitLimitOrderFilledByTrader(LimitOrderFilledByTraderParams memory _params) internal { emit LimitOrderFilledByTrader( _params.orderHash, - _params.maker, - _params.taker, + _params.user, + _params.pionex, _params.allowFillHash, _params.recipient, FillReceipt({ - makerToken: _params.makerToken, - takerToken: _params.takerToken, - makerTokenFilledAmount: _params.makerTokenFilledAmount, - takerTokenFilledAmount: _params.takerTokenFilledAmount, + userToken: _params.userToken, + pionexToken: _params.pionexToken, + userTokenFilledAmount: _params.userTokenFilledAmount, + pionexTokenFilledAmount: _params.pionexTokenFilledAmount, remainingAmount: _params.remainingAmount, tokenlonFee: _params.tokenlonFee, pionexFee: _params.pionexFee diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 8b1dc850..2aa3af38 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -15,24 +15,24 @@ interface IPionexContract is IStrategyBase { event UpgradeCoordinator(address newCoordinator); /// @notice Emitted when fee factors are updated - /// @param makerFeeFactor The new fee factor for maker - event FactorsUpdated(uint16 makerFeeFactor); + /// @param userFeeFactor The new fee factor for user + event FactorsUpdated(uint16 userFeeFactor); /// @notice Emitted when fee collector address is updated /// @param newFeeCollector The address of the new fee collector event SetFeeCollector(address newFeeCollector); - /// @notice Emitted when an order is filled by a trader + /// @notice Emitted when an order is filled by Pionex agent /// @param orderHash The EIP-712 hash of the target order - /// @param maker The address of the maker - /// @param taker The address of the taker (trader) + /// @param user The address of the user + /// @param pionex The address of the pionex (trader) /// @param allowFillHash The EIP-712 hash of the fill permit granted by coordinator - /// @param recipient The address of the recipient which will receive tokens from maker + /// @param recipient The address of the recipient which will receive tokens from user /// @param fillReceipt Contains details of this single fill event LimitOrderFilledByTrader( bytes32 indexed orderHash, - address indexed maker, - address indexed taker, + address indexed user, + address indexed pionex, bytes32 allowFillHash, address recipient, FillReceipt fillReceipt @@ -40,14 +40,14 @@ interface IPionexContract is IStrategyBase { /// @notice Emitted when order is cancelled /// @param orderHash The EIP-712 hash of the target order - /// @param maker The address of the maker - event OrderCancelled(bytes32 orderHash, address maker); + /// @param user The address of the user + event OrderCancelled(bytes32 orderHash, address user); struct FillReceipt { - address makerToken; - address takerToken; - uint256 makerTokenFilledAmount; - uint256 takerTokenFilledAmount; + address userToken; + address pionexToken; + uint256 userTokenFilledAmount; + uint256 pionexTokenFilledAmount; uint256 remainingAmount; uint256 tokenlonFee; uint256 pionexFee; @@ -60,21 +60,21 @@ interface IPionexContract is IStrategyBase { } struct TraderParams { - address taker; + address pionex; address recipient; - uint256 makerTokenAmount; - uint256 takerTokenAmount; + uint256 userTokenAmount; + uint256 pionexTokenAmount; uint16 gasFeeFactor; uint16 pionexStrategyFeeFactor; uint256 salt; uint64 expiry; - bytes takerSig; + bytes pionexSig; } /// @notice Fill an order by a trader /// @notice Only user proxy can call /// @param _order The order that is going to be filled - /// @param _orderMakerSig The signature of the order from maker + /// @param _orderMakerSig The signature of the order from user /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit function fillLimitOrderByTrader( @@ -87,6 +87,6 @@ interface IPionexContract is IStrategyBase { /// @notice Cancel an order /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled - /// @param _cancelMakerSig The cancelling signature signed by maker + /// @param _cancelMakerSig The cancelling signature signed by user function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelMakerSig) external; } diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/PionexContractLibEIP712.sol index aefbc8d1..67b73a78 100644 --- a/contracts/utils/PionexContractLibEIP712.sol +++ b/contracts/utils/PionexContractLibEIP712.sol @@ -7,12 +7,12 @@ import "../interfaces/IPionexContract.sol"; library PionexContractLibEIP712 { struct Order { - IERC20 makerToken; - IERC20 takerToken; - uint256 makerTokenAmount; - uint256 takerTokenAmount; - address maker; - address taker; + IERC20 userToken; + IERC20 pionexToken; + uint256 userTokenAmount; + uint256 pionexTokenAmount; + address user; + address pionex; uint256 salt; uint64 expiry; } @@ -21,31 +21,31 @@ library PionexContractLibEIP712 { keccak256( abi.encodePacked( "Order(", - "address makerToken,", - "address takerToken,", - "uint256 makerTokenAmount,", - "uint256 takerTokenAmount,", - "address maker,", - "address taker,", + "address userToken,", + "address pionexToken,", + "uint256 userTokenAmount,", + "uint256 pionexTokenAmount,", + "address user,", + "address pionex,", "uint256 salt,", "uint64 expiry", ")" ) ); */ - bytes32 private constant ORDER_TYPEHASH = 0x025174f0ee45736f4e018e96c368bd4baf3dce8d278860936559209f568c8ecb; + bytes32 private constant ORDER_TYPEHASH = 0x97aec2eaa3064135fc2be6548ccc65711bf2143e0a4ad193212bfdee8913eb9d; function _getOrderStructHash(Order memory _order) internal pure returns (bytes32) { return keccak256( abi.encode( ORDER_TYPEHASH, - address(_order.makerToken), - address(_order.takerToken), - _order.makerTokenAmount, - _order.takerTokenAmount, - _order.maker, - _order.taker, + address(_order.userToken), + address(_order.pionexToken), + _order.userTokenAmount, + _order.pionexTokenAmount, + _order.user, + _order.pionex, _order.salt, _order.expiry ) @@ -54,11 +54,11 @@ library PionexContractLibEIP712 { struct Fill { bytes32 orderHash; // EIP712 hash - address taker; + address pionex; address recipient; - uint256 makerTokenAmount; - uint256 takerTokenAmount; - uint256 takerSalt; + uint256 userTokenAmount; + uint256 pionexTokenAmount; + uint256 pionexSalt; uint64 expiry; } @@ -67,17 +67,17 @@ library PionexContractLibEIP712 { abi.encodePacked( "Fill(", "bytes32 orderHash,", - "address taker,", + "address pionex,", "address recipient,", - "uint256 makerTokenAmount,", - "uint256 takerTokenAmount,", - "uint256 takerSalt,", + "uint256 userTokenAmount,", + "uint256 pionexTokenAmount,", + "uint256 pionexSalt,", "uint64 expiry", ")" ) ); */ - bytes32 private constant FILL_TYPEHASH = 0x205396fa1b68e5a32114505757ea3414ca863515127de397dd50fc79342ce917; + bytes32 private constant FILL_TYPEHASH = 0x8df856cadbad83b5dc946bdac2a541b74332d7444f83e9794203304034f44166; function _getFillStructHash(Fill memory _fill) internal pure returns (bytes32) { return @@ -85,11 +85,11 @@ library PionexContractLibEIP712 { abi.encode( FILL_TYPEHASH, _fill.orderHash, - _fill.taker, + _fill.pionex, _fill.recipient, - _fill.makerTokenAmount, - _fill.takerTokenAmount, - _fill.takerSalt, + _fill.userTokenAmount, + _fill.pionexTokenAmount, + _fill.pionexSalt, _fill.expiry ) ); diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index bc71fc06..5b1b5f70 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -23,25 +23,25 @@ contract PionexContractTest is StrategySharedSetup { event LimitOrderFilledByTrader( bytes32 indexed orderHash, - address indexed maker, - address indexed taker, + address indexed user, + address indexed pionex, bytes32 allowFillHash, address recipient, IPionexContract.FillReceipt fillReceipt ); uint256 pionexPrivateKey = uint256(1); - uint256 makerPrivateKey = uint256(2); + uint256 userPrivateKey = uint256(2); uint256 coordinatorPrivateKey = uint256(3); address pionex = vm.addr(pionexPrivateKey); - address maker = vm.addr(makerPrivateKey); + address user = vm.addr(userPrivateKey); address coordinator = vm.addr(coordinatorPrivateKey); address owner = makeAddr("owner"); address feeCollector = makeAddr("feeCollector"); address receiver = makeAddr("receiver"); MockERC1271Wallet mockERC1271Wallet = new MockERC1271Wallet(pionex); - address[] wallet = [pionex, maker, coordinator, address(mockERC1271Wallet)]; + address[] wallet = [pionex, user, coordinator, address(mockERC1271Wallet)]; address[] allowanceAddrs; address[] DEFAULT_AMM_PATH; @@ -69,41 +69,41 @@ contract PionexContractTest is StrategySharedSetup { // Default params DEFAULT_ORDER = PionexContractLibEIP712.Order( - dai, // makerToken - usdt, // takerToken - 100 * 1e18, // makerTokenAmount - 90 * 1e6, // takerTokenAmount - maker, // maker - address(0), // taker + dai, // userToken + usdt, // pionexToken + 100 * 1e18, // userTokenAmount + 90 * 1e6, // pionexTokenAmount + user, // user + address(0), // pionex uint256(1001), // salt DEADLINE // expiry ); DEFAULT_ORDER_HASH = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); - DEFAULT_ORDER_MAKER_SIG = _signOrder(makerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); + DEFAULT_ORDER_MAKER_SIG = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); DEFAULT_FILL = PionexContractLibEIP712.Fill( DEFAULT_ORDER_HASH, pionex, receiver, - DEFAULT_ORDER.makerTokenAmount, - DEFAULT_ORDER.takerTokenAmount, + DEFAULT_ORDER.userTokenAmount, + DEFAULT_ORDER.pionexTokenAmount, uint256(1002), DEADLINE ); DEFAULT_TRADER_PARAMS = IPionexContract.TraderParams( - pionex, // taker + pionex, // pionex receiver, // recipient - DEFAULT_FILL.makerTokenAmount, // makerTokenAmount - DEFAULT_FILL.takerTokenAmount, // takerTokenAmount + DEFAULT_FILL.userTokenAmount, // userTokenAmount + DEFAULT_FILL.pionexTokenAmount, // pionexTokenAmount DEFAULT_GAS_FEE_FACTOR, // gas fee factor DEFAULT_PIONEX_STRATEGY_FEE_FACTOR, // pionex strategy fee factor - DEFAULT_FILL.takerSalt, // salt + DEFAULT_FILL.pionexSalt, // salt DEADLINE, // expiry - _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // takerSig + _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // pionexSig ); DEFAULT_ALLOW_FILL = PionexContractLibEIP712.AllowFill( DEFAULT_ORDER_HASH, // orderHash pionex, // executor - DEFAULT_FILL.takerTokenAmount, // fillAmount + DEFAULT_FILL.pionexTokenAmount, // fillAmount uint256(1003), // salt DEADLINE // expiry ); @@ -118,12 +118,12 @@ contract PionexContractTest is StrategySharedSetup { // Set token balance and approve tokens = [weth, usdt, dai]; setEOABalanceAndApprove(pionex, tokens, 10000); - setEOABalanceAndApprove(maker, tokens, 10000); + setEOABalanceAndApprove(user, tokens, 10000); setEOABalanceAndApprove(address(mockERC1271Wallet), tokens, 10000); // Label addresses for easier debugging vm.label(pionex, "Pionex"); - vm.label(maker, "Maker"); + vm.label(user, "User"); vm.label(coordinator, "Coordinator"); vm.label(receiver, "Receiver"); vm.label(feeCollector, "FeeCollector"); @@ -176,7 +176,7 @@ contract PionexContractTest is StrategySharedSetup { assertEq(address(pionexContract.permStorage()), address(permanentStorage)); assertEq(address(pionexContract.weth()), address(weth)); - assertEq(uint256(pionexContract.makerFeeFactor()), 0); + assertEq(uint256(pionexContract.userFeeFactor()), 0); } /********************************* @@ -301,7 +301,7 @@ contract PionexContractTest is StrategySharedSetup { *********************************/ function testCannotSetFactorsIfLargerThanBpsMax() public { - vm.expectRevert("LimitOrder: Invalid maker fee factor"); + vm.expectRevert("LimitOrder: Invalid user fee factor"); vm.prank(owner, owner); pionexContract.setFactors(LibConstant.BPS_MAX + 1); } @@ -310,13 +310,13 @@ contract PionexContractTest is StrategySharedSetup { vm.startPrank(owner, owner); pionexContract.setFactors(1); // fee factors should stay same before new ones activate - assertEq(uint256(pionexContract.makerFeeFactor()), 0); + assertEq(uint256(pionexContract.userFeeFactor()), 0); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); // fee factors should be updated now pionexContract.activateFactors(); vm.stopPrank(); - assertEq(uint256(pionexContract.makerFeeFactor()), 1); + assertEq(uint256(pionexContract.userFeeFactor()), 1); } /********************************* @@ -359,11 +359,11 @@ contract PionexContractTest is StrategySharedSetup { // Try to fill the default order, should fail PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.takerSalt = uint256(8001); + fill.pionexSalt = uint256(8001); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - traderParams.salt = fill.takerSalt; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.salt = fill.pionexSalt; PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.salt = uint256(8002); @@ -383,13 +383,13 @@ contract PionexContractTest is StrategySharedSetup { order.expiry = uint64(block.timestamp - 1); bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -407,34 +407,34 @@ contract PionexContractTest is StrategySharedSetup { bytes memory wrongMakerSig = _signOrder(pionexPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Order is not signed by maker"); + vm.expectRevert("LimitOrder: Order is not signed by user"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWrongTakerSig() public { IPionexContract.TraderParams memory wrongTraderParams = DEFAULT_TRADER_PARAMS; - wrongTraderParams.takerSig = _signFill(makerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + wrongTraderParams.pionexSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Fill is not signed by taker"); + vm.expectRevert("LimitOrder: Fill is not signed by pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithTakerOtherThanOrderSpecified() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify taker address - order.taker = coordinator; + // order specify pionex address + order.pionex = coordinator; bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; // pionex try to fill this order - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -443,7 +443,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.expectRevert("LimitOrder: Order cannot be filled by this taker"); + vm.expectRevert("LimitOrder: Order cannot be filled by this pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -453,7 +453,7 @@ contract PionexContractTest is StrategySharedSetup { fill.expiry = uint64(block.timestamp - 1); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.expiry = fill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); @@ -483,18 +483,18 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotFillByTraderWithAlteredTakerTokenAmount() public { - // Replace takerTokenAmount in traderParams without corresponded signature + // Replace pionexTokenAmount in traderParams without corresponded signature IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerTokenAmount = DEFAULT_TRADER_PARAMS.takerTokenAmount.mul(2); + traderParams.pionexTokenAmount = DEFAULT_TRADER_PARAMS.pionexTokenAmount.mul(2); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = traderParams.takerTokenAmount; + allowFill.fillAmount = traderParams.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.expectRevert("LimitOrder: Fill is not signed by taker"); + vm.expectRevert("LimitOrder: Fill is not signed by pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -504,7 +504,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = coordinator; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Fill is not signed by taker"); + vm.expectRevert("LimitOrder: Fill is not signed by pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -538,9 +538,9 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotFillByTraderWithAlteredExecutor() public { - // Set the executor to maker (not pionex) + // Set the executor to user (not pionex) PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.executor = maker; + allowFill.executor = user; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -584,10 +584,10 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload1); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.takerSalt = uint256(8001); + fill.pionexSalt = uint256(8001); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("PermanentStorage: allow fill seen before"); @@ -607,28 +607,28 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillByTraderWithWorseTakerMakerTokenRatio() public { PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - // Increase maker token amount so the takerToken/makerToken ratio is worse than order's takerToken/makerToken ratio - fill.makerTokenAmount = DEFAULT_FILL.makerTokenAmount.add(1); + // Increase user token amount so the pionexToken/userToken ratio is worse than order's pionexToken/userToken ratio + fill.userTokenAmount = DEFAULT_FILL.userTokenAmount.add(1); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.makerTokenAmount = fill.makerTokenAmount; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.userTokenAmount = fill.userTokenAmount; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: taker/maker token ratio not good enough"); + vm.expectRevert("LimitOrder: pionex/user token ratio not good enough"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } function testFullyFillByTrader() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); - - // makerFeeFactor : 10% + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + + // userFeeFactor : 10% vm.startPrank(owner, owner); pionexContract.setFactors(1000); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); @@ -638,55 +638,55 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% - traderParams.takerSig = _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectEmit(true, true, true, true); emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, - DEFAULT_ORDER.maker, + DEFAULT_ORDER.user, pionex, getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), DEFAULT_TRADER_PARAMS.recipient, IPionexContract.FillReceipt( - address(DEFAULT_ORDER.makerToken), - address(DEFAULT_ORDER.takerToken), - DEFAULT_ORDER.makerTokenAmount, - DEFAULT_ORDER.takerTokenAmount, + address(DEFAULT_ORDER.userToken), + address(DEFAULT_ORDER.pionexToken), + DEFAULT_ORDER.userTokenAmount, + DEFAULT_ORDER.pionexTokenAmount, 0, // remainingAmount should be zero after order fully filled - DEFAULT_ORDER.takerTokenAmount.mul(10).div(100), // tokenlonFee = 10% takerTokenAmount - DEFAULT_ORDER.takerTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% takerTokenAmount + DEFAULT_ORDER.pionexTokenAmount.mul(10).div(100), // tokenlonFee = 10% pionexTokenAmount + DEFAULT_ORDER.pionexTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% pionexTokenAmount ) ); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from takerTokenAmount directly - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(87).div(100))); // 10% fee for Tokenlon and 3% fee for Pionex - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from pionexTokenAmount directly + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.mul(87).div(100))); // 10% fee for Tokenlon and 3% fee for Pionex + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); - fcTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(10).div(100))); + fcTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.mul(10).div(100))); } function testFullyFillByTraderWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.takerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - // Increase taker token amount so the takerToken/makerToken ratio is better than order's takerToken/makerToken ratio - fill.takerTokenAmount = DEFAULT_FILL.takerTokenAmount.mul(11).div(10); // 10% more + // Increase pionex token amount so the pionexToken/userToken ratio is better than order's pionexToken/userToken ratio + fill.pionexTokenAmount = DEFAULT_FILL.pionexTokenAmount.mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerTokenAmount = fill.takerTokenAmount; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexTokenAmount = fill.pionexTokenAmount; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = traderParams.takerTokenAmount; + allowFill.fillAmount = traderParams.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -695,15 +695,15 @@ contract PionexContractTest is StrategySharedSetup { vm.expectEmit(true, true, true, true); emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, - DEFAULT_ORDER.maker, + DEFAULT_ORDER.user, pionex, getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), traderParams.recipient, IPionexContract.FillReceipt( - address(DEFAULT_ORDER.makerToken), - address(DEFAULT_ORDER.takerToken), - DEFAULT_ORDER.makerTokenAmount, - fill.takerTokenAmount, + address(DEFAULT_ORDER.userToken), + address(DEFAULT_ORDER.pionexToken), + DEFAULT_ORDER.userTokenAmount, + fill.pionexTokenAmount, 0, // remainingAmount should be zero after order fully filled 0, 0 @@ -712,22 +712,22 @@ contract PionexContractTest is StrategySharedSetup { vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(fill.takerTokenAmount)); - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(fill.takerTokenAmount)); // 10% more - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + pionexTakerAsset.assertChange(-int256(fill.pionexTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); + userTakerAsset.assertChange(int256(fill.pionexTokenAmount)); // 10% more + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(0); } function testFullyFillByContractWalletTrader() public { - // Contract mockERC1271Wallet as taker which always return valid ERC-1271 magic value no matter what. + // Contract mockERC1271Wallet as pionex which always return valid ERC-1271 magic value no matter what. PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.taker = address(mockERC1271Wallet); + fill.pionex = address(mockERC1271Wallet); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.taker = address(mockERC1271Wallet); - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); + traderParams.pionex = address(mockERC1271Wallet); + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = address(mockERC1271Wallet); @@ -742,16 +742,16 @@ contract PionexContractTest is StrategySharedSetup { function testFillBySpecificTaker() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify taker address - order.taker = pionex; + // order specify pionex address + order.pionex = pionex; bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrder(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -766,16 +766,16 @@ contract PionexContractTest is StrategySharedSetup { function testFillBySpecificTakerWithOldEIP712Method() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify taker address - order.taker = pionex; + // order specify pionex address + order.pionex = pionex; bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); - bytes memory orderMakerSig = _signOrderWithOldEIP712Method(makerPrivateKey, order, SignatureValidator.SignatureType.EIP712); + bytes memory orderMakerSig = _signOrderWithOldEIP712Method(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.takerSig = _signFillWithOldEIP712Method(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.pionexSig = _signFillWithOldEIP712Method(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -789,23 +789,23 @@ contract PionexContractTest is StrategySharedSetup { } function testOverFillByTrader() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota - fill.makerTokenAmount = DEFAULT_ORDER.makerTokenAmount.mul(2); - fill.takerTokenAmount = DEFAULT_ORDER.takerTokenAmount.mul(2); + fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); + fill.pionexTokenAmount = DEFAULT_ORDER.pionexTokenAmount.mul(2); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.makerTokenAmount = fill.makerTokenAmount; - traderParams.takerTokenAmount = fill.takerTokenAmount; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.userTokenAmount = fill.userTokenAmount; + traderParams.pionexTokenAmount = fill.pionexTokenAmount; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = fill.takerTokenAmount; + allowFill.fillAmount = fill.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -815,30 +815,30 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount)); - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount)); - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount)); + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); } function testOverFillByTraderWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota - fill.makerTokenAmount = DEFAULT_ORDER.makerTokenAmount.mul(2); - fill.takerTokenAmount = DEFAULT_ORDER.takerTokenAmount.mul(2).mul(11).div(10); // 10% more + fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); + fill.pionexTokenAmount = DEFAULT_ORDER.pionexTokenAmount.mul(2).mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.makerTokenAmount = fill.makerTokenAmount; - traderParams.takerTokenAmount = fill.takerTokenAmount; - traderParams.takerSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.userTokenAmount = fill.userTokenAmount; + traderParams.pionexTokenAmount = fill.pionexTokenAmount; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = fill.takerTokenAmount; + allowFill.fillAmount = fill.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -848,29 +848,29 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount)); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.mul(11).div(10))); // 10% more - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount)); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount.mul(11).div(10))); // 10% more + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.mul(11).div(10))); // 10% more + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); } function testFillByTraderMultipleTimes() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); // First fill amount : 9 USDT PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; - fill1.makerTokenAmount = 10 * 1e18; - fill1.takerTokenAmount = 9 * 1e6; + fill1.userTokenAmount = 10 * 1e18; + fill1.pionexTokenAmount = 9 * 1e6; IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; - traderParams1.makerTokenAmount = fill1.makerTokenAmount; - traderParams1.takerTokenAmount = fill1.takerTokenAmount; - traderParams1.takerSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + traderParams1.userTokenAmount = fill1.userTokenAmount; + traderParams1.pionexTokenAmount = fill1.pionexTokenAmount; + traderParams1.pionexSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; - allowFill1.fillAmount = fill1.takerTokenAmount; + allowFill1.fillAmount = fill1.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); @@ -881,16 +881,16 @@ contract PionexContractTest is StrategySharedSetup { // Second fill amount : 36 USDT PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; - fill2.makerTokenAmount = 40 * 1e18; - fill2.takerTokenAmount = 36 * 1e6; + fill2.userTokenAmount = 40 * 1e18; + fill2.pionexTokenAmount = 36 * 1e6; IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; - traderParams2.makerTokenAmount = fill2.makerTokenAmount; - traderParams2.takerTokenAmount = fill2.takerTokenAmount; - traderParams2.takerSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + traderParams2.userTokenAmount = fill2.userTokenAmount; + traderParams2.pionexTokenAmount = fill2.pionexTokenAmount; + traderParams2.pionexSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; - allowFill2.fillAmount = fill2.takerTokenAmount; + allowFill2.fillAmount = fill2.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); @@ -900,29 +900,29 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.takerTokenAmount.div(2))); - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.div(2))); - makerTakerAsset.assertChange(int256(DEFAULT_ORDER.takerTokenAmount.div(2))); - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount.div(2))); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount.div(2))); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.div(2))); + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2))); } function testFillByTraderMultipleTimesWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.makerToken)); - BalanceSnapshot.Snapshot memory makerTakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.takerToken)); - BalanceSnapshot.Snapshot memory makerMakerAsset = BalanceSnapshot.take(maker, address(DEFAULT_ORDER.makerToken)); + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); - // First fill amount : 9 USDT and same takerToken/makerToken ratio + // First fill amount : 9 USDT and same pionexToken/userToken ratio PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; - fill1.makerTokenAmount = 10 * 1e18; - fill1.takerTokenAmount = 9 * 1e6; + fill1.userTokenAmount = 10 * 1e18; + fill1.pionexTokenAmount = 9 * 1e6; IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; - traderParams1.makerTokenAmount = fill1.makerTokenAmount; - traderParams1.takerTokenAmount = fill1.takerTokenAmount; - traderParams1.takerSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + traderParams1.userTokenAmount = fill1.userTokenAmount; + traderParams1.pionexTokenAmount = fill1.pionexTokenAmount; + traderParams1.pionexSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; - allowFill1.fillAmount = fill1.takerTokenAmount; + allowFill1.fillAmount = fill1.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); @@ -931,18 +931,18 @@ contract PionexContractTest is StrategySharedSetup { vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload1); - // Second fill amount : 36 USDT and better takerToken/makerToken ratio + // Second fill amount : 36 USDT and better pionexToken/userToken ratio PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; - fill2.makerTokenAmount = 40 * 1e18; - fill2.takerTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more + fill2.userTokenAmount = 40 * 1e18; + fill2.pionexTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; - traderParams2.makerTokenAmount = fill2.makerTokenAmount; - traderParams2.takerTokenAmount = fill2.takerTokenAmount; - traderParams2.takerSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + traderParams2.userTokenAmount = fill2.userTokenAmount; + traderParams2.pionexTokenAmount = fill2.pionexTokenAmount; + traderParams2.pionexSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; - allowFill2.fillAmount = fill2.takerTokenAmount; + allowFill2.fillAmount = fill2.pionexTokenAmount; IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); @@ -952,10 +952,10 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - pionexTakerAsset.assertChange(-int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); - receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.makerTokenAmount.div(2))); - makerTakerAsset.assertChange(int256(fill1.takerTokenAmount.add(fill2.takerTokenAmount))); - makerMakerAsset.assertChange(-int256(DEFAULT_ORDER.makerTokenAmount.div(2))); + pionexTakerAsset.assertChange(-int256(fill1.pionexTokenAmount.add(fill2.pionexTokenAmount))); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount.div(2))); + userTakerAsset.assertChange(int256(fill1.pionexTokenAmount.add(fill2.pionexTokenAmount))); + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2))); } /********************************* @@ -964,12 +964,9 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillCanceledOrder() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.takerTokenAmount = 0; + zeroOrder.pionexTokenAmount = 0; - bytes memory cancelPayload = _genCancelLimitOrderPayload( - DEFAULT_ORDER, - _signOrder(makerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) - ); + bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(cancelPayload); @@ -981,13 +978,13 @@ contract PionexContractTest is StrategySharedSetup { function testCannotCancelIfNotMaker() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.takerTokenAmount = 0; + zeroOrder.pionexTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload( DEFAULT_ORDER, _signOrder(pionexPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) ); - vm.expectRevert("LimitOrder: Cancel request is not signed by maker"); + vm.expectRevert("LimitOrder: Cancel request is not signed by user"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(cancelPayload); } @@ -1004,9 +1001,9 @@ contract PionexContractTest is StrategySharedSetup { function testCannotCancelTwice() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.takerTokenAmount = 0; + zeroOrder.pionexTokenAmount = 0; - bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(makerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); vm.expectRevert("LimitOrder: Order is cancelled already"); From 4429fb13b5267fd3a14ce38b975d583b82bc67f2 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 26 May 2023 12:26:55 +0800 Subject: [PATCH 21/41] Rename LimitOrder -> PionexContract; fillLimitOrderByTrader -> fillLimitOrder --- contracts/PionexContract.sol | 45 +++++++++++---------- contracts/interfaces/IPionexContract.sol | 2 +- test/forkMainnet/PionexContract.t.sol | 50 ++++++++++++------------ 3 files changed, 48 insertions(+), 49 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index d88e68cf..e0ef60e3 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -20,7 +20,6 @@ import "./utils/PionexContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; /// @title Pionex Contract -/// @notice Modified from LimitOrder contract. Maker is user, pionex is Pionex agent. /// @notice Order can be filled as long as the provided pionexToken/userToken ratio is better than or equal to user's specfied pionexToken/userToken ratio. /// @author imToken Labs contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { @@ -58,7 +57,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _newCoordinator The new address of coordinator function upgradeCoordinator(address _newCoordinator) external onlyOwner { - require(_newCoordinator != address(0), "LimitOrder: coordinator can not be zero address"); + require(_newCoordinator != address(0), "PionexContract: coordinator can not be zero address"); coordinator = _newCoordinator; emit UpgradeCoordinator(_newCoordinator); @@ -67,7 +66,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _userFeeFactor The new fee factor for user function setFactors(uint16 _userFeeFactor) external onlyOwner { - require(_userFeeFactor <= LibConstant.BPS_MAX, "LimitOrder: Invalid user fee factor"); + require(_userFeeFactor <= LibConstant.BPS_MAX, "PionexContract: Invalid user fee factor"); pendingMakerFeeFactor = _userFeeFactor; @@ -76,8 +75,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call function activateFactors() external onlyOwner { - require(factorsTimeLock != 0, "LimitOrder: no pending fee factors"); - require(block.timestamp >= factorsTimeLock, "LimitOrder: fee factors timelocked"); + require(factorsTimeLock != 0, "PionexContract: no pending fee factors"); + require(block.timestamp >= factorsTimeLock, "PionexContract: fee factors timelocked"); factorsTimeLock = 0; userFeeFactor = pendingMakerFeeFactor; pendingMakerFeeFactor = 0; @@ -88,14 +87,14 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _newFeeCollector The new address of fee collector function setFeeCollector(address _newFeeCollector) external onlyOwner { - require(_newFeeCollector != address(0), "LimitOrder: fee collector can not be zero address"); + require(_newFeeCollector != address(0), "PionexContract: fee collector can not be zero address"); feeCollector = _newFeeCollector; emit SetFeeCollector(_newFeeCollector); } /// @inheritdoc IPionexContract - function fillLimitOrderByTrader( + function fillLimitOrder( PionexContractLibEIP712.Order calldata _order, bytes calldata _orderMakerSig, TraderParams calldata _params, @@ -111,14 +110,14 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // -> _params.pionexTokenAmount/_params.userTokenAmount >= _order.pionexTokenAmount/_order.userTokenAmount require( _params.pionexTokenAmount.mul(_order.userTokenAmount) >= _order.pionexTokenAmount.mul(_params.userTokenAmount), - "LimitOrder: pionex/user token ratio not good enough" + "PionexContract: pionex/user token ratio not good enough" ); // Check gas fee factor and pionex strategy fee factor do not exceed limit require( (_params.gasFeeFactor <= LibConstant.BPS_MAX) && (_params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX) && (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - userFeeFactor), - "LimitOrder: Invalid pionex fee factor" + "PionexContract: Invalid pionex fee factor" ); { @@ -162,11 +161,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } function _validateTraderFill(PionexContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { - require(_fill.expiry > uint64(block.timestamp), "LimitOrder: Fill request is expired"); - require(_fill.recipient != address(0), "LimitOrder: recipient can not be zero address"); + require(_fill.expiry > uint64(block.timestamp), "PionexContract: Fill request is expired"); + require(_fill.recipient != address(0), "PionexContract: recipient can not be zero address"); bytes32 fillHash = getEIP712Hash(PionexContractLibEIP712._getFillStructHash(_fill)); - require(isValidSignature(_fill.pionex, fillHash, bytes(""), _fillTakerSig), "LimitOrder: Fill is not signed by pionex"); + require(isValidSignature(_fill.pionex, fillHash, bytes(""), _fillTakerSig), "PionexContract: Fill is not signed by pionex"); // Set fill seen to avoid replay attack. // PermanentStorage would throw error if fill is already seen. @@ -179,7 +178,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address _executor, CoordinatorParams memory _crdParams ) internal returns (bytes32) { - require(_crdParams.expiry > uint64(block.timestamp), "LimitOrder: Fill permission is expired"); + require(_crdParams.expiry > uint64(block.timestamp), "PionexContract: Fill permission is expired"); bytes32 allowFillHash = getEIP712Hash( PionexContractLibEIP712._getAllowFillStructHash( @@ -192,7 +191,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu }) ) ); - require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "LimitOrder: AllowFill is not signed by coordinator"); + require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "PionexContract: AllowFill is not signed by coordinator"); // Set allow fill seen to avoid replay attack // PermanentStorage would throw error if allow fill is already seen. @@ -263,16 +262,16 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @inheritdoc IPionexContract function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderMakerSig) external override onlyUserProxy nonReentrant { - require(_order.expiry > uint64(block.timestamp), "LimitOrder: Order is expired"); + require(_order.expiry > uint64(block.timestamp), "PionexContract: Order is expired"); bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; - require(!isCancelled, "LimitOrder: Order is cancelled already"); + require(!isCancelled, "PionexContract: Order is cancelled already"); { PionexContractLibEIP712.Order memory cancelledOrder = _order; cancelledOrder.pionexTokenAmount = 0; bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); - require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "LimitOrder: Cancel request is not signed by user"); + require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "PionexContract: Cancel request is not signed by user"); } // Set cancelled state to storage @@ -287,16 +286,16 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes32 _orderHash, bytes memory _orderMakerSig ) internal view { - require(_order.expiry > uint64(block.timestamp), "LimitOrder: Order is expired"); + require(_order.expiry > uint64(block.timestamp), "PionexContract: Order is expired"); bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[_orderHash]; - require(!isCancelled, "LimitOrder: Order is cancelled"); + require(!isCancelled, "PionexContract: Order is cancelled"); - require(isValidSignature(_order.user, _orderHash, bytes(""), _orderMakerSig), "LimitOrder: Order is not signed by user"); + require(isValidSignature(_order.user, _orderHash, bytes(""), _orderMakerSig), "PionexContract: Order is not signed by user"); } function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _pionex) internal pure { if (_order.pionex != address(0)) { - require(_order.pionex == _pionex, "LimitOrder: Order cannot be filled by this pionex"); + require(_order.pionex == _pionex, "PionexContract: Order cannot be filled by this pionex"); } } @@ -307,13 +306,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu ) internal view returns (uint256, uint256) { uint256 userTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; - require(userTokenFilledAmount < _order.userTokenAmount, "LimitOrder: Order is filled"); + require(userTokenFilledAmount < _order.userTokenAmount, "PionexContract: Order is filled"); uint256 userTokenFillableAmount = _order.userTokenAmount.sub(userTokenFilledAmount); uint256 userTokenQuota = Math.min(_userTokenAmount, userTokenFillableAmount); uint256 remainingAfterFill = userTokenFillableAmount.sub(userTokenQuota); - require(userTokenQuota != 0, "LimitOrder: zero token amount"); + require(userTokenQuota != 0, "PionexContract: zero token amount"); return (userTokenQuota, remainingAfterFill); } diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 2aa3af38..44470232 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -77,7 +77,7 @@ interface IPionexContract is IStrategyBase { /// @param _orderMakerSig The signature of the order from user /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit - function fillLimitOrderByTrader( + function fillLimitOrder( PionexContractLibEIP712.Order calldata _order, bytes calldata _orderMakerSig, TraderParams calldata _params, diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 5b1b5f70..542b0f79 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -236,7 +236,7 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotUpgradeCoordinatorToZeroAddr() public { - vm.expectRevert("LimitOrder: coordinator can not be zero address"); + vm.expectRevert("PionexContract: coordinator can not be zero address"); vm.prank(owner, owner); pionexContract.upgradeCoordinator(address(0)); } @@ -301,7 +301,7 @@ contract PionexContractTest is StrategySharedSetup { *********************************/ function testCannotSetFactorsIfLargerThanBpsMax() public { - vm.expectRevert("LimitOrder: Invalid user fee factor"); + vm.expectRevert("PionexContract: Invalid user fee factor"); vm.prank(owner, owner); pionexContract.setFactors(LibConstant.BPS_MAX + 1); } @@ -330,7 +330,7 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotSetFeeCollectorToZeroAddr() public { - vm.expectRevert("LimitOrder: fee collector can not be zero address"); + vm.expectRevert("PionexContract: fee collector can not be zero address"); vm.prank(owner, owner); pionexContract.setFeeCollector(address(0)); } @@ -342,13 +342,13 @@ contract PionexContractTest is StrategySharedSetup { } /********************************* - * Test: fillLimitOrderByTrader * + * Test: fillLimitOrder * *********************************/ function testCannotFillByTraderIfNotFromUserProxy() public { vm.expectRevert("Strategy: not from UserProxy contract"); // Call limit order contract directly will get reverted since msg.sender is not from UserProxy - pionexContract.fillLimitOrderByTrader(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + pionexContract.fillLimitOrder(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); } function testCannotFillFilledOrderByTrader() public { @@ -373,7 +373,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.salt = allowFill.salt; bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.expectRevert("LimitOrder: Order is filled"); + vm.expectRevert("PionexContract: Order is filled"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload2); } @@ -398,7 +398,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.expectRevert("LimitOrder: Order is expired"); + vm.expectRevert("PionexContract: Order is expired"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -407,7 +407,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory wrongMakerSig = _signOrder(pionexPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Order is not signed by user"); + vm.expectRevert("PionexContract: Order is not signed by user"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -417,7 +417,7 @@ contract PionexContractTest is StrategySharedSetup { wrongTraderParams.pionexSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Fill is not signed by pionex"); + vm.expectRevert("PionexContract: Fill is not signed by pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -443,7 +443,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.expectRevert("LimitOrder: Order cannot be filled by this pionex"); + vm.expectRevert("PionexContract: Order cannot be filled by this pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -457,7 +457,7 @@ contract PionexContractTest is StrategySharedSetup { traderParams.expiry = fill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Fill request is expired"); + vm.expectRevert("PionexContract: Fill request is expired"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -494,7 +494,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.expectRevert("LimitOrder: Fill is not signed by pionex"); + vm.expectRevert("PionexContract: Fill is not signed by pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -504,7 +504,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = coordinator; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Fill is not signed by pionex"); + vm.expectRevert("PionexContract: Fill is not signed by pionex"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -518,7 +518,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.expiry = allowFill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("LimitOrder: Fill permission is expired"); + vm.expectRevert("PionexContract: Fill permission is expired"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -532,7 +532,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -547,7 +547,7 @@ contract PionexContractTest is StrategySharedSetup { // Fill order using pionex (not executor) bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -561,7 +561,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -572,7 +572,7 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(pionexPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("LimitOrder: AllowFill is not signed by coordinator"); + vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -600,7 +600,7 @@ contract PionexContractTest is StrategySharedSetup { traderParams.recipient = address(0); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: recipient can not be zero address"); + vm.expectRevert("PionexContract: recipient can not be zero address"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -615,7 +615,7 @@ contract PionexContractTest is StrategySharedSetup { traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: pionex/user token ratio not good enough"); + vm.expectRevert("PionexContract: pionex/user token ratio not good enough"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -971,7 +971,7 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(cancelPayload); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectRevert("LimitOrder: Order is cancelled"); + vm.expectRevert("PionexContract: Order is cancelled"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -984,7 +984,7 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER, _signOrder(pionexPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) ); - vm.expectRevert("LimitOrder: Cancel request is not signed by user"); + vm.expectRevert("PionexContract: Cancel request is not signed by user"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(cancelPayload); } @@ -994,7 +994,7 @@ contract PionexContractTest is StrategySharedSetup { expiredOrder.expiry = 0; bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(pionexPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); - vm.expectRevert("LimitOrder: Order is expired"); + vm.expectRevert("PionexContract: Order is expired"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -1006,7 +1006,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - vm.expectRevert("LimitOrder: Order is cancelled already"); + vm.expectRevert("PionexContract: Order is cancelled already"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } @@ -1131,7 +1131,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory params, IPionexContract.CoordinatorParams memory crdParams ) internal view returns (bytes memory payload) { - return abi.encodeWithSelector(pionexContract.fillLimitOrderByTrader.selector, order, orderMakerSig, params, crdParams); + return abi.encodeWithSelector(pionexContract.fillLimitOrder.selector, order, orderMakerSig, params, crdParams); } function _genCancelLimitOrderPayload(PionexContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) From a37116d733b6c2c2fdd5d3aa4974daa5d0d36b40 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 26 May 2023 12:28:02 +0800 Subject: [PATCH 22/41] Rename userFeeFactor -> tokenlonFeeFactor --- contracts/PionexContract.sol | 22 +++++++++++----------- test/forkMainnet/PionexContract.t.sol | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index e0ef60e3..344d1e46 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -34,8 +34,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // Factors uint256 public factorsTimeLock; - uint16 public userFeeFactor = 0; - uint16 public pendingMakerFeeFactor; + uint16 public tokenlonFeeFactor = 0; + uint16 public pendingTokenlonFeeFactor; constructor( address _owner, @@ -64,11 +64,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } /// @notice Only owner can call - /// @param _userFeeFactor The new fee factor for user - function setFactors(uint16 _userFeeFactor) external onlyOwner { - require(_userFeeFactor <= LibConstant.BPS_MAX, "PionexContract: Invalid user fee factor"); + /// @param _tokenlonFeeFactor The new fee factor for user + function setFactors(uint16 _tokenlonFeeFactor) external onlyOwner { + require(_tokenlonFeeFactor <= LibConstant.BPS_MAX, "PionexContract: Invalid user fee factor"); - pendingMakerFeeFactor = _userFeeFactor; + pendingTokenlonFeeFactor = _tokenlonFeeFactor; factorsTimeLock = block.timestamp + factorActivateDelay; } @@ -78,10 +78,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(factorsTimeLock != 0, "PionexContract: no pending fee factors"); require(block.timestamp >= factorsTimeLock, "PionexContract: fee factors timelocked"); factorsTimeLock = 0; - userFeeFactor = pendingMakerFeeFactor; - pendingMakerFeeFactor = 0; + tokenlonFeeFactor = pendingTokenlonFeeFactor; + pendingTokenlonFeeFactor = 0; - emit FactorsUpdated(userFeeFactor); + emit FactorsUpdated(tokenlonFeeFactor); } /// @notice Only owner can call @@ -116,7 +116,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require( (_params.gasFeeFactor <= LibConstant.BPS_MAX) && (_params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX) && - (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - userFeeFactor), + (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - tokenlonFeeFactor), "PionexContract: Invalid pionex fee factor" ); @@ -223,7 +223,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // Calculate user fee (user receives pionex token so fee is charged in pionex token) // 1. Fee for Tokenlon - uint256 tokenlonFee = _mulFactor(_settlement.pionexTokenAmount, userFeeFactor); + uint256 tokenlonFee = _mulFactor(_settlement.pionexTokenAmount, tokenlonFeeFactor); // 2. Fee for Pionex, including gas fee and strategy fee uint256 pionexFee = _mulFactor(_settlement.pionexTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); uint256 pionexTokenForMaker = _settlement.pionexTokenAmount.sub(tokenlonFee).sub(pionexFee); diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 542b0f79..70f9df73 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -176,7 +176,7 @@ contract PionexContractTest is StrategySharedSetup { assertEq(address(pionexContract.permStorage()), address(permanentStorage)); assertEq(address(pionexContract.weth()), address(weth)); - assertEq(uint256(pionexContract.userFeeFactor()), 0); + assertEq(uint256(pionexContract.tokenlonFeeFactor()), 0); } /********************************* @@ -310,13 +310,13 @@ contract PionexContractTest is StrategySharedSetup { vm.startPrank(owner, owner); pionexContract.setFactors(1); // fee factors should stay same before new ones activate - assertEq(uint256(pionexContract.userFeeFactor()), 0); + assertEq(uint256(pionexContract.tokenlonFeeFactor()), 0); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); // fee factors should be updated now pionexContract.activateFactors(); vm.stopPrank(); - assertEq(uint256(pionexContract.userFeeFactor()), 1); + assertEq(uint256(pionexContract.tokenlonFeeFactor()), 1); } /********************************* @@ -628,7 +628,7 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); - // userFeeFactor : 10% + // tokenlonFeeFactor : 10% vm.startPrank(owner, owner); pionexContract.setFactors(1000); vm.warp(block.timestamp + pionexContract.factorActivateDelay()); From 1a1093d384240aac77f69e79b4d0ea1a16e1111c Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 26 May 2023 12:28:53 +0800 Subject: [PATCH 23/41] Rename Order.pionexTokenAmount -> minPionexTokenAmount; remainingAmount -> remainingUserTokenAmount --- contracts/PionexContract.sol | 16 ++++---- contracts/interfaces/IPionexContract.sol | 2 +- contracts/utils/PionexContractLibEIP712.sol | 8 ++-- test/forkMainnet/PionexContract.t.sol | 42 ++++++++++----------- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 344d1e46..0143f8c7 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -109,7 +109,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // Check provided pionexToken/userToken ratio is better than or equal to user's specfied pionexToken/userToken ratio // -> _params.pionexTokenAmount/_params.userTokenAmount >= _order.pionexTokenAmount/_order.userTokenAmount require( - _params.pionexTokenAmount.mul(_order.userTokenAmount) >= _order.pionexTokenAmount.mul(_params.userTokenAmount), + _params.pionexTokenAmount.mul(_order.userTokenAmount) >= _order.minPionexTokenAmount.mul(_params.userTokenAmount), "PionexContract: pionex/user token ratio not good enough" ); // Check gas fee factor and pionex strategy fee factor do not exceed limit @@ -133,7 +133,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _validateTraderFill(fill, _params.pionexSig); } - (uint256 userTokenAmount, uint256 remainingAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.userTokenAmount); + (uint256 userTokenAmount, uint256 remainingUserTokenAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.userTokenAmount); // Calculate pionexTokenAmount according to the provided pionexToken/userToken ratio uint256 pionexTokenAmount = userTokenAmount.mul(_params.pionexTokenAmount).div(_params.userTokenAmount); @@ -149,7 +149,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu pionexToken: _order.pionexToken, userTokenAmount: userTokenAmount, pionexTokenAmount: pionexTokenAmount, - remainingAmount: remainingAmount, + remainingUserTokenAmount: remainingUserTokenAmount, gasFeeFactor: _params.gasFeeFactor, pionexStrategyFeeFactor: _params.pionexStrategyFeeFactor }) @@ -211,7 +211,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu IERC20 pionexToken; uint256 userTokenAmount; uint256 pionexTokenAmount; - uint256 remainingAmount; + uint256 remainingUserTokenAmount; uint16 gasFeeFactor; uint16 pionexStrategyFeeFactor; } @@ -251,7 +251,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu pionexToken: address(_settlement.pionexToken), userTokenFilledAmount: _settlement.userTokenAmount, pionexTokenFilledAmount: _settlement.pionexTokenAmount, - remainingAmount: _settlement.remainingAmount, + remainingUserTokenAmount: _settlement.remainingUserTokenAmount, tokenlonFee: tokenlonFee, pionexFee: pionexFee }) @@ -268,7 +268,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(!isCancelled, "PionexContract: Order is cancelled already"); { PionexContractLibEIP712.Order memory cancelledOrder = _order; - cancelledOrder.pionexTokenAmount = 0; + cancelledOrder.minPionexTokenAmount = 0; bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "PionexContract: Cancel request is not signed by user"); @@ -340,7 +340,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address pionexToken; uint256 userTokenFilledAmount; uint256 pionexTokenFilledAmount; - uint256 remainingAmount; + uint256 remainingUserTokenAmount; uint256 tokenlonFee; uint256 pionexFee; } @@ -357,7 +357,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu pionexToken: _params.pionexToken, userTokenFilledAmount: _params.userTokenFilledAmount, pionexTokenFilledAmount: _params.pionexTokenFilledAmount, - remainingAmount: _params.remainingAmount, + remainingUserTokenAmount: _params.remainingUserTokenAmount, tokenlonFee: _params.tokenlonFee, pionexFee: _params.pionexFee }) diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 44470232..704f3bbd 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -48,7 +48,7 @@ interface IPionexContract is IStrategyBase { address pionexToken; uint256 userTokenFilledAmount; uint256 pionexTokenFilledAmount; - uint256 remainingAmount; + uint256 remainingUserTokenAmount; uint256 tokenlonFee; uint256 pionexFee; } diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/PionexContractLibEIP712.sol index 67b73a78..f6053ca8 100644 --- a/contracts/utils/PionexContractLibEIP712.sol +++ b/contracts/utils/PionexContractLibEIP712.sol @@ -10,7 +10,7 @@ library PionexContractLibEIP712 { IERC20 userToken; IERC20 pionexToken; uint256 userTokenAmount; - uint256 pionexTokenAmount; + uint256 minPionexTokenAmount; address user; address pionex; uint256 salt; @@ -24,7 +24,7 @@ library PionexContractLibEIP712 { "address userToken,", "address pionexToken,", "uint256 userTokenAmount,", - "uint256 pionexTokenAmount,", + "uint256 minPionexTokenAmount,", "address user,", "address pionex,", "uint256 salt,", @@ -33,7 +33,7 @@ library PionexContractLibEIP712 { ) ); */ - bytes32 private constant ORDER_TYPEHASH = 0x97aec2eaa3064135fc2be6548ccc65711bf2143e0a4ad193212bfdee8913eb9d; + bytes32 private constant ORDER_TYPEHASH = 0xc3eca7f47a388a29b03acba9184de40640fb7d9394cc3ef572b90c15c2f34feb; function _getOrderStructHash(Order memory _order) internal pure returns (bytes32) { return @@ -43,7 +43,7 @@ library PionexContractLibEIP712 { address(_order.userToken), address(_order.pionexToken), _order.userTokenAmount, - _order.pionexTokenAmount, + _order.minPionexTokenAmount, _order.user, _order.pionex, _order.salt, diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 70f9df73..7694a4ed 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -72,7 +72,7 @@ contract PionexContractTest is StrategySharedSetup { dai, // userToken usdt, // pionexToken 100 * 1e18, // userTokenAmount - 90 * 1e6, // pionexTokenAmount + 90 * 1e6, // minPionexTokenAmount user, // user address(0), // pionex uint256(1001), // salt @@ -85,7 +85,7 @@ contract PionexContractTest is StrategySharedSetup { pionex, receiver, DEFAULT_ORDER.userTokenAmount, - DEFAULT_ORDER.pionexTokenAmount, + DEFAULT_ORDER.minPionexTokenAmount, uint256(1002), DEADLINE ); @@ -652,21 +652,21 @@ contract PionexContractTest is StrategySharedSetup { address(DEFAULT_ORDER.userToken), address(DEFAULT_ORDER.pionexToken), DEFAULT_ORDER.userTokenAmount, - DEFAULT_ORDER.pionexTokenAmount, - 0, // remainingAmount should be zero after order fully filled - DEFAULT_ORDER.pionexTokenAmount.mul(10).div(100), // tokenlonFee = 10% pionexTokenAmount - DEFAULT_ORDER.pionexTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% pionexTokenAmount + DEFAULT_ORDER.minPionexTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + DEFAULT_ORDER.minPionexTokenAmount.mul(10).div(100), // tokenlonFee = 10% pionexTokenAmount + DEFAULT_ORDER.minPionexTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% pionexTokenAmount ) ); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from pionexTokenAmount directly + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from pionexTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.mul(87).div(100))); // 10% fee for Tokenlon and 3% fee for Pionex + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.mul(87).div(100))); // 10% fee for Tokenlon and 3% fee for Pionex userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); - fcTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.mul(10).div(100))); + fcTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.mul(10).div(100))); } function testFullyFillByTraderWithBetterTakerMakerTokenRatio() public { @@ -704,7 +704,7 @@ contract PionexContractTest is StrategySharedSetup { address(DEFAULT_ORDER.pionexToken), DEFAULT_ORDER.userTokenAmount, fill.pionexTokenAmount, - 0, // remainingAmount should be zero after order fully filled + 0, // remainingUserTokenAmount should be zero after order fully filled 0, 0 ) @@ -797,7 +797,7 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); - fill.pionexTokenAmount = DEFAULT_ORDER.pionexTokenAmount.mul(2); + fill.pionexTokenAmount = DEFAULT_ORDER.minPionexTokenAmount.mul(2); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; @@ -815,9 +815,9 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount)); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount)); userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); } @@ -830,7 +830,7 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); - fill.pionexTokenAmount = DEFAULT_ORDER.pionexTokenAmount.mul(2).mul(11).div(10); // 10% more + fill.pionexTokenAmount = DEFAULT_ORDER.minPionexTokenAmount.mul(2).mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; @@ -848,9 +848,9 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount.mul(11).div(10))); // 10% more + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount.mul(11).div(10))); // 10% more receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.mul(11).div(10))); // 10% more + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.mul(11).div(10))); // 10% more userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); } @@ -900,9 +900,9 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.pionexTokenAmount.div(2))); + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount.div(2))); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount.div(2))); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.pionexTokenAmount.div(2))); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.div(2))); userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2))); } @@ -964,7 +964,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillCanceledOrder() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.pionexTokenAmount = 0; + zeroOrder.minPionexTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(pionex, pionex); // Only EOA @@ -978,7 +978,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotCancelIfNotMaker() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.pionexTokenAmount = 0; + zeroOrder.minPionexTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload( DEFAULT_ORDER, @@ -1001,7 +1001,7 @@ contract PionexContractTest is StrategySharedSetup { function testCannotCancelTwice() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.pionexTokenAmount = 0; + zeroOrder.minPionexTokenAmount = 0; bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(pionex, pionex); // Only EOA From e5f5046e5d322cc1d37c8cdc41212877b1ab99bf Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 26 May 2023 12:34:34 +0800 Subject: [PATCH 24/41] Update after merge --- test/forkMainnet/PionexContract.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 7694a4ed..4f4feb4d 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -144,8 +144,8 @@ contract PionexContractTest is StrategySharedSetup { feeCollector ); // Setup + vm.startPrank(tokenlonOperator, tokenlonOperator); userProxy.upgradeLimitOrder(address(pionexContract), true); - vm.startPrank(psOperator, psOperator); permanentStorage.upgradeLimitOrder(address(pionexContract)); permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(pionexContract), true); permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(pionexContract), true); From 1a4bf65327bd21204bef0881d0dd3388fb746a2a Mon Sep 17 00:00:00 2001 From: NIC619 Date: Mon, 29 May 2023 15:00:30 +0800 Subject: [PATCH 25/41] Remove TraderSettlement.pionex param --- contracts/PionexContract.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 0143f8c7..461b8973 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -144,7 +144,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu trader: _params.pionex, recipient: _params.recipient, user: _order.user, - pionex: _order.pionex, userToken: _order.userToken, pionexToken: _order.pionexToken, userTokenAmount: userTokenAmount, @@ -206,7 +205,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address trader; address recipient; address user; - address pionex; IERC20 userToken; IERC20 pionexToken; uint256 userTokenAmount; From b1e9d4bcf4a5fbdef2caab78f51b2a79a45a4159 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Mon, 29 May 2023 15:03:52 +0800 Subject: [PATCH 26/41] Rename Maker -> User --- contracts/PionexContract.sol | 30 +++++++++---------- contracts/interfaces/IPionexContract.sol | 8 ++--- .../utils/LibPionexContractOrderStorage.sol | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 461b8973..00198d51 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -96,13 +96,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @inheritdoc IPionexContract function fillLimitOrder( PionexContractLibEIP712.Order calldata _order, - bytes calldata _orderMakerSig, + bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams ) external override onlyUserProxy nonReentrant returns (uint256, uint256) { bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); - _validateOrder(_order, orderHash, _orderMakerSig); + _validateOrder(_order, orderHash, _orderUserSig); bytes32 allowFillHash = _validateFillPermission(orderHash, _params.pionexTokenAmount, _params.pionex, _crdParams); _validateOrderTaker(_order, _params.pionex); @@ -133,7 +133,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _validateTraderFill(fill, _params.pionexSig); } - (uint256 userTokenAmount, uint256 remainingUserTokenAmount) = _quoteOrderFromMakerToken(_order, orderHash, _params.userTokenAmount); + (uint256 userTokenAmount, uint256 remainingUserTokenAmount) = _quoteOrderFromUserToken(_order, orderHash, _params.userTokenAmount); // Calculate pionexTokenAmount according to the provided pionexToken/userToken ratio uint256 pionexTokenAmount = userTokenAmount.mul(_params.pionexTokenAmount).div(_params.userTokenAmount); @@ -154,7 +154,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu }) ); - _recordMakerTokenFilled(orderHash, userTokenAmount); + _recordUserTokenFilled(orderHash, userTokenAmount); return (pionexTokenAmount, userTokenOut); } @@ -224,10 +224,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu uint256 tokenlonFee = _mulFactor(_settlement.pionexTokenAmount, tokenlonFeeFactor); // 2. Fee for Pionex, including gas fee and strategy fee uint256 pionexFee = _mulFactor(_settlement.pionexTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); - uint256 pionexTokenForMaker = _settlement.pionexTokenAmount.sub(tokenlonFee).sub(pionexFee); + uint256 pionexTokenForUser = _settlement.pionexTokenAmount.sub(tokenlonFee).sub(pionexFee); // trader -> user - _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _settlement.user, pionexTokenForMaker); + _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _settlement.user, pionexTokenForUser); // user -> recipient _spender.spendFromUserTo(_settlement.user, address(_settlement.userToken), _settlement.recipient, _settlement.userTokenAmount); @@ -259,7 +259,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } /// @inheritdoc IPionexContract - function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderMakerSig) external override onlyUserProxy nonReentrant { + function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) external override onlyUserProxy nonReentrant { require(_order.expiry > uint64(block.timestamp), "PionexContract: Order is expired"); bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; @@ -269,7 +269,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu cancelledOrder.minPionexTokenAmount = 0; bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); - require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderMakerSig), "PionexContract: Cancel request is not signed by user"); + require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderUserSig), "PionexContract: Cancel request is not signed by user"); } // Set cancelled state to storage @@ -282,13 +282,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu function _validateOrder( PionexContractLibEIP712.Order memory _order, bytes32 _orderHash, - bytes memory _orderMakerSig + bytes memory _orderUserSig ) internal view { require(_order.expiry > uint64(block.timestamp), "PionexContract: Order is expired"); bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[_orderHash]; require(!isCancelled, "PionexContract: Order is cancelled"); - require(isValidSignature(_order.user, _orderHash, bytes(""), _orderMakerSig), "PionexContract: Order is not signed by user"); + require(isValidSignature(_order.user, _orderHash, bytes(""), _orderUserSig), "PionexContract: Order is not signed by user"); } function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _pionex) internal pure { @@ -297,12 +297,12 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu } } - function _quoteOrderFromMakerToken( + function _quoteOrderFromUserToken( PionexContractLibEIP712.Order memory _order, bytes32 _orderHash, uint256 _userTokenAmount ) internal view returns (uint256, uint256) { - uint256 userTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToMakerTokenFilledAmount[_orderHash]; + uint256 userTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToUserTokenFilledAmount[_orderHash]; require(userTokenFilledAmount < _order.userTokenAmount, "PionexContract: Order is filled"); @@ -314,10 +314,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu return (userTokenQuota, remainingAfterFill); } - function _recordMakerTokenFilled(bytes32 _orderHash, uint256 _userTokenAmount) internal { + function _recordUserTokenFilled(bytes32 _orderHash, uint256 _userTokenAmount) internal { LibPionexContractOrderStorage.Storage storage stor = LibPionexContractOrderStorage.getStorage(); - uint256 userTokenFilledAmount = stor.orderHashToMakerTokenFilledAmount[_orderHash]; - stor.orderHashToMakerTokenFilledAmount[_orderHash] = userTokenFilledAmount.add(_userTokenAmount); + uint256 userTokenFilledAmount = stor.orderHashToUserTokenFilledAmount[_orderHash]; + stor.orderHashToUserTokenFilledAmount[_orderHash] = userTokenFilledAmount.add(_userTokenAmount); } /* math utils */ diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 704f3bbd..1bbff8dd 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -74,12 +74,12 @@ interface IPionexContract is IStrategyBase { /// @notice Fill an order by a trader /// @notice Only user proxy can call /// @param _order The order that is going to be filled - /// @param _orderMakerSig The signature of the order from user + /// @param _orderUserSig The signature of the order from user /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit function fillLimitOrder( PionexContractLibEIP712.Order calldata _order, - bytes calldata _orderMakerSig, + bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams ) external returns (uint256, uint256); @@ -87,6 +87,6 @@ interface IPionexContract is IStrategyBase { /// @notice Cancel an order /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled - /// @param _cancelMakerSig The cancelling signature signed by user - function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelMakerSig) external; + /// @param _cancelUserSig The cancelling signature signed by user + function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelUserSig) external; } diff --git a/contracts/utils/LibPionexContractOrderStorage.sol b/contracts/utils/LibPionexContractOrderStorage.sol index f465d957..8056fbf4 100644 --- a/contracts/utils/LibPionexContractOrderStorage.sol +++ b/contracts/utils/LibPionexContractOrderStorage.sol @@ -6,7 +6,7 @@ library LibPionexContractOrderStorage { /// @dev Storage bucket for this feature. struct Storage { // How much maker token has been filled in order. - mapping(bytes32 => uint256) orderHashToMakerTokenFilledAmount; + mapping(bytes32 => uint256) orderHashToUserTokenFilledAmount; // Whether order is cancelled or not. mapping(bytes32 => bool) orderHashToCancelled; } From 273d472a0b15077a2fd4bdf13241bc0374965ebc Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 9 Jun 2023 18:39:28 +0800 Subject: [PATCH 27/41] Add minPionexTokenAmount check to protect user --- contracts/PionexContract.sol | 13 ++- test/forkMainnet/PionexContract.t.sol | 133 ++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 15 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 00198d51..e91c705b 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -136,8 +136,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu (uint256 userTokenAmount, uint256 remainingUserTokenAmount) = _quoteOrderFromUserToken(_order, orderHash, _params.userTokenAmount); // Calculate pionexTokenAmount according to the provided pionexToken/userToken ratio uint256 pionexTokenAmount = userTokenAmount.mul(_params.pionexTokenAmount).div(_params.userTokenAmount); + // Calculate minimum pionexTokenAmount according to the offer's pionexToken/userToken ratio + uint256 minPionexTokenAmount = userTokenAmount.mul(_order.minPionexTokenAmount).div(_order.userTokenAmount); - uint256 userTokenOut = _settleForTrader( + _settleForTrader( TraderSettlement({ orderHash: orderHash, allowFillHash: allowFillHash, @@ -148,6 +150,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu pionexToken: _order.pionexToken, userTokenAmount: userTokenAmount, pionexTokenAmount: pionexTokenAmount, + minPionexTokenAmount: minPionexTokenAmount, remainingUserTokenAmount: remainingUserTokenAmount, gasFeeFactor: _params.gasFeeFactor, pionexStrategyFeeFactor: _params.pionexStrategyFeeFactor @@ -156,7 +159,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu _recordUserTokenFilled(orderHash, userTokenAmount); - return (pionexTokenAmount, userTokenOut); + return (pionexTokenAmount, userTokenAmount); } function _validateTraderFill(PionexContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { @@ -209,12 +212,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu IERC20 pionexToken; uint256 userTokenAmount; uint256 pionexTokenAmount; + uint256 minPionexTokenAmount; uint256 remainingUserTokenAmount; uint16 gasFeeFactor; uint16 pionexStrategyFeeFactor; } - function _settleForTrader(TraderSettlement memory _settlement) internal returns (uint256) { + function _settleForTrader(TraderSettlement memory _settlement) internal { // memory cache ISpender _spender = spender; address _feeCollector = feeCollector; @@ -225,6 +229,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // 2. Fee for Pionex, including gas fee and strategy fee uint256 pionexFee = _mulFactor(_settlement.pionexTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); uint256 pionexTokenForUser = _settlement.pionexTokenAmount.sub(tokenlonFee).sub(pionexFee); + require(pionexTokenForUser >= _settlement.minPionexTokenAmount, "PionexContract: pionex token amount not enough"); // trader -> user _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _settlement.user, pionexTokenForUser); @@ -254,8 +259,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu pionexFee: pionexFee }) ); - - return _settlement.userTokenAmount; } /// @inheritdoc IPionexContract diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index 4f4feb4d..cc2881c4 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -620,7 +620,56 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload); } - function testFullyFillByTrader() public { + function testCannotFullyFillByTraderWithWorseTakerTokenAmountDueToFee() public { + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% + traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% + traderParams.pionexSig = _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + vm.expectRevert("PionexContract: pionex token amount not enough"); + vm.prank(pionex, pionex); // Only EOA + userProxy.toLimitOrder(payload); + } + + function testFullyFillByTraderWithNoFee() public { + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + vm.expectEmit(true, true, true, true); + emit LimitOrderFilledByTrader( + DEFAULT_ORDER_HASH, + DEFAULT_ORDER.user, + pionex, + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + DEFAULT_TRADER_PARAMS.recipient, + IPionexContract.FillReceipt( + address(DEFAULT_ORDER.userToken), + address(DEFAULT_ORDER.pionexToken), + DEFAULT_ORDER.userTokenAmount, + DEFAULT_ORDER.minPionexTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + 0, // tokenlonFee = 0 + 0 // pionexStrategyFee = 0 + ) + ); + vm.prank(pionex, pionex); // Only EOA + userProxy.toLimitOrder(payload); + + pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount)); + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); + fcMakerAsset.assertChange(0); + fcTakerAsset.assertChange(0); + } + + function testFullyFillByTraderWithAddedTokenlonFee() public { BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); @@ -635,38 +684,102 @@ contract PionexContractTest is StrategySharedSetup { pionexContract.activateFactors(); vm.stopPrank(); + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + // Increase pionex token amount so the pionexToken/userToken ratio is better than order's pionexToken/userToken ratio + // to account for tokenlon fee + fill.pionexTokenAmount = DEFAULT_FILL.pionexTokenAmount.mul(115).div(100); // 15% more + + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.pionexTokenAmount = fill.pionexTokenAmount; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = traderParams.pionexTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); + vm.expectEmit(true, true, true, true); + emit LimitOrderFilledByTrader( + DEFAULT_ORDER_HASH, + DEFAULT_ORDER.user, + pionex, + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + DEFAULT_TRADER_PARAMS.recipient, + IPionexContract.FillReceipt( + address(DEFAULT_ORDER.userToken), + address(DEFAULT_ORDER.pionexToken), + DEFAULT_ORDER.userTokenAmount, + traderParams.pionexTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + traderParams.pionexTokenAmount.div(10), // tokenlonFee = 10% pionexTokenAmount + 0 // pionexStrategyFee = 0 + ) + ); + vm.prank(pionex, pionex); // Only EOA + userProxy.toLimitOrder(payload); + + pionexTakerAsset.assertChange(-int256(traderParams.pionexTokenAmount)); + receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); + userTakerAsset.assertChange(int256(traderParams.pionexTokenAmount.mul(9).div(10))); // 10% fee for Tokenlon + userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); + fcMakerAsset.assertChange(0); + fcTakerAsset.assertChange(int256(traderParams.pionexTokenAmount.div(10))); + } + + function testFullyFillByTraderWithAddedGasFeeAndStrategyFee() public { + BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + + PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + // Increase pionex token amount so the pionexToken/userToken ratio is better than order's pionexToken/userToken ratio + // to account for gas fee and pionex strategy fee + fill.pionexTokenAmount = DEFAULT_FILL.pionexTokenAmount.mul(11).div(10); // 10% more + IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% - traderParams.pionexSig = _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + traderParams.pionexTokenAmount = fill.pionexTokenAmount; + traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.fillAmount = traderParams.pionexTokenAmount; + + IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, pionex, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, IPionexContract.FillReceipt( address(DEFAULT_ORDER.userToken), address(DEFAULT_ORDER.pionexToken), DEFAULT_ORDER.userTokenAmount, - DEFAULT_ORDER.minPionexTokenAmount, + traderParams.pionexTokenAmount, 0, // remainingUserTokenAmount should be zero after order fully filled - DEFAULT_ORDER.minPionexTokenAmount.mul(10).div(100), // tokenlonFee = 10% pionexTokenAmount - DEFAULT_ORDER.minPionexTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% pionexTokenAmount + 0, // tokenlonFee = 0 + traderParams.pionexTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% pionexTokenAmount ) ); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from pionexTokenAmount directly + pionexTakerAsset.assertChange(-int256(traderParams.pionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from pionexTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.mul(87).div(100))); // 10% fee for Tokenlon and 3% fee for Pionex + userTakerAsset.assertChange(int256(traderParams.pionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); - fcTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.mul(10).div(100))); + fcTakerAsset.assertChange(0); } function testFullyFillByTraderWithBetterTakerMakerTokenRatio() public { From ed48d9bd9646f77b1f5aead59dfd4021bbedcf47 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Mon, 12 Jun 2023 14:10:04 +0800 Subject: [PATCH 28/41] Remove ratio check bc we check minPionexTokenAmount --- contracts/PionexContract.sol | 6 ------ test/forkMainnet/PionexContract.t.sol | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index e91c705b..7a0869c8 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -106,12 +106,6 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes32 allowFillHash = _validateFillPermission(orderHash, _params.pionexTokenAmount, _params.pionex, _crdParams); _validateOrderTaker(_order, _params.pionex); - // Check provided pionexToken/userToken ratio is better than or equal to user's specfied pionexToken/userToken ratio - // -> _params.pionexTokenAmount/_params.userTokenAmount >= _order.pionexTokenAmount/_order.userTokenAmount - require( - _params.pionexTokenAmount.mul(_order.userTokenAmount) >= _order.minPionexTokenAmount.mul(_params.userTokenAmount), - "PionexContract: pionex/user token ratio not good enough" - ); // Check gas fee factor and pionex strategy fee factor do not exceed limit require( (_params.gasFeeFactor <= LibConstant.BPS_MAX) && diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index cc2881c4..f1f4de3d 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -615,7 +615,7 @@ contract PionexContractTest is StrategySharedSetup { traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: pionex/user token ratio not good enough"); + vm.expectRevert("PionexContract: pionex token amount not enough"); vm.prank(pionex, pionex); // Only EOA userProxy.toLimitOrder(payload); } From f92de423d15bba2b03eaa8ff781ffdff41fba8dd Mon Sep 17 00:00:00 2001 From: NIC619 Date: Mon, 12 Jun 2023 16:38:33 +0800 Subject: [PATCH 29/41] Rename pionex -> dealer --- contracts/PionexContract.sol | 100 ++-- contracts/interfaces/IPionexContract.sol | 20 +- contracts/utils/PionexContractLibEIP712.sol | 40 +- test/forkMainnet/PionexContract.t.sol | 568 ++++++++++---------- 4 files changed, 364 insertions(+), 364 deletions(-) diff --git a/contracts/PionexContract.sol b/contracts/PionexContract.sol index 7a0869c8..d32a420d 100644 --- a/contracts/PionexContract.sol +++ b/contracts/PionexContract.sol @@ -20,7 +20,7 @@ import "./utils/PionexContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; /// @title Pionex Contract -/// @notice Order can be filled as long as the provided pionexToken/userToken ratio is better than or equal to user's specfied pionexToken/userToken ratio. +/// @notice Order can be filled as long as the provided dealerToken/userToken ratio is better than or equal to user's specfied dealerToken/userToken ratio. /// @author imToken Labs contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { using SafeMath for uint256; @@ -103,57 +103,57 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); _validateOrder(_order, orderHash, _orderUserSig); - bytes32 allowFillHash = _validateFillPermission(orderHash, _params.pionexTokenAmount, _params.pionex, _crdParams); - _validateOrderTaker(_order, _params.pionex); + bytes32 allowFillHash = _validateFillPermission(orderHash, _params.dealerTokenAmount, _params.dealer, _crdParams); + _validateOrderTaker(_order, _params.dealer); - // Check gas fee factor and pionex strategy fee factor do not exceed limit + // Check gas fee factor and dealer strategy fee factor do not exceed limit require( (_params.gasFeeFactor <= LibConstant.BPS_MAX) && - (_params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX) && - (_params.gasFeeFactor + _params.pionexStrategyFeeFactor <= LibConstant.BPS_MAX - tokenlonFeeFactor), - "PionexContract: Invalid pionex fee factor" + (_params.dealerStrategyFeeFactor <= LibConstant.BPS_MAX) && + (_params.gasFeeFactor + _params.dealerStrategyFeeFactor <= LibConstant.BPS_MAX - tokenlonFeeFactor), + "PionexContract: Invalid dealer fee factor" ); { PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ orderHash: orderHash, - pionex: _params.pionex, + dealer: _params.dealer, recipient: _params.recipient, userTokenAmount: _params.userTokenAmount, - pionexTokenAmount: _params.pionexTokenAmount, - pionexSalt: _params.salt, + dealerTokenAmount: _params.dealerTokenAmount, + dealerSalt: _params.salt, expiry: _params.expiry }); - _validateTraderFill(fill, _params.pionexSig); + _validateTraderFill(fill, _params.dealerSig); } (uint256 userTokenAmount, uint256 remainingUserTokenAmount) = _quoteOrderFromUserToken(_order, orderHash, _params.userTokenAmount); - // Calculate pionexTokenAmount according to the provided pionexToken/userToken ratio - uint256 pionexTokenAmount = userTokenAmount.mul(_params.pionexTokenAmount).div(_params.userTokenAmount); - // Calculate minimum pionexTokenAmount according to the offer's pionexToken/userToken ratio - uint256 minPionexTokenAmount = userTokenAmount.mul(_order.minPionexTokenAmount).div(_order.userTokenAmount); + // Calculate dealerTokenAmount according to the provided dealerToken/userToken ratio + uint256 dealerTokenAmount = userTokenAmount.mul(_params.dealerTokenAmount).div(_params.userTokenAmount); + // Calculate minimum dealerTokenAmount according to the offer's dealerToken/userToken ratio + uint256 minDealerTokenAmount = userTokenAmount.mul(_order.minDealerTokenAmount).div(_order.userTokenAmount); _settleForTrader( TraderSettlement({ orderHash: orderHash, allowFillHash: allowFillHash, - trader: _params.pionex, + trader: _params.dealer, recipient: _params.recipient, user: _order.user, userToken: _order.userToken, - pionexToken: _order.pionexToken, + dealerToken: _order.dealerToken, userTokenAmount: userTokenAmount, - pionexTokenAmount: pionexTokenAmount, - minPionexTokenAmount: minPionexTokenAmount, + dealerTokenAmount: dealerTokenAmount, + minDealerTokenAmount: minDealerTokenAmount, remainingUserTokenAmount: remainingUserTokenAmount, gasFeeFactor: _params.gasFeeFactor, - pionexStrategyFeeFactor: _params.pionexStrategyFeeFactor + dealerStrategyFeeFactor: _params.dealerStrategyFeeFactor }) ); _recordUserTokenFilled(orderHash, userTokenAmount); - return (pionexTokenAmount, userTokenAmount); + return (dealerTokenAmount, userTokenAmount); } function _validateTraderFill(PionexContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { @@ -161,7 +161,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(_fill.recipient != address(0), "PionexContract: recipient can not be zero address"); bytes32 fillHash = getEIP712Hash(PionexContractLibEIP712._getFillStructHash(_fill)); - require(isValidSignature(_fill.pionex, fillHash, bytes(""), _fillTakerSig), "PionexContract: Fill is not signed by pionex"); + require(isValidSignature(_fill.dealer, fillHash, bytes(""), _fillTakerSig), "PionexContract: Fill is not signed by dealer"); // Set fill seen to avoid replay attack. // PermanentStorage would throw error if fill is already seen. @@ -203,13 +203,13 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address recipient; address user; IERC20 userToken; - IERC20 pionexToken; + IERC20 dealerToken; uint256 userTokenAmount; - uint256 pionexTokenAmount; - uint256 minPionexTokenAmount; + uint256 dealerTokenAmount; + uint256 minDealerTokenAmount; uint256 remainingUserTokenAmount; uint16 gasFeeFactor; - uint16 pionexStrategyFeeFactor; + uint16 dealerStrategyFeeFactor; } function _settleForTrader(TraderSettlement memory _settlement) internal { @@ -217,23 +217,23 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu ISpender _spender = spender; address _feeCollector = feeCollector; - // Calculate user fee (user receives pionex token so fee is charged in pionex token) + // Calculate user fee (user receives dealer token so fee is charged in dealer token) // 1. Fee for Tokenlon - uint256 tokenlonFee = _mulFactor(_settlement.pionexTokenAmount, tokenlonFeeFactor); + uint256 tokenlonFee = _mulFactor(_settlement.dealerTokenAmount, tokenlonFeeFactor); // 2. Fee for Pionex, including gas fee and strategy fee - uint256 pionexFee = _mulFactor(_settlement.pionexTokenAmount, _settlement.gasFeeFactor + _settlement.pionexStrategyFeeFactor); - uint256 pionexTokenForUser = _settlement.pionexTokenAmount.sub(tokenlonFee).sub(pionexFee); - require(pionexTokenForUser >= _settlement.minPionexTokenAmount, "PionexContract: pionex token amount not enough"); + uint256 dealerFee = _mulFactor(_settlement.dealerTokenAmount, _settlement.gasFeeFactor + _settlement.dealerStrategyFeeFactor); + uint256 dealerTokenForUser = _settlement.dealerTokenAmount.sub(tokenlonFee).sub(dealerFee); + require(dealerTokenForUser >= _settlement.minDealerTokenAmount, "PionexContract: dealer token amount not enough"); // trader -> user - _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _settlement.user, pionexTokenForUser); + _spender.spendFromUserTo(_settlement.trader, address(_settlement.dealerToken), _settlement.user, dealerTokenForUser); // user -> recipient _spender.spendFromUserTo(_settlement.user, address(_settlement.userToken), _settlement.recipient, _settlement.userTokenAmount); - // Collect user fee (charged in pionex token) + // Collect user fee (charged in dealer token) if (tokenlonFee > 0) { - _spender.spendFromUserTo(_settlement.trader, address(_settlement.pionexToken), _feeCollector, tokenlonFee); + _spender.spendFromUserTo(_settlement.trader, address(_settlement.dealerToken), _feeCollector, tokenlonFee); } // bypass stack too deep error @@ -241,16 +241,16 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu LimitOrderFilledByTraderParams({ orderHash: _settlement.orderHash, user: _settlement.user, - pionex: _settlement.trader, + dealer: _settlement.trader, allowFillHash: _settlement.allowFillHash, recipient: _settlement.recipient, userToken: address(_settlement.userToken), - pionexToken: address(_settlement.pionexToken), + dealerToken: address(_settlement.dealerToken), userTokenFilledAmount: _settlement.userTokenAmount, - pionexTokenFilledAmount: _settlement.pionexTokenAmount, + dealerTokenFilledAmount: _settlement.dealerTokenAmount, remainingUserTokenAmount: _settlement.remainingUserTokenAmount, tokenlonFee: tokenlonFee, - pionexFee: pionexFee + dealerFee: dealerFee }) ); } @@ -263,7 +263,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(!isCancelled, "PionexContract: Order is cancelled already"); { PionexContractLibEIP712.Order memory cancelledOrder = _order; - cancelledOrder.minPionexTokenAmount = 0; + cancelledOrder.minDealerTokenAmount = 0; bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderUserSig), "PionexContract: Cancel request is not signed by user"); @@ -288,9 +288,9 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu require(isValidSignature(_order.user, _orderHash, bytes(""), _orderUserSig), "PionexContract: Order is not signed by user"); } - function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _pionex) internal pure { - if (_order.pionex != address(0)) { - require(_order.pionex == _pionex, "PionexContract: Order cannot be filled by this pionex"); + function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _dealer) internal pure { + if (_order.dealer != address(0)) { + require(_order.dealer == _dealer, "PionexContract: Order cannot be filled by this dealer"); } } @@ -328,33 +328,33 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu struct LimitOrderFilledByTraderParams { bytes32 orderHash; address user; - address pionex; + address dealer; bytes32 allowFillHash; address recipient; address userToken; - address pionexToken; + address dealerToken; uint256 userTokenFilledAmount; - uint256 pionexTokenFilledAmount; + uint256 dealerTokenFilledAmount; uint256 remainingUserTokenAmount; uint256 tokenlonFee; - uint256 pionexFee; + uint256 dealerFee; } function _emitLimitOrderFilledByTrader(LimitOrderFilledByTraderParams memory _params) internal { emit LimitOrderFilledByTrader( _params.orderHash, _params.user, - _params.pionex, + _params.dealer, _params.allowFillHash, _params.recipient, FillReceipt({ userToken: _params.userToken, - pionexToken: _params.pionexToken, + dealerToken: _params.dealerToken, userTokenFilledAmount: _params.userTokenFilledAmount, - pionexTokenFilledAmount: _params.pionexTokenFilledAmount, + dealerTokenFilledAmount: _params.dealerTokenFilledAmount, remainingUserTokenAmount: _params.remainingUserTokenAmount, tokenlonFee: _params.tokenlonFee, - pionexFee: _params.pionexFee + dealerFee: _params.dealerFee }) ); } diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/IPionexContract.sol index 1bbff8dd..37be59ca 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/IPionexContract.sol @@ -22,17 +22,17 @@ interface IPionexContract is IStrategyBase { /// @param newFeeCollector The address of the new fee collector event SetFeeCollector(address newFeeCollector); - /// @notice Emitted when an order is filled by Pionex agent + /// @notice Emitted when an order is filled by dealer /// @param orderHash The EIP-712 hash of the target order /// @param user The address of the user - /// @param pionex The address of the pionex (trader) + /// @param dealer The address of the dealer /// @param allowFillHash The EIP-712 hash of the fill permit granted by coordinator /// @param recipient The address of the recipient which will receive tokens from user /// @param fillReceipt Contains details of this single fill event LimitOrderFilledByTrader( bytes32 indexed orderHash, address indexed user, - address indexed pionex, + address indexed dealer, bytes32 allowFillHash, address recipient, FillReceipt fillReceipt @@ -45,12 +45,12 @@ interface IPionexContract is IStrategyBase { struct FillReceipt { address userToken; - address pionexToken; + address dealerToken; uint256 userTokenFilledAmount; - uint256 pionexTokenFilledAmount; + uint256 dealerTokenFilledAmount; uint256 remainingUserTokenAmount; uint256 tokenlonFee; - uint256 pionexFee; + uint256 dealerFee; } struct CoordinatorParams { @@ -60,15 +60,15 @@ interface IPionexContract is IStrategyBase { } struct TraderParams { - address pionex; + address dealer; address recipient; uint256 userTokenAmount; - uint256 pionexTokenAmount; + uint256 dealerTokenAmount; uint16 gasFeeFactor; - uint16 pionexStrategyFeeFactor; + uint16 dealerStrategyFeeFactor; uint256 salt; uint64 expiry; - bytes pionexSig; + bytes dealerSig; } /// @notice Fill an order by a trader diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/PionexContractLibEIP712.sol index f6053ca8..fba91b5f 100644 --- a/contracts/utils/PionexContractLibEIP712.sol +++ b/contracts/utils/PionexContractLibEIP712.sol @@ -8,11 +8,11 @@ import "../interfaces/IPionexContract.sol"; library PionexContractLibEIP712 { struct Order { IERC20 userToken; - IERC20 pionexToken; + IERC20 dealerToken; uint256 userTokenAmount; - uint256 minPionexTokenAmount; + uint256 minDealerTokenAmount; address user; - address pionex; + address dealer; uint256 salt; uint64 expiry; } @@ -22,18 +22,18 @@ library PionexContractLibEIP712 { abi.encodePacked( "Order(", "address userToken,", - "address pionexToken,", + "address dealerToken,", "uint256 userTokenAmount,", - "uint256 minPionexTokenAmount,", + "uint256 minDealerTokenAmount,", "address user,", - "address pionex,", + "address dealer,", "uint256 salt,", "uint64 expiry", ")" ) ); */ - bytes32 private constant ORDER_TYPEHASH = 0xc3eca7f47a388a29b03acba9184de40640fb7d9394cc3ef572b90c15c2f34feb; + bytes32 private constant ORDER_TYPEHASH = 0x2f0bead1a08e744d3b433a8d66c0a8f920a802838bc159ace4322e432f51458d; function _getOrderStructHash(Order memory _order) internal pure returns (bytes32) { return @@ -41,11 +41,11 @@ library PionexContractLibEIP712 { abi.encode( ORDER_TYPEHASH, address(_order.userToken), - address(_order.pionexToken), + address(_order.dealerToken), _order.userTokenAmount, - _order.minPionexTokenAmount, + _order.minDealerTokenAmount, _order.user, - _order.pionex, + _order.dealer, _order.salt, _order.expiry ) @@ -54,11 +54,11 @@ library PionexContractLibEIP712 { struct Fill { bytes32 orderHash; // EIP712 hash - address pionex; + address dealer; address recipient; uint256 userTokenAmount; - uint256 pionexTokenAmount; - uint256 pionexSalt; + uint256 dealerTokenAmount; + uint256 dealerSalt; uint64 expiry; } @@ -67,17 +67,17 @@ library PionexContractLibEIP712 { abi.encodePacked( "Fill(", "bytes32 orderHash,", - "address pionex,", + "address dealer,", "address recipient,", "uint256 userTokenAmount,", - "uint256 pionexTokenAmount,", - "uint256 pionexSalt,", + "uint256 dealerTokenAmount,", + "uint256 dealerSalt,", "uint64 expiry", ")" ) ); */ - bytes32 private constant FILL_TYPEHASH = 0x8df856cadbad83b5dc946bdac2a541b74332d7444f83e9794203304034f44166; + bytes32 private constant FILL_TYPEHASH = 0xd368a73a41233a76912e96676a984799852399878d2dc3ae8ddd0480b42aec88; function _getFillStructHash(Fill memory _fill) internal pure returns (bytes32) { return @@ -85,11 +85,11 @@ library PionexContractLibEIP712 { abi.encode( FILL_TYPEHASH, _fill.orderHash, - _fill.pionex, + _fill.dealer, _fill.recipient, _fill.userTokenAmount, - _fill.pionexTokenAmount, - _fill.pionexSalt, + _fill.dealerTokenAmount, + _fill.dealerSalt, _fill.expiry ) ); diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/PionexContract.t.sol index f1f4de3d..db7b3130 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/PionexContract.t.sol @@ -24,24 +24,24 @@ contract PionexContractTest is StrategySharedSetup { event LimitOrderFilledByTrader( bytes32 indexed orderHash, address indexed user, - address indexed pionex, + address indexed dealer, bytes32 allowFillHash, address recipient, IPionexContract.FillReceipt fillReceipt ); - uint256 pionexPrivateKey = uint256(1); + uint256 dealerPrivateKey = uint256(1); uint256 userPrivateKey = uint256(2); uint256 coordinatorPrivateKey = uint256(3); - address pionex = vm.addr(pionexPrivateKey); + address dealer = vm.addr(dealerPrivateKey); address user = vm.addr(userPrivateKey); address coordinator = vm.addr(coordinatorPrivateKey); address owner = makeAddr("owner"); address feeCollector = makeAddr("feeCollector"); address receiver = makeAddr("receiver"); - MockERC1271Wallet mockERC1271Wallet = new MockERC1271Wallet(pionex); - address[] wallet = [pionex, user, coordinator, address(mockERC1271Wallet)]; + MockERC1271Wallet mockERC1271Wallet = new MockERC1271Wallet(dealer); + address[] wallet = [dealer, user, coordinator, address(mockERC1271Wallet)]; address[] allowanceAddrs; address[] DEFAULT_AMM_PATH; @@ -55,7 +55,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams DEFAULT_TRADER_PARAMS; IPionexContract.CoordinatorParams DEFAULT_CRD_PARAMS; - PionexContract pionexContract; + PionexContract dealerContract; uint64 DEADLINE = uint64(block.timestamp + 2 days); uint256 FACTORSDEALY = 12 hours; @@ -70,40 +70,40 @@ contract PionexContractTest is StrategySharedSetup { // Default params DEFAULT_ORDER = PionexContractLibEIP712.Order( dai, // userToken - usdt, // pionexToken + usdt, // dealerToken 100 * 1e18, // userTokenAmount - 90 * 1e6, // minPionexTokenAmount + 90 * 1e6, // minDealerTokenAmount user, // user - address(0), // pionex + address(0), // dealer uint256(1001), // salt DEADLINE // expiry ); - DEFAULT_ORDER_HASH = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); + DEFAULT_ORDER_HASH = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); DEFAULT_ORDER_MAKER_SIG = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); DEFAULT_FILL = PionexContractLibEIP712.Fill( DEFAULT_ORDER_HASH, - pionex, + dealer, receiver, DEFAULT_ORDER.userTokenAmount, - DEFAULT_ORDER.minPionexTokenAmount, + DEFAULT_ORDER.minDealerTokenAmount, uint256(1002), DEADLINE ); DEFAULT_TRADER_PARAMS = IPionexContract.TraderParams( - pionex, // pionex + dealer, // dealer receiver, // recipient DEFAULT_FILL.userTokenAmount, // userTokenAmount - DEFAULT_FILL.pionexTokenAmount, // pionexTokenAmount + DEFAULT_FILL.dealerTokenAmount, // dealerTokenAmount DEFAULT_GAS_FEE_FACTOR, // gas fee factor - DEFAULT_PIONEX_STRATEGY_FEE_FACTOR, // pionex strategy fee factor - DEFAULT_FILL.pionexSalt, // salt + DEFAULT_PIONEX_STRATEGY_FEE_FACTOR, // dealer strategy fee factor + DEFAULT_FILL.dealerSalt, // salt DEADLINE, // expiry - _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // pionexSig + _signFill(dealerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // dealerSig ); DEFAULT_ALLOW_FILL = PionexContractLibEIP712.AllowFill( DEFAULT_ORDER_HASH, // orderHash - pionex, // executor - DEFAULT_FILL.pionexTokenAmount, // fillAmount + dealer, // executor + DEFAULT_FILL.dealerTokenAmount, // fillAmount uint256(1003), // salt DEADLINE // expiry ); @@ -117,23 +117,23 @@ contract PionexContractTest is StrategySharedSetup { dealWallet(wallet, 100 ether); // Set token balance and approve tokens = [weth, usdt, dai]; - setEOABalanceAndApprove(pionex, tokens, 10000); + setEOABalanceAndApprove(dealer, tokens, 10000); setEOABalanceAndApprove(user, tokens, 10000); setEOABalanceAndApprove(address(mockERC1271Wallet), tokens, 10000); // Label addresses for easier debugging - vm.label(pionex, "Pionex"); + vm.label(dealer, "Pionex"); vm.label(user, "User"); vm.label(coordinator, "Coordinator"); vm.label(receiver, "Receiver"); vm.label(feeCollector, "FeeCollector"); vm.label(address(this), "TestingContract"); - vm.label(address(pionexContract), "LimitOrderContract"); + vm.label(address(dealerContract), "LimitOrderContract"); vm.label(address(mockERC1271Wallet), "MockERC1271Wallet"); } function _deployStrategyAndUpgrade() internal override returns (address) { - pionexContract = new PionexContract( + dealerContract = new PionexContract( owner, address(userProxy), address(weth), @@ -145,23 +145,23 @@ contract PionexContractTest is StrategySharedSetup { ); // Setup vm.startPrank(tokenlonOperator, tokenlonOperator); - userProxy.upgradeLimitOrder(address(pionexContract), true); - permanentStorage.upgradeLimitOrder(address(pionexContract)); - permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(pionexContract), true); - permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(pionexContract), true); + userProxy.upgradeLimitOrder(address(dealerContract), true); + permanentStorage.upgradeLimitOrder(address(dealerContract)); + permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(dealerContract), true); + permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(dealerContract), true); vm.stopPrank(); - return address(pionexContract); + return address(dealerContract); } function _setupDeployedStrategy() internal override { - pionexContract = PionexContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); + dealerContract = PionexContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); // prank owner and update coordinator address - owner = pionexContract.owner(); + owner = dealerContract.owner(); vm.prank(owner, owner); - pionexContract.upgradeCoordinator(coordinator); + dealerContract.upgradeCoordinator(coordinator); // update local feeCollector address - feeCollector = pionexContract.feeCollector(); + feeCollector = dealerContract.feeCollector(); } /********************************* @@ -169,14 +169,14 @@ contract PionexContractTest is StrategySharedSetup { *********************************/ function testSetupLimitOrder() public { - assertEq(pionexContract.owner(), owner); - assertEq(pionexContract.coordinator(), coordinator); - assertEq(pionexContract.userProxy(), address(userProxy)); - assertEq(address(pionexContract.spender()), address(spender)); - assertEq(address(pionexContract.permStorage()), address(permanentStorage)); - assertEq(address(pionexContract.weth()), address(weth)); + assertEq(dealerContract.owner(), owner); + assertEq(dealerContract.coordinator(), coordinator); + assertEq(dealerContract.userProxy(), address(userProxy)); + assertEq(address(dealerContract.spender()), address(spender)); + assertEq(address(dealerContract.permStorage()), address(permanentStorage)); + assertEq(address(dealerContract.weth()), address(weth)); - assertEq(uint256(pionexContract.tokenlonFeeFactor()), 0); + assertEq(uint256(dealerContract.tokenlonFeeFactor()), 0); } /********************************* @@ -185,22 +185,22 @@ contract PionexContractTest is StrategySharedSetup { function testCannotTransferOwnershipByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.nominateNewOwner(pionex); + vm.prank(dealer); + dealerContract.nominateNewOwner(dealer); } function testCannotAcceptOwnershipIfNotNominated() public { vm.expectRevert("not nominated"); - vm.prank(pionex); - pionexContract.acceptOwnership(); + vm.prank(dealer); + dealerContract.acceptOwnership(); } function testTransferOwnership() public { vm.prank(owner, owner); - pionexContract.nominateNewOwner(pionex); - vm.prank(pionex); - pionexContract.acceptOwnership(); - assertEq(pionexContract.owner(), pionex); + dealerContract.nominateNewOwner(dealer); + vm.prank(dealer); + dealerContract.acceptOwnership(); + assertEq(dealerContract.owner(), dealer); } /********************************* @@ -209,20 +209,20 @@ contract PionexContractTest is StrategySharedSetup { function testCannotUpgradeSpenderByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.upgradeSpender(pionex); + vm.prank(dealer); + dealerContract.upgradeSpender(dealer); } function testCannotUpgradeSpenderToZeroAddr() public { vm.expectRevert("Strategy: spender can not be zero address"); vm.prank(owner, owner); - pionexContract.upgradeSpender(address(0)); + dealerContract.upgradeSpender(address(0)); } function testUpgradeSpender() public { vm.prank(owner, owner); - pionexContract.upgradeSpender(pionex); - assertEq(address(pionexContract.spender()), pionex); + dealerContract.upgradeSpender(dealer); + assertEq(address(dealerContract.spender()), dealer); } /********************************* @@ -231,20 +231,20 @@ contract PionexContractTest is StrategySharedSetup { function testCannotUpgradeCoordinatorByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.upgradeCoordinator(pionex); + vm.prank(dealer); + dealerContract.upgradeCoordinator(dealer); } function testCannotUpgradeCoordinatorToZeroAddr() public { vm.expectRevert("PionexContract: coordinator can not be zero address"); vm.prank(owner, owner); - pionexContract.upgradeCoordinator(address(0)); + dealerContract.upgradeCoordinator(address(0)); } function testUpgradeCoordinator() public { vm.prank(owner, owner); - pionexContract.upgradeCoordinator(pionex); - assertEq(address(pionexContract.coordinator()), pionex); + dealerContract.upgradeCoordinator(dealer); + assertEq(address(dealerContract.coordinator()), dealer); } /********************************* @@ -253,28 +253,28 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetAllowanceByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + vm.prank(dealer); + dealerContract.setAllowance(allowanceAddrs, address(allowanceTarget)); } function testCannotCloseAllowanceByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + vm.prank(dealer); + dealerContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); } function testSetAndCloseAllowance() public { // Set allowance vm.prank(owner, owner); - pionexContract.setAllowance(allowanceAddrs, address(allowanceTarget)); - assertEq(usdt.allowance(address(pionexContract), address(allowanceTarget)), LibConstant.MAX_UINT); - assertEq(dai.allowance(address(pionexContract), address(allowanceTarget)), LibConstant.MAX_UINT); + dealerContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + assertEq(usdt.allowance(address(dealerContract), address(allowanceTarget)), LibConstant.MAX_UINT); + assertEq(dai.allowance(address(dealerContract), address(allowanceTarget)), LibConstant.MAX_UINT); // Close allowance vm.prank(owner, owner); - pionexContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); - assertEq(usdt.allowance(address(pionexContract), address(allowanceTarget)), 0); - assertEq(dai.allowance(address(pionexContract), address(allowanceTarget)), 0); + dealerContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + assertEq(usdt.allowance(address(dealerContract), address(allowanceTarget)), 0); + assertEq(dai.allowance(address(dealerContract), address(allowanceTarget)), 0); } /********************************* @@ -283,17 +283,17 @@ contract PionexContractTest is StrategySharedSetup { function testCannotDepositETHByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.depositETH(); + vm.prank(dealer); + dealerContract.depositETH(); } function testDepositETH() public { // Send ether to limit order contract uint256 amount = 1234 ether; - deal(address(pionexContract), amount); + deal(address(dealerContract), amount); vm.prank(owner, owner); - pionexContract.depositETH(); - assertEq(weth.balanceOf(address(pionexContract)), amount); + dealerContract.depositETH(); + assertEq(weth.balanceOf(address(dealerContract)), amount); } /********************************* @@ -303,20 +303,20 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetFactorsIfLargerThanBpsMax() public { vm.expectRevert("PionexContract: Invalid user fee factor"); vm.prank(owner, owner); - pionexContract.setFactors(LibConstant.BPS_MAX + 1); + dealerContract.setFactors(LibConstant.BPS_MAX + 1); } function testSetFactors() public { vm.startPrank(owner, owner); - pionexContract.setFactors(1); + dealerContract.setFactors(1); // fee factors should stay same before new ones activate - assertEq(uint256(pionexContract.tokenlonFeeFactor()), 0); - vm.warp(block.timestamp + pionexContract.factorActivateDelay()); + assertEq(uint256(dealerContract.tokenlonFeeFactor()), 0); + vm.warp(block.timestamp + dealerContract.factorActivateDelay()); // fee factors should be updated now - pionexContract.activateFactors(); + dealerContract.activateFactors(); vm.stopPrank(); - assertEq(uint256(pionexContract.tokenlonFeeFactor()), 1); + assertEq(uint256(dealerContract.tokenlonFeeFactor()), 1); } /********************************* @@ -325,20 +325,20 @@ contract PionexContractTest is StrategySharedSetup { function testCannotSetFeeCollectorByNotOwner() public { vm.expectRevert("not owner"); - vm.prank(pionex); - pionexContract.setFeeCollector(feeCollector); + vm.prank(dealer); + dealerContract.setFeeCollector(feeCollector); } function testCannotSetFeeCollectorToZeroAddr() public { vm.expectRevert("PionexContract: fee collector can not be zero address"); vm.prank(owner, owner); - pionexContract.setFeeCollector(address(0)); + dealerContract.setFeeCollector(address(0)); } function testSetFeeCollector() public { vm.prank(owner, owner); - pionexContract.setFeeCollector(pionex); - assertEq(address(pionexContract.feeCollector()), pionex); + dealerContract.setFeeCollector(dealer); + assertEq(address(dealerContract.feeCollector()), dealer); } /********************************* @@ -348,22 +348,22 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillByTraderIfNotFromUserProxy() public { vm.expectRevert("Strategy: not from UserProxy contract"); // Call limit order contract directly will get reverted since msg.sender is not from UserProxy - pionexContract.fillLimitOrder(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + dealerContract.fillLimitOrder(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); } function testCannotFillFilledOrderByTrader() public { // Fullly fill the default order first bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload1); // Try to fill the default order, should fail PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.pionexSalt = uint256(8001); + fill.dealerSalt = uint256(8001); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - traderParams.salt = fill.pionexSalt; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.salt = fill.dealerSalt; PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.salt = uint256(8002); @@ -374,7 +374,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectRevert("PionexContract: Order is filled"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload2); } @@ -382,14 +382,14 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; order.expiry = uint64(block.timestamp - 1); - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -399,42 +399,42 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); vm.expectRevert("PionexContract: Order is expired"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWrongMakerSig() public { - bytes memory wrongMakerSig = _signOrder(pionexPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); + bytes memory wrongMakerSig = _signOrder(dealerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectRevert("PionexContract: Order is not signed by user"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWrongTakerSig() public { IPionexContract.TraderParams memory wrongTraderParams = DEFAULT_TRADER_PARAMS; - wrongTraderParams.pionexSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + wrongTraderParams.dealerSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Fill is not signed by pionex"); - vm.prank(pionex, pionex); // Only EOA + vm.expectRevert("PionexContract: Fill is not signed by dealer"); + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithTakerOtherThanOrderSpecified() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify pionex address - order.pionex = coordinator; - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + // order specify dealer address + order.dealer = coordinator; + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - // pionex try to fill this order - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + // dealer try to fill this order + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -443,8 +443,8 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.expectRevert("PionexContract: Order cannot be filled by this pionex"); - vm.prank(pionex, pionex); // Only EOA + vm.expectRevert("PionexContract: Order cannot be filled by this dealer"); + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -453,19 +453,19 @@ contract PionexContractTest is StrategySharedSetup { fill.expiry = uint64(block.timestamp - 1); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.expiry = fill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("PionexContract: Fill request is expired"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotReplayFill() public { // Fill with DEFAULT_FILL bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload1); // Try to fill with same fill request with differnt allowFill (otherwise will revert by dup allowFill) @@ -478,24 +478,24 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PermanentStorage: transaction seen before"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload2); } function testCannotFillByTraderWithAlteredTakerTokenAmount() public { - // Replace pionexTokenAmount in traderParams without corresponded signature + // Replace dealerTokenAmount in traderParams without corresponded signature IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexTokenAmount = DEFAULT_TRADER_PARAMS.pionexTokenAmount.mul(2); + traderParams.dealerTokenAmount = DEFAULT_TRADER_PARAMS.dealerTokenAmount.mul(2); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = traderParams.pionexTokenAmount; + allowFill.fillAmount = traderParams.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.expectRevert("PionexContract: Fill is not signed by pionex"); - vm.prank(pionex, pionex); // Only EOA + vm.expectRevert("PionexContract: Fill is not signed by dealer"); + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -504,8 +504,8 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = coordinator; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Fill is not signed by pionex"); - vm.prank(pionex, pionex); // Only EOA + vm.expectRevert("PionexContract: Fill is not signed by dealer"); + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -519,7 +519,7 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PionexContract: Fill permission is expired"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -533,22 +533,22 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAlteredExecutor() public { - // Set the executor to user (not pionex) + // Set the executor to user (not dealer) PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = user; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - // Fill order using pionex (not executor) + // Fill order using dealer (not executor) bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -562,36 +562,36 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAllowFillNotSignedByCoordinator() public { IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; - // Sign allow fill using pionex's private key - crdParams.sig = _signAllowFill(pionexPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); + // Sign allow fill using dealer's private key + crdParams.sig = _signAllowFill(dealerPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithReplayedAllowFill() public { // Fill with default allow fill bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload1); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.pionexSalt = uint256(8001); + fill.dealerSalt = uint256(8001); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("PermanentStorage: allow fill seen before"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload2); } @@ -601,100 +601,100 @@ contract PionexContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("PionexContract: recipient can not be zero address"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWorseTakerMakerTokenRatio() public { PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - // Increase user token amount so the pionexToken/userToken ratio is worse than order's pionexToken/userToken ratio + // Increase user token amount so the dealerToken/userToken ratio is worse than order's dealerToken/userToken ratio fill.userTokenAmount = DEFAULT_FILL.userTokenAmount.add(1); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: pionex token amount not enough"); - vm.prank(pionex, pionex); // Only EOA + vm.expectRevert("PionexContract: dealer token amount not enough"); + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFullyFillByTraderWithWorseTakerTokenAmountDueToFee() public { IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% - traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% - traderParams.pionexSig = _signFill(pionexPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); + traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5% + traderParams.dealerSig = _signFill(dealerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: pionex token amount not enough"); - vm.prank(pionex, pionex); // Only EOA + vm.expectRevert("PionexContract: dealer token amount not enough"); + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testFullyFillByTraderWithNoFee() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectEmit(true, true, true, true); emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, - pionex, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + dealer, + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), DEFAULT_TRADER_PARAMS.recipient, IPionexContract.FillReceipt( address(DEFAULT_ORDER.userToken), - address(DEFAULT_ORDER.pionexToken), + address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, - DEFAULT_ORDER.minPionexTokenAmount, + DEFAULT_ORDER.minDealerTokenAmount, 0, // remainingUserTokenAmount should be zero after order fully filled 0, // tokenlonFee = 0 - 0 // pionexStrategyFee = 0 + 0 // dealerStrategyFee = 0 ) ); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount)); + dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minDealerTokenAmount)); userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(0); } function testFullyFillByTraderWithAddedTokenlonFee() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); // tokenlonFeeFactor : 10% vm.startPrank(owner, owner); - pionexContract.setFactors(1000); - vm.warp(block.timestamp + pionexContract.factorActivateDelay()); - pionexContract.activateFactors(); + dealerContract.setFactors(1000); + vm.warp(block.timestamp + dealerContract.factorActivateDelay()); + dealerContract.activateFactors(); vm.stopPrank(); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - // Increase pionex token amount so the pionexToken/userToken ratio is better than order's pionexToken/userToken ratio + // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for tokenlon fee - fill.pionexTokenAmount = DEFAULT_FILL.pionexTokenAmount.mul(115).div(100); // 15% more + fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(115).div(100); // 15% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexTokenAmount = fill.pionexTokenAmount; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = traderParams.pionexTokenAmount; + allowFill.fillAmount = traderParams.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -704,51 +704,51 @@ contract PionexContractTest is StrategySharedSetup { emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, - pionex, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + dealer, + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, IPionexContract.FillReceipt( address(DEFAULT_ORDER.userToken), - address(DEFAULT_ORDER.pionexToken), + address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, - traderParams.pionexTokenAmount, + traderParams.dealerTokenAmount, 0, // remainingUserTokenAmount should be zero after order fully filled - traderParams.pionexTokenAmount.div(10), // tokenlonFee = 10% pionexTokenAmount - 0 // pionexStrategyFee = 0 + traderParams.dealerTokenAmount.div(10), // tokenlonFee = 10% dealerTokenAmount + 0 // dealerStrategyFee = 0 ) ); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(traderParams.pionexTokenAmount)); + dealerTakerAsset.assertChange(-int256(traderParams.dealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(traderParams.pionexTokenAmount.mul(9).div(10))); // 10% fee for Tokenlon + userTakerAsset.assertChange(int256(traderParams.dealerTokenAmount.mul(9).div(10))); // 10% fee for Tokenlon userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); - fcTakerAsset.assertChange(int256(traderParams.pionexTokenAmount.div(10))); + fcTakerAsset.assertChange(int256(traderParams.dealerTokenAmount.div(10))); } function testFullyFillByTraderWithAddedGasFeeAndStrategyFee() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - // Increase pionex token amount so the pionexToken/userToken ratio is better than order's pionexToken/userToken ratio - // to account for gas fee and pionex strategy fee - fill.pionexTokenAmount = DEFAULT_FILL.pionexTokenAmount.mul(11).div(10); // 10% more + // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio + // to account for gas fee and dealer strategy fee + fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% - traderParams.pionexStrategyFeeFactor = 250; // pionexStrategyFeeFactor: 2.5% - traderParams.pionexTokenAmount = fill.pionexTokenAmount; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5% + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = traderParams.pionexTokenAmount; + allowFill.fillAmount = traderParams.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -758,48 +758,48 @@ contract PionexContractTest is StrategySharedSetup { emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, - pionex, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + dealer, + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, IPionexContract.FillReceipt( address(DEFAULT_ORDER.userToken), - address(DEFAULT_ORDER.pionexToken), + address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, - traderParams.pionexTokenAmount, + traderParams.dealerTokenAmount, 0, // remainingUserTokenAmount should be zero after order fully filled 0, // tokenlonFee = 0 - traderParams.pionexTokenAmount.mul(3).div(100) // pionexStrategyFee = 0.5% + 2.5% = 3% pionexTokenAmount + traderParams.dealerTokenAmount.mul(3).div(100) // dealerStrategyFee = 0.5% + 2.5% = 3% dealerTokenAmount ) ); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(traderParams.pionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from pionexTokenAmount directly + dealerTakerAsset.assertChange(-int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from dealerTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(traderParams.pionexTokenAmount.mul(97).div(100))); // 3% fee for Pionex + userTakerAsset.assertChange(int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for Pionex userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(0); } function testFullyFillByTraderWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - // Increase pionex token amount so the pionexToken/userToken ratio is better than order's pionexToken/userToken ratio - fill.pionexTokenAmount = DEFAULT_FILL.pionexTokenAmount.mul(11).div(10); // 10% more + // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio + fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexTokenAmount = fill.pionexTokenAmount; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = traderParams.pionexTokenAmount; + allowFill.fillAmount = traderParams.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); @@ -809,38 +809,38 @@ contract PionexContractTest is StrategySharedSetup { emit LimitOrderFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, - pionex, - getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + dealer, + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), traderParams.recipient, IPionexContract.FillReceipt( address(DEFAULT_ORDER.userToken), - address(DEFAULT_ORDER.pionexToken), + address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, - fill.pionexTokenAmount, + fill.dealerTokenAmount, 0, // remainingUserTokenAmount should be zero after order fully filled 0, 0 ) ); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); - pionexTakerAsset.assertChange(-int256(fill.pionexTokenAmount)); + dealerTakerAsset.assertChange(-int256(fill.dealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(fill.pionexTokenAmount)); // 10% more + userTakerAsset.assertChange(int256(fill.dealerTokenAmount)); // 10% more userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(0); } function testFullyFillByContractWalletTrader() public { - // Contract mockERC1271Wallet as pionex which always return valid ERC-1271 magic value no matter what. + // Contract mockERC1271Wallet as dealer which always return valid ERC-1271 magic value no matter what. PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.pionex = address(mockERC1271Wallet); + fill.dealer = address(mockERC1271Wallet); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionex = address(mockERC1271Wallet); - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); + traderParams.dealer = address(mockERC1271Wallet); + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = address(mockERC1271Wallet); @@ -849,22 +849,22 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testFillBySpecificTaker() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify pionex address - order.pionex = pionex; - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + // order specify dealer address + order.dealer = dealer; + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -873,22 +873,22 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testFillBySpecificTakerWithOldEIP712Method() public { PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; - // order specify pionex address - order.pionex = pionex; - bytes32 orderHash = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + // order specify dealer address + order.dealer = dealer; + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrderWithOldEIP712Method(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.pionexSig = _signFillWithOldEIP712Method(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerSig = _signFillWithOldEIP712Method(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; @@ -897,177 +897,177 @@ contract PionexContractTest is StrategySharedSetup { crdParams.sig = _signAllowFillWithOldEIP712Method(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testOverFillByTrader() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); - fill.pionexTokenAmount = DEFAULT_ORDER.minPionexTokenAmount.mul(2); + fill.dealerTokenAmount = DEFAULT_ORDER.minDealerTokenAmount.mul(2); IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; - traderParams.pionexTokenAmount = fill.pionexTokenAmount; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = fill.pionexTokenAmount; + allowFill.fillAmount = fill.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount)); + dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount)); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minDealerTokenAmount)); userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); } function testOverFillByTraderWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); - fill.pionexTokenAmount = DEFAULT_ORDER.minPionexTokenAmount.mul(2).mul(11).div(10); // 10% more + fill.dealerTokenAmount = DEFAULT_ORDER.minDealerTokenAmount.mul(2).mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; - traderParams.pionexTokenAmount = fill.pionexTokenAmount; - traderParams.pionexSig = _signFill(pionexPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.fillAmount = fill.pionexTokenAmount; + allowFill.fillAmount = fill.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); // Balance change should be bound by order amount (not affected by 2x fill amount) - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount.mul(11).div(10))); // 10% more + dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount.mul(11).div(10))); // 10% more receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.mul(11).div(10))); // 10% more + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minDealerTokenAmount.mul(11).div(10))); // 10% more userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); } function testFillByTraderMultipleTimes() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); // First fill amount : 9 USDT PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; fill1.userTokenAmount = 10 * 1e18; - fill1.pionexTokenAmount = 9 * 1e6; + fill1.dealerTokenAmount = 9 * 1e6; IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; traderParams1.userTokenAmount = fill1.userTokenAmount; - traderParams1.pionexTokenAmount = fill1.pionexTokenAmount; - traderParams1.pionexSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + traderParams1.dealerTokenAmount = fill1.dealerTokenAmount; + traderParams1.dealerSig = _signFill(dealerPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; - allowFill1.fillAmount = fill1.pionexTokenAmount; + allowFill1.fillAmount = fill1.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload1); // Second fill amount : 36 USDT PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; fill2.userTokenAmount = 40 * 1e18; - fill2.pionexTokenAmount = 36 * 1e6; + fill2.dealerTokenAmount = 36 * 1e6; IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; traderParams2.userTokenAmount = fill2.userTokenAmount; - traderParams2.pionexTokenAmount = fill2.pionexTokenAmount; - traderParams2.pionexSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + traderParams2.dealerTokenAmount = fill2.dealerTokenAmount; + traderParams2.dealerSig = _signFill(dealerPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; - allowFill2.fillAmount = fill2.pionexTokenAmount; + allowFill2.fillAmount = fill2.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - pionexTakerAsset.assertChange(-int256(DEFAULT_ORDER.minPionexTokenAmount.div(2))); + dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount.div(2))); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount.div(2))); - userTakerAsset.assertChange(int256(DEFAULT_ORDER.minPionexTokenAmount.div(2))); + userTakerAsset.assertChange(int256(DEFAULT_ORDER.minDealerTokenAmount.div(2))); userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2))); } function testFillByTraderMultipleTimesWithBetterTakerMakerTokenRatio() public { - BalanceSnapshot.Snapshot memory pionexTakerAsset = BalanceSnapshot.take(pionex, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory dealerTakerAsset = BalanceSnapshot.take(dealer, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory receiverMakerAsset = BalanceSnapshot.take(receiver, address(DEFAULT_ORDER.userToken)); - BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.pionexToken)); + BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); - // First fill amount : 9 USDT and same pionexToken/userToken ratio + // First fill amount : 9 USDT and same dealerToken/userToken ratio PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; fill1.userTokenAmount = 10 * 1e18; - fill1.pionexTokenAmount = 9 * 1e6; + fill1.dealerTokenAmount = 9 * 1e6; IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; traderParams1.userTokenAmount = fill1.userTokenAmount; - traderParams1.pionexTokenAmount = fill1.pionexTokenAmount; - traderParams1.pionexSig = _signFill(pionexPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); + traderParams1.dealerTokenAmount = fill1.dealerTokenAmount; + traderParams1.dealerSig = _signFill(dealerPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; - allowFill1.fillAmount = fill1.pionexTokenAmount; + allowFill1.fillAmount = fill1.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload1); - // Second fill amount : 36 USDT and better pionexToken/userToken ratio + // Second fill amount : 36 USDT and better dealerToken/userToken ratio PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; fill2.userTokenAmount = 40 * 1e18; - fill2.pionexTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more + fill2.dealerTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; traderParams2.userTokenAmount = fill2.userTokenAmount; - traderParams2.pionexTokenAmount = fill2.pionexTokenAmount; - traderParams2.pionexSig = _signFill(pionexPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); + traderParams2.dealerTokenAmount = fill2.dealerTokenAmount; + traderParams2.dealerSig = _signFill(dealerPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; - allowFill2.fillAmount = fill2.pionexTokenAmount; + allowFill2.fillAmount = fill2.dealerTokenAmount; IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload2); // Half of the order filled after 2 txs - pionexTakerAsset.assertChange(-int256(fill1.pionexTokenAmount.add(fill2.pionexTokenAmount))); + dealerTakerAsset.assertChange(-int256(fill1.dealerTokenAmount.add(fill2.dealerTokenAmount))); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount.div(2))); - userTakerAsset.assertChange(int256(fill1.pionexTokenAmount.add(fill2.pionexTokenAmount))); + userTakerAsset.assertChange(int256(fill1.dealerTokenAmount.add(fill2.dealerTokenAmount))); userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2))); } @@ -1077,28 +1077,28 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillCanceledOrder() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.minPionexTokenAmount = 0; + zeroOrder.minDealerTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(cancelPayload); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectRevert("PionexContract: Order is cancelled"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotCancelIfNotMaker() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.minPionexTokenAmount = 0; + zeroOrder.minDealerTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload( DEFAULT_ORDER, - _signOrder(pionexPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) + _signOrder(dealerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) ); vm.expectRevert("PionexContract: Cancel request is not signed by user"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(cancelPayload); } @@ -1106,21 +1106,21 @@ contract PionexContractTest is StrategySharedSetup { PionexContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; expiredOrder.expiry = 0; - bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(pionexPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(dealerPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); vm.expectRevert("PionexContract: Order is expired"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotCancelTwice() public { PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; - zeroOrder.minPionexTokenAmount = 0; + zeroOrder.minDealerTokenAmount = 0; bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); vm.expectRevert("PionexContract: Order is cancelled already"); - vm.prank(pionex, pionex); // Only EOA + vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -1167,7 +1167,7 @@ contract PionexContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); - bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), orderHash); + bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), orderHash); if (sigType == SignatureValidator.SignatureType.EIP712) { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1186,7 +1186,7 @@ contract PionexContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); - bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), orderHash); + bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), orderHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); @@ -1198,7 +1198,7 @@ contract PionexContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); - bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), fillHash); + bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), fillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); } @@ -1209,7 +1209,7 @@ contract PionexContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); - bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), fillHash); + bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), fillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); @@ -1221,7 +1221,7 @@ contract PionexContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); - bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); + bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); } @@ -1232,7 +1232,7 @@ contract PionexContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); - bytes32 EIP712SignDigest = getEIP712Hash(pionexContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); + bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); @@ -1244,7 +1244,7 @@ contract PionexContractTest is StrategySharedSetup { IPionexContract.TraderParams memory params, IPionexContract.CoordinatorParams memory crdParams ) internal view returns (bytes memory payload) { - return abi.encodeWithSelector(pionexContract.fillLimitOrder.selector, order, orderMakerSig, params, crdParams); + return abi.encodeWithSelector(dealerContract.fillLimitOrder.selector, order, orderMakerSig, params, crdParams); } function _genCancelLimitOrderPayload(PionexContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) @@ -1252,6 +1252,6 @@ contract PionexContractTest is StrategySharedSetup { view returns (bytes memory payload) { - return abi.encodeWithSelector(pionexContract.cancelLimitOrder.selector, order, cancelOrderMakerSig); + return abi.encodeWithSelector(dealerContract.cancelLimitOrder.selector, order, cancelOrderMakerSig); } } From 8bb9f0f35debb335b881a5d001b7c9321840060e Mon Sep 17 00:00:00 2001 From: NIC619 Date: Mon, 12 Jun 2023 19:26:03 +0800 Subject: [PATCH 30/41] Rename Pionex -> SignalBuy --- ...onexContract.sol => SignalBuyContract.sol} | 104 +++--- ...nexContract.sol => ISignalBuyContract.sol} | 10 +- ...l => LibSignalBuyContractOrderStorage.sol} | 6 +- ...712.sol => SignalBuyContractLibEIP712.sol} | 4 +- ...Contract.t.sol => SignalBuyContract.t.sol} | 342 +++++++++--------- 5 files changed, 237 insertions(+), 229 deletions(-) rename contracts/{PionexContract.sol => SignalBuyContract.sol} (73%) rename contracts/interfaces/{IPionexContract.sol => ISignalBuyContract.sol} (90%) rename contracts/utils/{LibPionexContractOrderStorage.sol => LibSignalBuyContractOrderStorage.sol} (75%) rename contracts/utils/{PionexContractLibEIP712.sol => SignalBuyContractLibEIP712.sol} (97%) rename test/forkMainnet/{PionexContract.t.sol => SignalBuyContract.t.sol} (80%) diff --git a/contracts/PionexContract.sol b/contracts/SignalBuyContract.sol similarity index 73% rename from contracts/PionexContract.sol rename to contracts/SignalBuyContract.sol index d32a420d..85576efa 100644 --- a/contracts/PionexContract.sol +++ b/contracts/SignalBuyContract.sol @@ -8,21 +8,21 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; -import "./interfaces/IPionexContract.sol"; +import "./interfaces/ISignalBuyContract.sol"; import "./interfaces/IPermanentStorage.sol"; import "./interfaces/ISpender.sol"; import "./interfaces/IWeth.sol"; import "./utils/StrategyBase.sol"; import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; -import "./utils/LibPionexContractOrderStorage.sol"; -import "./utils/PionexContractLibEIP712.sol"; +import "./utils/LibSignalBuyContractOrderStorage.sol"; +import "./utils/SignalBuyContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; -/// @title Pionex Contract +/// @title SignalBuy Contract /// @notice Order can be filled as long as the provided dealerToken/userToken ratio is better than or equal to user's specfied dealerToken/userToken ratio. /// @author imToken Labs -contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { +contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for IERC20; @@ -57,7 +57,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _newCoordinator The new address of coordinator function upgradeCoordinator(address _newCoordinator) external onlyOwner { - require(_newCoordinator != address(0), "PionexContract: coordinator can not be zero address"); + require(_newCoordinator != address(0), "SignalBuyContract: coordinator can not be zero address"); coordinator = _newCoordinator; emit UpgradeCoordinator(_newCoordinator); @@ -66,7 +66,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _tokenlonFeeFactor The new fee factor for user function setFactors(uint16 _tokenlonFeeFactor) external onlyOwner { - require(_tokenlonFeeFactor <= LibConstant.BPS_MAX, "PionexContract: Invalid user fee factor"); + require(_tokenlonFeeFactor <= LibConstant.BPS_MAX, "SignalBuyContract: Invalid user fee factor"); pendingTokenlonFeeFactor = _tokenlonFeeFactor; @@ -75,8 +75,8 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call function activateFactors() external onlyOwner { - require(factorsTimeLock != 0, "PionexContract: no pending fee factors"); - require(block.timestamp >= factorsTimeLock, "PionexContract: fee factors timelocked"); + require(factorsTimeLock != 0, "SignalBuyContract: no pending fee factors"); + require(block.timestamp >= factorsTimeLock, "SignalBuyContract: fee factors timelocked"); factorsTimeLock = 0; tokenlonFeeFactor = pendingTokenlonFeeFactor; pendingTokenlonFeeFactor = 0; @@ -87,20 +87,20 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu /// @notice Only owner can call /// @param _newFeeCollector The new address of fee collector function setFeeCollector(address _newFeeCollector) external onlyOwner { - require(_newFeeCollector != address(0), "PionexContract: fee collector can not be zero address"); + require(_newFeeCollector != address(0), "SignalBuyContract: fee collector can not be zero address"); feeCollector = _newFeeCollector; emit SetFeeCollector(_newFeeCollector); } - /// @inheritdoc IPionexContract + /// @inheritdoc ISignalBuyContract function fillLimitOrder( - PionexContractLibEIP712.Order calldata _order, + SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams ) external override onlyUserProxy nonReentrant returns (uint256, uint256) { - bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); + bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); _validateOrder(_order, orderHash, _orderUserSig); bytes32 allowFillHash = _validateFillPermission(orderHash, _params.dealerTokenAmount, _params.dealer, _crdParams); @@ -111,11 +111,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu (_params.gasFeeFactor <= LibConstant.BPS_MAX) && (_params.dealerStrategyFeeFactor <= LibConstant.BPS_MAX) && (_params.gasFeeFactor + _params.dealerStrategyFeeFactor <= LibConstant.BPS_MAX - tokenlonFeeFactor), - "PionexContract: Invalid dealer fee factor" + "SignalBuyContract: Invalid dealer fee factor" ); { - PionexContractLibEIP712.Fill memory fill = PionexContractLibEIP712.Fill({ + SignalBuyContractLibEIP712.Fill memory fill = SignalBuyContractLibEIP712.Fill({ orderHash: orderHash, dealer: _params.dealer, recipient: _params.recipient, @@ -156,12 +156,12 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu return (dealerTokenAmount, userTokenAmount); } - function _validateTraderFill(PionexContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { - require(_fill.expiry > uint64(block.timestamp), "PionexContract: Fill request is expired"); - require(_fill.recipient != address(0), "PionexContract: recipient can not be zero address"); + function _validateTraderFill(SignalBuyContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { + require(_fill.expiry > uint64(block.timestamp), "SignalBuyContract: Fill request is expired"); + require(_fill.recipient != address(0), "SignalBuyContract: recipient can not be zero address"); - bytes32 fillHash = getEIP712Hash(PionexContractLibEIP712._getFillStructHash(_fill)); - require(isValidSignature(_fill.dealer, fillHash, bytes(""), _fillTakerSig), "PionexContract: Fill is not signed by dealer"); + bytes32 fillHash = getEIP712Hash(SignalBuyContractLibEIP712._getFillStructHash(_fill)); + require(isValidSignature(_fill.dealer, fillHash, bytes(""), _fillTakerSig), "SignalBuyContract: Fill is not signed by dealer"); // Set fill seen to avoid replay attack. // PermanentStorage would throw error if fill is already seen. @@ -174,11 +174,11 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu address _executor, CoordinatorParams memory _crdParams ) internal returns (bytes32) { - require(_crdParams.expiry > uint64(block.timestamp), "PionexContract: Fill permission is expired"); + require(_crdParams.expiry > uint64(block.timestamp), "SignalBuyContract: Fill permission is expired"); bytes32 allowFillHash = getEIP712Hash( - PionexContractLibEIP712._getAllowFillStructHash( - PionexContractLibEIP712.AllowFill({ + SignalBuyContractLibEIP712._getAllowFillStructHash( + SignalBuyContractLibEIP712.AllowFill({ orderHash: _orderHash, executor: _executor, fillAmount: _fillAmount, @@ -187,7 +187,7 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu }) ) ); - require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "PionexContract: AllowFill is not signed by coordinator"); + require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "SignalBuyContract: AllowFill is not signed by coordinator"); // Set allow fill seen to avoid replay attack // PermanentStorage would throw error if allow fill is already seen. @@ -220,10 +220,10 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu // Calculate user fee (user receives dealer token so fee is charged in dealer token) // 1. Fee for Tokenlon uint256 tokenlonFee = _mulFactor(_settlement.dealerTokenAmount, tokenlonFeeFactor); - // 2. Fee for Pionex, including gas fee and strategy fee + // 2. Fee for SignalBuy, including gas fee and strategy fee uint256 dealerFee = _mulFactor(_settlement.dealerTokenAmount, _settlement.gasFeeFactor + _settlement.dealerStrategyFeeFactor); uint256 dealerTokenForUser = _settlement.dealerTokenAmount.sub(tokenlonFee).sub(dealerFee); - require(dealerTokenForUser >= _settlement.minDealerTokenAmount, "PionexContract: dealer token amount not enough"); + require(dealerTokenForUser >= _settlement.minDealerTokenAmount, "SignalBuyContract: dealer token amount not enough"); // trader -> user _spender.spendFromUserTo(_settlement.trader, address(_settlement.dealerToken), _settlement.user, dealerTokenForUser); @@ -255,64 +255,72 @@ contract PionexContract is IPionexContract, StrategyBase, BaseLibEIP712, Signatu ); } - /// @inheritdoc IPionexContract - function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) external override onlyUserProxy nonReentrant { - require(_order.expiry > uint64(block.timestamp), "PionexContract: Order is expired"); - bytes32 orderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(_order)); - bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; - require(!isCancelled, "PionexContract: Order is cancelled already"); + /// @inheritdoc ISignalBuyContract + function cancelLimitOrder(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) + external + override + onlyUserProxy + nonReentrant + { + require(_order.expiry > uint64(block.timestamp), "SignalBuyContract: Order is expired"); + bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); + bool isCancelled = LibSignalBuyContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; + require(!isCancelled, "SignalBuyContract: Order is cancelled already"); { - PionexContractLibEIP712.Order memory cancelledOrder = _order; + SignalBuyContractLibEIP712.Order memory cancelledOrder = _order; cancelledOrder.minDealerTokenAmount = 0; - bytes32 cancelledOrderHash = getEIP712Hash(PionexContractLibEIP712._getOrderStructHash(cancelledOrder)); - require(isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderUserSig), "PionexContract: Cancel request is not signed by user"); + bytes32 cancelledOrderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(cancelledOrder)); + require( + isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderUserSig), + "SignalBuyContract: Cancel request is not signed by user" + ); } // Set cancelled state to storage - LibPionexContractOrderStorage.getStorage().orderHashToCancelled[orderHash] = true; + LibSignalBuyContractOrderStorage.getStorage().orderHashToCancelled[orderHash] = true; emit OrderCancelled(orderHash, _order.user); } /* order utils */ function _validateOrder( - PionexContractLibEIP712.Order memory _order, + SignalBuyContractLibEIP712.Order memory _order, bytes32 _orderHash, bytes memory _orderUserSig ) internal view { - require(_order.expiry > uint64(block.timestamp), "PionexContract: Order is expired"); - bool isCancelled = LibPionexContractOrderStorage.getStorage().orderHashToCancelled[_orderHash]; - require(!isCancelled, "PionexContract: Order is cancelled"); + require(_order.expiry > uint64(block.timestamp), "SignalBuyContract: Order is expired"); + bool isCancelled = LibSignalBuyContractOrderStorage.getStorage().orderHashToCancelled[_orderHash]; + require(!isCancelled, "SignalBuyContract: Order is cancelled"); - require(isValidSignature(_order.user, _orderHash, bytes(""), _orderUserSig), "PionexContract: Order is not signed by user"); + require(isValidSignature(_order.user, _orderHash, bytes(""), _orderUserSig), "SignalBuyContract: Order is not signed by user"); } - function _validateOrderTaker(PionexContractLibEIP712.Order memory _order, address _dealer) internal pure { + function _validateOrderTaker(SignalBuyContractLibEIP712.Order memory _order, address _dealer) internal pure { if (_order.dealer != address(0)) { - require(_order.dealer == _dealer, "PionexContract: Order cannot be filled by this dealer"); + require(_order.dealer == _dealer, "SignalBuyContract: Order cannot be filled by this dealer"); } } function _quoteOrderFromUserToken( - PionexContractLibEIP712.Order memory _order, + SignalBuyContractLibEIP712.Order memory _order, bytes32 _orderHash, uint256 _userTokenAmount ) internal view returns (uint256, uint256) { - uint256 userTokenFilledAmount = LibPionexContractOrderStorage.getStorage().orderHashToUserTokenFilledAmount[_orderHash]; + uint256 userTokenFilledAmount = LibSignalBuyContractOrderStorage.getStorage().orderHashToUserTokenFilledAmount[_orderHash]; - require(userTokenFilledAmount < _order.userTokenAmount, "PionexContract: Order is filled"); + require(userTokenFilledAmount < _order.userTokenAmount, "SignalBuyContract: Order is filled"); uint256 userTokenFillableAmount = _order.userTokenAmount.sub(userTokenFilledAmount); uint256 userTokenQuota = Math.min(_userTokenAmount, userTokenFillableAmount); uint256 remainingAfterFill = userTokenFillableAmount.sub(userTokenQuota); - require(userTokenQuota != 0, "PionexContract: zero token amount"); + require(userTokenQuota != 0, "SignalBuyContract: zero token amount"); return (userTokenQuota, remainingAfterFill); } function _recordUserTokenFilled(bytes32 _orderHash, uint256 _userTokenAmount) internal { - LibPionexContractOrderStorage.Storage storage stor = LibPionexContractOrderStorage.getStorage(); + LibSignalBuyContractOrderStorage.Storage storage stor = LibSignalBuyContractOrderStorage.getStorage(); uint256 userTokenFilledAmount = stor.orderHashToUserTokenFilledAmount[_orderHash]; stor.orderHashToUserTokenFilledAmount[_orderHash] = userTokenFilledAmount.add(_userTokenAmount); } diff --git a/contracts/interfaces/IPionexContract.sol b/contracts/interfaces/ISignalBuyContract.sol similarity index 90% rename from contracts/interfaces/IPionexContract.sol rename to contracts/interfaces/ISignalBuyContract.sol index 37be59ca..03e06982 100644 --- a/contracts/interfaces/IPionexContract.sol +++ b/contracts/interfaces/ISignalBuyContract.sol @@ -5,11 +5,11 @@ pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IStrategyBase.sol"; -import "../utils/PionexContractLibEIP712.sol"; +import "../utils/SignalBuyContractLibEIP712.sol"; -/// @title IPionexContract Interface +/// @title ISignalBuyContract Interface /// @author imToken Labs -interface IPionexContract is IStrategyBase { +interface ISignalBuyContract is IStrategyBase { /// @notice Emitted when coordinator address is updated /// @param newCoordinator The address of the new coordinator event UpgradeCoordinator(address newCoordinator); @@ -78,7 +78,7 @@ interface IPionexContract is IStrategyBase { /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit function fillLimitOrder( - PionexContractLibEIP712.Order calldata _order, + SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams @@ -88,5 +88,5 @@ interface IPionexContract is IStrategyBase { /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled /// @param _cancelUserSig The cancelling signature signed by user - function cancelLimitOrder(PionexContractLibEIP712.Order calldata _order, bytes calldata _cancelUserSig) external; + function cancelLimitOrder(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelUserSig) external; } diff --git a/contracts/utils/LibPionexContractOrderStorage.sol b/contracts/utils/LibSignalBuyContractOrderStorage.sol similarity index 75% rename from contracts/utils/LibPionexContractOrderStorage.sol rename to contracts/utils/LibSignalBuyContractOrderStorage.sol index 8056fbf4..8ee803cd 100644 --- a/contracts/utils/LibPionexContractOrderStorage.sol +++ b/contracts/utils/LibSignalBuyContractOrderStorage.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.7.6; -library LibPionexContractOrderStorage { - bytes32 private constant STORAGE_SLOT = 0x95a5390854dc73a7f7b647527d9be60908d60f6434dd66098c304c2918e6d1a1; +library LibSignalBuyContractOrderStorage { + bytes32 private constant STORAGE_SLOT = 0x1360fb69f36f46eb45cf50ca3a6184b38e4ef3bde9e5aff734dccec027d7b9f7; /// @dev Storage bucket for this feature. struct Storage { // How much maker token has been filled in order. @@ -13,7 +13,7 @@ library LibPionexContractOrderStorage { /// @dev Get the storage bucket for this contract. function getStorage() internal pure returns (Storage storage stor) { - assert(STORAGE_SLOT == bytes32(uint256(keccak256("pionexcontract.order.storage")) - 1)); + assert(STORAGE_SLOT == bytes32(uint256(keccak256("signalbuycontract.order.storage")) - 1)); // Dip into assembly to change the slot pointed to by the local // variable `stor`. diff --git a/contracts/utils/PionexContractLibEIP712.sol b/contracts/utils/SignalBuyContractLibEIP712.sol similarity index 97% rename from contracts/utils/PionexContractLibEIP712.sol rename to contracts/utils/SignalBuyContractLibEIP712.sol index fba91b5f..0746ab84 100644 --- a/contracts/utils/PionexContractLibEIP712.sol +++ b/contracts/utils/SignalBuyContractLibEIP712.sol @@ -3,9 +3,9 @@ pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "../interfaces/IPionexContract.sol"; +import "../interfaces/ISignalBuyContract.sol"; -library PionexContractLibEIP712 { +library SignalBuyContractLibEIP712 { struct Order { IERC20 userToken; IERC20 dealerToken; diff --git a/test/forkMainnet/PionexContract.t.sol b/test/forkMainnet/SignalBuyContract.t.sol similarity index 80% rename from test/forkMainnet/PionexContract.t.sol rename to test/forkMainnet/SignalBuyContract.t.sol index db7b3130..331eab63 100644 --- a/test/forkMainnet/PionexContract.t.sol +++ b/test/forkMainnet/SignalBuyContract.t.sol @@ -6,10 +6,10 @@ import "@openzeppelin/contracts/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; -import "contracts/PionexContract.sol"; -import "contracts/interfaces/IPionexContract.sol"; +import "contracts/SignalBuyContract.sol"; +import "contracts/interfaces/ISignalBuyContract.sol"; import "contracts/utils/SignatureValidator.sol"; -import "contracts/utils/PionexContractLibEIP712.sol"; +import "contracts/utils/SignalBuyContractLibEIP712.sol"; import "contracts/utils/LibConstant.sol"; import "test/mocks/MockERC1271Wallet.sol"; @@ -17,7 +17,7 @@ import "test/utils/BalanceSnapshot.sol"; import "test/utils/StrategySharedSetup.sol"; import { computeMainnetEIP712DomainSeparator, getEIP712Hash } from "test/utils/Sig.sol"; -contract PionexContractTest is StrategySharedSetup { +contract SignalBuyContractTest is StrategySharedSetup { using SafeMath for uint256; using BalanceSnapshot for BalanceSnapshot.Snapshot; @@ -27,7 +27,7 @@ contract PionexContractTest is StrategySharedSetup { address indexed dealer, bytes32 allowFillHash, address recipient, - IPionexContract.FillReceipt fillReceipt + ISignalBuyContract.FillReceipt fillReceipt ); uint256 dealerPrivateKey = uint256(1); @@ -45,17 +45,17 @@ contract PionexContractTest is StrategySharedSetup { address[] allowanceAddrs; address[] DEFAULT_AMM_PATH; - PionexContractLibEIP712.Order DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order DEFAULT_ORDER; bytes32 DEFAULT_ORDER_HASH; bytes DEFAULT_ORDER_MAKER_SIG; - PionexContractLibEIP712.Fill DEFAULT_FILL; - PionexContractLibEIP712.AllowFill DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.Fill DEFAULT_FILL; + SignalBuyContractLibEIP712.AllowFill DEFAULT_ALLOW_FILL; uint16 DEFAULT_GAS_FEE_FACTOR = 0; uint16 DEFAULT_PIONEX_STRATEGY_FEE_FACTOR = 0; - IPionexContract.TraderParams DEFAULT_TRADER_PARAMS; - IPionexContract.CoordinatorParams DEFAULT_CRD_PARAMS; + ISignalBuyContract.TraderParams DEFAULT_TRADER_PARAMS; + ISignalBuyContract.CoordinatorParams DEFAULT_CRD_PARAMS; - PionexContract dealerContract; + SignalBuyContract dealerContract; uint64 DEADLINE = uint64(block.timestamp + 2 days); uint256 FACTORSDEALY = 12 hours; @@ -68,7 +68,7 @@ contract PionexContractTest is StrategySharedSetup { allowanceAddrs = DEFAULT_AMM_PATH; // Default params - DEFAULT_ORDER = PionexContractLibEIP712.Order( + DEFAULT_ORDER = SignalBuyContractLibEIP712.Order( dai, // userToken usdt, // dealerToken 100 * 1e18, // userTokenAmount @@ -78,9 +78,9 @@ contract PionexContractTest is StrategySharedSetup { uint256(1001), // salt DEADLINE // expiry ); - DEFAULT_ORDER_HASH = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); + DEFAULT_ORDER_HASH = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); DEFAULT_ORDER_MAKER_SIG = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); - DEFAULT_FILL = PionexContractLibEIP712.Fill( + DEFAULT_FILL = SignalBuyContractLibEIP712.Fill( DEFAULT_ORDER_HASH, dealer, receiver, @@ -89,7 +89,7 @@ contract PionexContractTest is StrategySharedSetup { uint256(1002), DEADLINE ); - DEFAULT_TRADER_PARAMS = IPionexContract.TraderParams( + DEFAULT_TRADER_PARAMS = ISignalBuyContract.TraderParams( dealer, // dealer receiver, // recipient DEFAULT_FILL.userTokenAmount, // userTokenAmount @@ -100,14 +100,14 @@ contract PionexContractTest is StrategySharedSetup { DEADLINE, // expiry _signFill(dealerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // dealerSig ); - DEFAULT_ALLOW_FILL = PionexContractLibEIP712.AllowFill( + DEFAULT_ALLOW_FILL = SignalBuyContractLibEIP712.AllowFill( DEFAULT_ORDER_HASH, // orderHash dealer, // executor DEFAULT_FILL.dealerTokenAmount, // fillAmount uint256(1003), // salt DEADLINE // expiry ); - DEFAULT_CRD_PARAMS = IPionexContract.CoordinatorParams( + DEFAULT_CRD_PARAMS = ISignalBuyContract.CoordinatorParams( _signAllowFill(coordinatorPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712), DEFAULT_ALLOW_FILL.salt, DEFAULT_ALLOW_FILL.expiry @@ -122,7 +122,7 @@ contract PionexContractTest is StrategySharedSetup { setEOABalanceAndApprove(address(mockERC1271Wallet), tokens, 10000); // Label addresses for easier debugging - vm.label(dealer, "Pionex"); + vm.label(dealer, "SignalBuy"); vm.label(user, "User"); vm.label(coordinator, "Coordinator"); vm.label(receiver, "Receiver"); @@ -133,7 +133,7 @@ contract PionexContractTest is StrategySharedSetup { } function _deployStrategyAndUpgrade() internal override returns (address) { - dealerContract = new PionexContract( + dealerContract = new SignalBuyContract( owner, address(userProxy), address(weth), @@ -154,7 +154,7 @@ contract PionexContractTest is StrategySharedSetup { } function _setupDeployedStrategy() internal override { - dealerContract = PionexContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); + dealerContract = SignalBuyContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); // prank owner and update coordinator address owner = dealerContract.owner(); @@ -236,7 +236,7 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotUpgradeCoordinatorToZeroAddr() public { - vm.expectRevert("PionexContract: coordinator can not be zero address"); + vm.expectRevert("SignalBuyContract: coordinator can not be zero address"); vm.prank(owner, owner); dealerContract.upgradeCoordinator(address(0)); } @@ -301,7 +301,7 @@ contract PionexContractTest is StrategySharedSetup { *********************************/ function testCannotSetFactorsIfLargerThanBpsMax() public { - vm.expectRevert("PionexContract: Invalid user fee factor"); + vm.expectRevert("SignalBuyContract: Invalid user fee factor"); vm.prank(owner, owner); dealerContract.setFactors(LibConstant.BPS_MAX + 1); } @@ -330,7 +330,7 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotSetFeeCollectorToZeroAddr() public { - vm.expectRevert("PionexContract: fee collector can not be zero address"); + vm.expectRevert("SignalBuyContract: fee collector can not be zero address"); vm.prank(owner, owner); dealerContract.setFeeCollector(address(0)); } @@ -358,47 +358,47 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload1); // Try to fill the default order, should fail - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.dealerSalt = uint256(8001); - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.salt = fill.dealerSalt; - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.salt = uint256(8002); - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); crdParams.salt = allowFill.salt; bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.expectRevert("PionexContract: Order is filled"); + vm.expectRevert("SignalBuyContract: Order is filled"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload2); } function testCannotFillExpiredOrderByTrader() public { - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; order.expiry = uint64(block.timestamp - 1); - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.expectRevert("PionexContract: Order is expired"); + vm.expectRevert("SignalBuyContract: Order is expired"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -407,57 +407,57 @@ contract PionexContractTest is StrategySharedSetup { bytes memory wrongMakerSig = _signOrder(dealerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Order is not signed by user"); + vm.expectRevert("SignalBuyContract: Order is not signed by user"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWrongTakerSig() public { - IPionexContract.TraderParams memory wrongTraderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory wrongTraderParams = DEFAULT_TRADER_PARAMS; wrongTraderParams.dealerSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Fill is not signed by dealer"); + vm.expectRevert("SignalBuyContract: Fill is not signed by dealer"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithTakerOtherThanOrderSpecified() public { - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = coordinator; - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; // dealer try to fill this order traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.expectRevert("PionexContract: Order cannot be filled by this dealer"); + vm.expectRevert("SignalBuyContract: Order cannot be filled by this dealer"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithExpiredFill() public { - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.expiry = uint64(block.timestamp - 1); - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.expiry = fill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Fill request is expired"); + vm.expectRevert("SignalBuyContract: Fill request is expired"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -469,10 +469,10 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload1); // Try to fill with same fill request with differnt allowFill (otherwise will revert by dup allowFill) - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.salt = uint256(9001); - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); crdParams.salt = allowFill.salt; @@ -484,95 +484,95 @@ contract PionexContractTest is StrategySharedSetup { function testCannotFillByTraderWithAlteredTakerTokenAmount() public { // Replace dealerTokenAmount in traderParams without corresponded signature - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerTokenAmount = DEFAULT_TRADER_PARAMS.dealerTokenAmount.mul(2); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.expectRevert("PionexContract: Fill is not signed by dealer"); + vm.expectRevert("SignalBuyContract: Fill is not signed by dealer"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAlteredRecipient() public { // Replace recipient in traderParams without corresponded signature - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = coordinator; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Fill is not signed by dealer"); + vm.expectRevert("SignalBuyContract: Fill is not signed by dealer"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithExpiredAllowFill() public { - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.expiry = uint64(block.timestamp - 1); - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); crdParams.expiry = allowFill.expiry; bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("PionexContract: Fill permission is expired"); + vm.expectRevert("SignalBuyContract: Fill permission is expired"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAlteredOrderHash() public { // Replace orderHash in allowFill - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = bytes32(0); - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); + vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAlteredExecutor() public { // Set the executor to user (not dealer) - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = user; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); // Fill order using dealer (not executor) bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); + vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAlteredFillAmount() public { // Change fill amount in allow fill - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = DEFAULT_ALLOW_FILL.fillAmount.div(2); - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); + vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithAllowFillNotSignedByCoordinator() public { - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; // Sign allow fill using dealer's private key crdParams.sig = _signAllowFill(dealerPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("PionexContract: AllowFill is not signed by coordinator"); + vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -583,10 +583,10 @@ contract PionexContractTest is StrategySharedSetup { vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload1); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.dealerSalt = uint256(8001); - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); @@ -596,38 +596,38 @@ contract PionexContractTest is StrategySharedSetup { } function testCannotFillByZeroTrader() public { - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = address(0); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: recipient can not be zero address"); + vm.expectRevert("SignalBuyContract: recipient can not be zero address"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFillByTraderWithWorseTakerMakerTokenRatio() public { - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; // Increase user token amount so the dealerToken/userToken ratio is worse than order's dealerToken/userToken ratio fill.userTokenAmount = DEFAULT_FILL.userTokenAmount.add(1); - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: dealer token amount not enough"); + vm.expectRevert("SignalBuyContract: dealer token amount not enough"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotFullyFillByTraderWithWorseTakerTokenAmountDueToFee() public { - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5% traderParams.dealerSig = _signFill(dealerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: dealer token amount not enough"); + vm.expectRevert("SignalBuyContract: dealer token amount not enough"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -646,9 +646,9 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), DEFAULT_TRADER_PARAMS.recipient, - IPionexContract.FillReceipt( + ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, @@ -684,19 +684,19 @@ contract PionexContractTest is StrategySharedSetup { dealerContract.activateFactors(); vm.stopPrank(); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for tokenlon fee fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(115).div(100); // 15% more - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); @@ -705,9 +705,9 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, - IPionexContract.FillReceipt( + ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, @@ -736,21 +736,21 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for gas fee and dealer strategy fee fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(11).div(10); // 10% more - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5% traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); @@ -759,9 +759,9 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, - IPionexContract.FillReceipt( + ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, @@ -774,9 +774,9 @@ contract PionexContractTest is StrategySharedSetup { vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); - dealerTakerAsset.assertChange(-int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for Pionex is deducted from dealerTokenAmount directly + dealerTakerAsset.assertChange(-int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy is deducted from dealerTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); - userTakerAsset.assertChange(int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for Pionex + userTakerAsset.assertChange(int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount)); fcMakerAsset.assertChange(0); fcTakerAsset.assertChange(0); @@ -790,18 +790,18 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(11).div(10); // 10% more - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); @@ -810,9 +810,9 @@ contract PionexContractTest is StrategySharedSetup { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), traderParams.recipient, - IPionexContract.FillReceipt( + ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), address(DEFAULT_ORDER.dealerToken), DEFAULT_ORDER.userTokenAmount, @@ -835,17 +835,17 @@ contract PionexContractTest is StrategySharedSetup { function testFullyFillByContractWalletTrader() public { // Contract mockERC1271Wallet as dealer which always return valid ERC-1271 magic value no matter what. - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.dealer = address(mockERC1271Wallet); - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealer = address(mockERC1271Wallet); traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = address(mockERC1271Wallet); - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); @@ -854,22 +854,22 @@ contract PionexContractTest is StrategySharedSetup { } function testFillBySpecificTaker() public { - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = dealer; - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); @@ -878,22 +878,22 @@ contract PionexContractTest is StrategySharedSetup { } function testFillBySpecificTakerWithOldEIP712Method() public { - PionexContractLibEIP712.Order memory order = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = dealer; - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), PionexContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrderWithOldEIP712Method(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFillWithOldEIP712Method(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFillWithOldEIP712Method(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); @@ -907,20 +907,20 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); fill.dealerTokenAmount = DEFAULT_ORDER.minDealerTokenAmount.mul(2); - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = fill.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); @@ -940,20 +940,20 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); - PionexContractLibEIP712.Fill memory fill = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); fill.dealerTokenAmount = DEFAULT_ORDER.minDealerTokenAmount.mul(2).mul(11).div(10); // 10% more - IPionexContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.userTokenAmount = fill.userTokenAmount; traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = fill.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); @@ -974,18 +974,18 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); // First fill amount : 9 USDT - PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; fill1.userTokenAmount = 10 * 1e18; fill1.dealerTokenAmount = 9 * 1e6; - IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; traderParams1.userTokenAmount = fill1.userTokenAmount; traderParams1.dealerTokenAmount = fill1.dealerTokenAmount; traderParams1.dealerSig = _signFill(dealerPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; allowFill1.fillAmount = fill1.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); @@ -993,19 +993,19 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload1); // Second fill amount : 36 USDT - PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; fill2.userTokenAmount = 40 * 1e18; fill2.dealerTokenAmount = 36 * 1e6; - IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; traderParams2.userTokenAmount = fill2.userTokenAmount; traderParams2.dealerTokenAmount = fill2.dealerTokenAmount; traderParams2.dealerSig = _signFill(dealerPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; allowFill2.fillAmount = fill2.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); @@ -1026,18 +1026,18 @@ contract PionexContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); // First fill amount : 9 USDT and same dealerToken/userToken ratio - PionexContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; fill1.userTokenAmount = 10 * 1e18; fill1.dealerTokenAmount = 9 * 1e6; - IPionexContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; traderParams1.userTokenAmount = fill1.userTokenAmount; traderParams1.dealerTokenAmount = fill1.dealerTokenAmount; traderParams1.dealerSig = _signFill(dealerPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; allowFill1.fillAmount = fill1.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); @@ -1045,19 +1045,19 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(payload1); // Second fill amount : 36 USDT and better dealerToken/userToken ratio - PionexContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + SignalBuyContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; fill2.userTokenAmount = 40 * 1e18; fill2.dealerTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more - IPionexContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; + ISignalBuyContract.TraderParams memory traderParams2 = DEFAULT_TRADER_PARAMS; traderParams2.userTokenAmount = fill2.userTokenAmount; traderParams2.dealerTokenAmount = fill2.dealerTokenAmount; traderParams2.dealerSig = _signFill(dealerPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); - PionexContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; + SignalBuyContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; allowFill2.fillAmount = fill2.dealerTokenAmount; - IPionexContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; + ISignalBuyContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); @@ -1076,7 +1076,7 @@ contract PionexContractTest is StrategySharedSetup { *********************************/ function testCannotFillCanceledOrder() public { - PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); @@ -1084,42 +1084,42 @@ contract PionexContractTest is StrategySharedSetup { userProxy.toLimitOrder(cancelPayload); bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.expectRevert("PionexContract: Order is cancelled"); + vm.expectRevert("SignalBuyContract: Order is cancelled"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotCancelIfNotMaker() public { - PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; bytes memory cancelPayload = _genCancelLimitOrderPayload( DEFAULT_ORDER, _signOrder(dealerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) ); - vm.expectRevert("PionexContract: Cancel request is not signed by user"); + vm.expectRevert("SignalBuyContract: Cancel request is not signed by user"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(cancelPayload); } function testCannotCancelExpiredOrder() public { - PionexContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; expiredOrder.expiry = 0; bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(dealerPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); - vm.expectRevert("PionexContract: Order is expired"); + vm.expectRevert("SignalBuyContract: Order is expired"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } function testCannotCancelTwice() public { - PionexContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); - vm.expectRevert("PionexContract: Order is cancelled already"); + vm.expectRevert("SignalBuyContract: Order is cancelled already"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); } @@ -1127,9 +1127,9 @@ contract PionexContractTest is StrategySharedSetup { function _signOrderEIP712( address limitOrderAddr, uint256 privateKey, - PionexContractLibEIP712.Order memory order + SignalBuyContractLibEIP712.Order memory order ) internal returns (bytes memory sig) { - bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); + bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), orderHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); @@ -1138,9 +1138,9 @@ contract PionexContractTest is StrategySharedSetup { function _signFillEIP712( address limitOrderAddr, uint256 privateKey, - PionexContractLibEIP712.Fill memory fill + SignalBuyContractLibEIP712.Fill memory fill ) internal returns (bytes memory sig) { - bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); + bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), fillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); @@ -1149,9 +1149,9 @@ contract PionexContractTest is StrategySharedSetup { function _signAllowFillEIP712( address limitOrderAddr, uint256 privateKey, - PionexContractLibEIP712.AllowFill memory allowFill + SignalBuyContractLibEIP712.AllowFill memory allowFill ) internal returns (bytes memory sig) { - bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), allowFillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); @@ -1163,10 +1163,10 @@ contract PionexContractTest is StrategySharedSetup { function _signOrder( uint256 privateKey, - PionexContractLibEIP712.Order memory order, + SignalBuyContractLibEIP712.Order memory order, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); + bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), orderHash); if (sigType == SignatureValidator.SignatureType.EIP712) { @@ -1182,10 +1182,10 @@ contract PionexContractTest is StrategySharedSetup { function _signOrderWithOldEIP712Method( uint256 privateKey, - PionexContractLibEIP712.Order memory order, + SignalBuyContractLibEIP712.Order memory order, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 orderHash = PionexContractLibEIP712._getOrderStructHash(order); + bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), orderHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1194,10 +1194,10 @@ contract PionexContractTest is StrategySharedSetup { function _signFill( uint256 privateKey, - PionexContractLibEIP712.Fill memory fill, + SignalBuyContractLibEIP712.Fill memory fill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); + bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), fillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); @@ -1205,10 +1205,10 @@ contract PionexContractTest is StrategySharedSetup { function _signFillWithOldEIP712Method( uint256 privateKey, - PionexContractLibEIP712.Fill memory fill, + SignalBuyContractLibEIP712.Fill memory fill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 fillHash = PionexContractLibEIP712._getFillStructHash(fill); + bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), fillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1217,10 +1217,10 @@ contract PionexContractTest is StrategySharedSetup { function _signAllowFill( uint256 privateKey, - PionexContractLibEIP712.AllowFill memory allowFill, + SignalBuyContractLibEIP712.AllowFill memory allowFill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); @@ -1228,10 +1228,10 @@ contract PionexContractTest is StrategySharedSetup { function _signAllowFillWithOldEIP712Method( uint256 privateKey, - PionexContractLibEIP712.AllowFill memory allowFill, + SignalBuyContractLibEIP712.AllowFill memory allowFill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 allowFillHash = PionexContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1239,15 +1239,15 @@ contract PionexContractTest is StrategySharedSetup { } function _genFillByTraderPayload( - PionexContractLibEIP712.Order memory order, + SignalBuyContractLibEIP712.Order memory order, bytes memory orderMakerSig, - IPionexContract.TraderParams memory params, - IPionexContract.CoordinatorParams memory crdParams + ISignalBuyContract.TraderParams memory params, + ISignalBuyContract.CoordinatorParams memory crdParams ) internal view returns (bytes memory payload) { return abi.encodeWithSelector(dealerContract.fillLimitOrder.selector, order, orderMakerSig, params, crdParams); } - function _genCancelLimitOrderPayload(PionexContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) + function _genCancelLimitOrderPayload(SignalBuyContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) internal view returns (bytes memory payload) From 471fbd873ace05fffc38d53659827257f2502b15 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 13 Jun 2023 00:14:30 +0800 Subject: [PATCH 31/41] Rename LimitOrder -> SignalBuy --- contracts/SignalBuyContract.sol | 14 +- contracts/interfaces/ISignalBuyContract.sol | 6 +- test/forkMainnet/SignalBuyContract.t.sol | 176 ++++++++++---------- 3 files changed, 98 insertions(+), 98 deletions(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index 85576efa..ee6e6f0b 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -94,7 +94,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S } /// @inheritdoc ISignalBuyContract - function fillLimitOrder( + function fillSignalBuy( SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _orderUserSig, TraderParams calldata _params, @@ -237,8 +237,8 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S } // bypass stack too deep error - _emitLimitOrderFilledByTrader( - LimitOrderFilledByTraderParams({ + _emitSignalBuyFilledByTrader( + SignalBuyFilledByTraderParams({ orderHash: _settlement.orderHash, user: _settlement.user, dealer: _settlement.trader, @@ -256,7 +256,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S } /// @inheritdoc ISignalBuyContract - function cancelLimitOrder(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) + function cancelSignalBuy(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) external override onlyUserProxy @@ -333,7 +333,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S /* event utils */ - struct LimitOrderFilledByTraderParams { + struct SignalBuyFilledByTraderParams { bytes32 orderHash; address user; address dealer; @@ -348,8 +348,8 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S uint256 dealerFee; } - function _emitLimitOrderFilledByTrader(LimitOrderFilledByTraderParams memory _params) internal { - emit LimitOrderFilledByTrader( + function _emitSignalBuyFilledByTrader(SignalBuyFilledByTraderParams memory _params) internal { + emit SignalBuyFilledByTrader( _params.orderHash, _params.user, _params.dealer, diff --git a/contracts/interfaces/ISignalBuyContract.sol b/contracts/interfaces/ISignalBuyContract.sol index 03e06982..4d36717f 100644 --- a/contracts/interfaces/ISignalBuyContract.sol +++ b/contracts/interfaces/ISignalBuyContract.sol @@ -29,7 +29,7 @@ interface ISignalBuyContract is IStrategyBase { /// @param allowFillHash The EIP-712 hash of the fill permit granted by coordinator /// @param recipient The address of the recipient which will receive tokens from user /// @param fillReceipt Contains details of this single fill - event LimitOrderFilledByTrader( + event SignalBuyFilledByTrader( bytes32 indexed orderHash, address indexed user, address indexed dealer, @@ -77,7 +77,7 @@ interface ISignalBuyContract is IStrategyBase { /// @param _orderUserSig The signature of the order from user /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit - function fillLimitOrder( + function fillSignalBuy( SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _orderUserSig, TraderParams calldata _params, @@ -88,5 +88,5 @@ interface ISignalBuyContract is IStrategyBase { /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled /// @param _cancelUserSig The cancelling signature signed by user - function cancelLimitOrder(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelUserSig) external; + function cancelSignalBuy(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelUserSig) external; } diff --git a/test/forkMainnet/SignalBuyContract.t.sol b/test/forkMainnet/SignalBuyContract.t.sol index 331eab63..7f550a51 100644 --- a/test/forkMainnet/SignalBuyContract.t.sol +++ b/test/forkMainnet/SignalBuyContract.t.sol @@ -21,7 +21,7 @@ contract SignalBuyContractTest is StrategySharedSetup { using SafeMath for uint256; using BalanceSnapshot for BalanceSnapshot.Snapshot; - event LimitOrderFilledByTrader( + event SignalBuyFilledByTrader( bytes32 indexed orderHash, address indexed user, address indexed dealer, @@ -55,7 +55,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.TraderParams DEFAULT_TRADER_PARAMS; ISignalBuyContract.CoordinatorParams DEFAULT_CRD_PARAMS; - SignalBuyContract dealerContract; + SignalBuyContract signalBuyContract; uint64 DEADLINE = uint64(block.timestamp + 2 days); uint256 FACTORSDEALY = 12 hours; @@ -78,7 +78,7 @@ contract SignalBuyContractTest is StrategySharedSetup { uint256(1001), // salt DEADLINE // expiry ); - DEFAULT_ORDER_HASH = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); + DEFAULT_ORDER_HASH = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); DEFAULT_ORDER_MAKER_SIG = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); DEFAULT_FILL = SignalBuyContractLibEIP712.Fill( DEFAULT_ORDER_HASH, @@ -128,12 +128,12 @@ contract SignalBuyContractTest is StrategySharedSetup { vm.label(receiver, "Receiver"); vm.label(feeCollector, "FeeCollector"); vm.label(address(this), "TestingContract"); - vm.label(address(dealerContract), "LimitOrderContract"); + vm.label(address(signalBuyContract), "SignalBuyContract"); vm.label(address(mockERC1271Wallet), "MockERC1271Wallet"); } function _deployStrategyAndUpgrade() internal override returns (address) { - dealerContract = new SignalBuyContract( + signalBuyContract = new SignalBuyContract( owner, address(userProxy), address(weth), @@ -145,38 +145,38 @@ contract SignalBuyContractTest is StrategySharedSetup { ); // Setup vm.startPrank(tokenlonOperator, tokenlonOperator); - userProxy.upgradeLimitOrder(address(dealerContract), true); - permanentStorage.upgradeLimitOrder(address(dealerContract)); - permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(dealerContract), true); - permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(dealerContract), true); + userProxy.upgradeLimitOrder(address(signalBuyContract), true); + permanentStorage.upgradeLimitOrder(address(signalBuyContract)); + permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(signalBuyContract), true); + permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(signalBuyContract), true); vm.stopPrank(); - return address(dealerContract); + return address(signalBuyContract); } function _setupDeployedStrategy() internal override { - dealerContract = SignalBuyContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); + signalBuyContract = SignalBuyContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); // prank owner and update coordinator address - owner = dealerContract.owner(); + owner = signalBuyContract.owner(); vm.prank(owner, owner); - dealerContract.upgradeCoordinator(coordinator); + signalBuyContract.upgradeCoordinator(coordinator); // update local feeCollector address - feeCollector = dealerContract.feeCollector(); + feeCollector = signalBuyContract.feeCollector(); } /********************************* * Test: setup * *********************************/ - function testSetupLimitOrder() public { - assertEq(dealerContract.owner(), owner); - assertEq(dealerContract.coordinator(), coordinator); - assertEq(dealerContract.userProxy(), address(userProxy)); - assertEq(address(dealerContract.spender()), address(spender)); - assertEq(address(dealerContract.permStorage()), address(permanentStorage)); - assertEq(address(dealerContract.weth()), address(weth)); + function testSetupSignalBuy() public { + assertEq(signalBuyContract.owner(), owner); + assertEq(signalBuyContract.coordinator(), coordinator); + assertEq(signalBuyContract.userProxy(), address(userProxy)); + assertEq(address(signalBuyContract.spender()), address(spender)); + assertEq(address(signalBuyContract.permStorage()), address(permanentStorage)); + assertEq(address(signalBuyContract.weth()), address(weth)); - assertEq(uint256(dealerContract.tokenlonFeeFactor()), 0); + assertEq(uint256(signalBuyContract.tokenlonFeeFactor()), 0); } /********************************* @@ -186,21 +186,21 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotTransferOwnershipByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.nominateNewOwner(dealer); + signalBuyContract.nominateNewOwner(dealer); } function testCannotAcceptOwnershipIfNotNominated() public { vm.expectRevert("not nominated"); vm.prank(dealer); - dealerContract.acceptOwnership(); + signalBuyContract.acceptOwnership(); } function testTransferOwnership() public { vm.prank(owner, owner); - dealerContract.nominateNewOwner(dealer); + signalBuyContract.nominateNewOwner(dealer); vm.prank(dealer); - dealerContract.acceptOwnership(); - assertEq(dealerContract.owner(), dealer); + signalBuyContract.acceptOwnership(); + assertEq(signalBuyContract.owner(), dealer); } /********************************* @@ -210,19 +210,19 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotUpgradeSpenderByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.upgradeSpender(dealer); + signalBuyContract.upgradeSpender(dealer); } function testCannotUpgradeSpenderToZeroAddr() public { vm.expectRevert("Strategy: spender can not be zero address"); vm.prank(owner, owner); - dealerContract.upgradeSpender(address(0)); + signalBuyContract.upgradeSpender(address(0)); } function testUpgradeSpender() public { vm.prank(owner, owner); - dealerContract.upgradeSpender(dealer); - assertEq(address(dealerContract.spender()), dealer); + signalBuyContract.upgradeSpender(dealer); + assertEq(address(signalBuyContract.spender()), dealer); } /********************************* @@ -232,19 +232,19 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotUpgradeCoordinatorByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.upgradeCoordinator(dealer); + signalBuyContract.upgradeCoordinator(dealer); } function testCannotUpgradeCoordinatorToZeroAddr() public { vm.expectRevert("SignalBuyContract: coordinator can not be zero address"); vm.prank(owner, owner); - dealerContract.upgradeCoordinator(address(0)); + signalBuyContract.upgradeCoordinator(address(0)); } function testUpgradeCoordinator() public { vm.prank(owner, owner); - dealerContract.upgradeCoordinator(dealer); - assertEq(address(dealerContract.coordinator()), dealer); + signalBuyContract.upgradeCoordinator(dealer); + assertEq(address(signalBuyContract.coordinator()), dealer); } /********************************* @@ -254,27 +254,27 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotSetAllowanceByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + signalBuyContract.setAllowance(allowanceAddrs, address(allowanceTarget)); } function testCannotCloseAllowanceByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + signalBuyContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); } function testSetAndCloseAllowance() public { // Set allowance vm.prank(owner, owner); - dealerContract.setAllowance(allowanceAddrs, address(allowanceTarget)); - assertEq(usdt.allowance(address(dealerContract), address(allowanceTarget)), LibConstant.MAX_UINT); - assertEq(dai.allowance(address(dealerContract), address(allowanceTarget)), LibConstant.MAX_UINT); + signalBuyContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + assertEq(usdt.allowance(address(signalBuyContract), address(allowanceTarget)), LibConstant.MAX_UINT); + assertEq(dai.allowance(address(signalBuyContract), address(allowanceTarget)), LibConstant.MAX_UINT); // Close allowance vm.prank(owner, owner); - dealerContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); - assertEq(usdt.allowance(address(dealerContract), address(allowanceTarget)), 0); - assertEq(dai.allowance(address(dealerContract), address(allowanceTarget)), 0); + signalBuyContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + assertEq(usdt.allowance(address(signalBuyContract), address(allowanceTarget)), 0); + assertEq(dai.allowance(address(signalBuyContract), address(allowanceTarget)), 0); } /********************************* @@ -284,16 +284,16 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotDepositETHByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.depositETH(); + signalBuyContract.depositETH(); } function testDepositETH() public { // Send ether to limit order contract uint256 amount = 1234 ether; - deal(address(dealerContract), amount); + deal(address(signalBuyContract), amount); vm.prank(owner, owner); - dealerContract.depositETH(); - assertEq(weth.balanceOf(address(dealerContract)), amount); + signalBuyContract.depositETH(); + assertEq(weth.balanceOf(address(signalBuyContract)), amount); } /********************************* @@ -303,20 +303,20 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotSetFactorsIfLargerThanBpsMax() public { vm.expectRevert("SignalBuyContract: Invalid user fee factor"); vm.prank(owner, owner); - dealerContract.setFactors(LibConstant.BPS_MAX + 1); + signalBuyContract.setFactors(LibConstant.BPS_MAX + 1); } function testSetFactors() public { vm.startPrank(owner, owner); - dealerContract.setFactors(1); + signalBuyContract.setFactors(1); // fee factors should stay same before new ones activate - assertEq(uint256(dealerContract.tokenlonFeeFactor()), 0); - vm.warp(block.timestamp + dealerContract.factorActivateDelay()); + assertEq(uint256(signalBuyContract.tokenlonFeeFactor()), 0); + vm.warp(block.timestamp + signalBuyContract.factorActivateDelay()); // fee factors should be updated now - dealerContract.activateFactors(); + signalBuyContract.activateFactors(); vm.stopPrank(); - assertEq(uint256(dealerContract.tokenlonFeeFactor()), 1); + assertEq(uint256(signalBuyContract.tokenlonFeeFactor()), 1); } /********************************* @@ -326,29 +326,29 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotSetFeeCollectorByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - dealerContract.setFeeCollector(feeCollector); + signalBuyContract.setFeeCollector(feeCollector); } function testCannotSetFeeCollectorToZeroAddr() public { vm.expectRevert("SignalBuyContract: fee collector can not be zero address"); vm.prank(owner, owner); - dealerContract.setFeeCollector(address(0)); + signalBuyContract.setFeeCollector(address(0)); } function testSetFeeCollector() public { vm.prank(owner, owner); - dealerContract.setFeeCollector(dealer); - assertEq(address(dealerContract.feeCollector()), dealer); + signalBuyContract.setFeeCollector(dealer); + assertEq(address(signalBuyContract.feeCollector()), dealer); } /********************************* - * Test: fillLimitOrder * + * Test: fillSignalBuy * *********************************/ function testCannotFillByTraderIfNotFromUserProxy() public { vm.expectRevert("Strategy: not from UserProxy contract"); // Call limit order contract directly will get reverted since msg.sender is not from UserProxy - dealerContract.fillLimitOrder(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); } function testCannotFillFilledOrderByTrader() public { @@ -382,7 +382,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; order.expiry = uint64(block.timestamp - 1); - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -426,7 +426,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = coordinator; - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -642,11 +642,11 @@ contract SignalBuyContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectEmit(true, true, true, true); - emit LimitOrderFilledByTrader( + emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -679,9 +679,9 @@ contract SignalBuyContractTest is StrategySharedSetup { // tokenlonFeeFactor : 10% vm.startPrank(owner, owner); - dealerContract.setFactors(1000); - vm.warp(block.timestamp + dealerContract.factorActivateDelay()); - dealerContract.activateFactors(); + signalBuyContract.setFactors(1000); + vm.warp(block.timestamp + signalBuyContract.factorActivateDelay()); + signalBuyContract.activateFactors(); vm.stopPrank(); SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -701,11 +701,11 @@ contract SignalBuyContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); - emit LimitOrderFilledByTrader( + emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -755,11 +755,11 @@ contract SignalBuyContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); - emit LimitOrderFilledByTrader( + emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -806,11 +806,11 @@ contract SignalBuyContractTest is StrategySharedSetup { bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); - emit LimitOrderFilledByTrader( + emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), traderParams.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -857,7 +857,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = dealer; - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -881,7 +881,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = dealer; - bytes32 orderHash = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); bytes memory orderMakerSig = _signOrderWithOldEIP712Method(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -1072,14 +1072,14 @@ contract SignalBuyContractTest is StrategySharedSetup { } /********************************* - * cancelLimitOrder * + * cancelSignalBuy * *********************************/ function testCannotFillCanceledOrder() public { SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; - bytes memory cancelPayload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory cancelPayload = _genCancelSignalBuyPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(cancelPayload); @@ -1093,7 +1093,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; - bytes memory cancelPayload = _genCancelLimitOrderPayload( + bytes memory cancelPayload = _genCancelSignalBuyPayload( DEFAULT_ORDER, _signOrder(dealerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) ); @@ -1106,7 +1106,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; expiredOrder.expiry = 0; - bytes memory payload = _genCancelLimitOrderPayload(expiredOrder, _signOrder(dealerPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory payload = _genCancelSignalBuyPayload(expiredOrder, _signOrder(dealerPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); vm.expectRevert("SignalBuyContract: Order is expired"); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); @@ -1116,7 +1116,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; - bytes memory payload = _genCancelLimitOrderPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); + bytes memory payload = _genCancelSignalBuyPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); vm.prank(dealer, dealer); // Only EOA userProxy.toLimitOrder(payload); vm.expectRevert("SignalBuyContract: Order is cancelled already"); @@ -1167,7 +1167,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); - bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), orderHash); + bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), orderHash); if (sigType == SignatureValidator.SignatureType.EIP712) { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1186,7 +1186,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); - bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), orderHash); + bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), orderHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); @@ -1198,7 +1198,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); - bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), fillHash); + bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), fillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); } @@ -1209,7 +1209,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); - bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), fillHash); + bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), fillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); @@ -1221,7 +1221,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); - bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); + bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); } @@ -1232,7 +1232,7 @@ contract SignalBuyContractTest is StrategySharedSetup { SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); - bytes32 EIP712SignDigest = getEIP712Hash(dealerContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); + bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); @@ -1244,14 +1244,14 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.TraderParams memory params, ISignalBuyContract.CoordinatorParams memory crdParams ) internal view returns (bytes memory payload) { - return abi.encodeWithSelector(dealerContract.fillLimitOrder.selector, order, orderMakerSig, params, crdParams); + return abi.encodeWithSelector(signalBuyContract.fillSignalBuy.selector, order, orderMakerSig, params, crdParams); } - function _genCancelLimitOrderPayload(SignalBuyContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) + function _genCancelSignalBuyPayload(SignalBuyContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) internal view returns (bytes memory payload) { - return abi.encodeWithSelector(dealerContract.cancelLimitOrder.selector, order, cancelOrderMakerSig); + return abi.encodeWithSelector(signalBuyContract.cancelSignalBuy.selector, order, cancelOrderMakerSig); } } From c7cb51666dd6ea13a4bad925e663836b9e19fc49 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Tue, 13 Jun 2023 21:53:53 +0800 Subject: [PATCH 32/41] Turn SignalBuy into a standalone contract --- contracts/SignalBuyContract.sol | 84 +++-- contracts/interfaces/ISignalBuyContract.sol | 3 +- .../LibSignalBuyContractOrderStorage.sol | 4 + test/forkMainnet/SignalBuyContract.t.sol | 295 +++++------------- 4 files changed, 148 insertions(+), 238 deletions(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index ee6e6f0b..d90e0d0b 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -12,20 +12,21 @@ import "./interfaces/ISignalBuyContract.sol"; import "./interfaces/IPermanentStorage.sol"; import "./interfaces/ISpender.sol"; import "./interfaces/IWeth.sol"; -import "./utils/StrategyBase.sol"; import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; import "./utils/LibSignalBuyContractOrderStorage.sol"; +import "./utils/Ownable.sol"; import "./utils/SignalBuyContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; /// @title SignalBuy Contract /// @notice Order can be filled as long as the provided dealerToken/userToken ratio is better than or equal to user's specfied dealerToken/userToken ratio. /// @author imToken Labs -contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, SignatureValidator, ReentrancyGuard { +contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValidator, ReentrancyGuard, Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; + IWETH public immutable weth; uint256 public immutable factorActivateDelay; // Below are the variables which consume storage slots. @@ -37,16 +38,28 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S uint16 public tokenlonFeeFactor = 0; uint16 public pendingTokenlonFeeFactor; + mapping(bytes32 => uint256) public filledAmount; + + /// @notice Emitted when allowing another account to spend assets + /// @param spender The address that is allowed to transfer tokens + event AllowTransfer(address indexed spender, address token); + + /// @notice Emitted when disallowing an account to spend assets + /// @param spender The address that is removed from allow list + event DisallowTransfer(address indexed spender, address token); + + /// @notice Emitted when ETH converted to WETH + /// @param amount The amount of converted ETH + event DepositETH(uint256 amount); + constructor( address _owner, - address _userProxy, address _weth, - address _permStorage, - address _spender, address _coordinator, uint256 _factorActivateDelay, address _feeCollector - ) StrategyBase(_owner, _userProxy, _weth, _permStorage, _spender) { + ) Ownable(_owner) { + weth = IWETH(_weth); coordinator = _coordinator; factorActivateDelay = _factorActivateDelay; feeCollector = _feeCollector; @@ -54,6 +67,41 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S receive() external payable {} + /// @notice Set allowance of tokens to an address + /// @notice Only owner can call + /// @param _tokenList The list of tokens + /// @param _spender The address that will be allowed + function setAllowance(address[] calldata _tokenList, address _spender) external onlyOwner { + for (uint256 i = 0; i < _tokenList.length; ++i) { + IERC20(_tokenList[i]).safeApprove(_spender, LibConstant.MAX_UINT); + + emit AllowTransfer(_spender, _tokenList[i]); + } + } + + /// @notice Clear allowance of tokens to an address + /// @notice Only owner can call + /// @param _tokenList The list of tokens + /// @param _spender The address that will be cleared + function closeAllowance(address[] calldata _tokenList, address _spender) external onlyOwner { + for (uint256 i = 0; i < _tokenList.length; ++i) { + IERC20(_tokenList[i]).safeApprove(_spender, 0); + + emit DisallowTransfer(_spender, _tokenList[i]); + } + } + + /// @notice Convert ETH in this contract to WETH + /// @notice Only owner can call + function depositETH() external onlyOwner { + uint256 balance = address(this).balance; + if (balance > 0) { + weth.deposit{ value: balance }(); + + emit DepositETH(balance); + } + } + /// @notice Only owner can call /// @param _newCoordinator The new address of coordinator function upgradeCoordinator(address _newCoordinator) external onlyOwner { @@ -99,7 +147,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams - ) external override onlyUserProxy nonReentrant returns (uint256, uint256) { + ) external override nonReentrant returns (uint256, uint256) { bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); _validateOrder(_order, orderHash, _orderUserSig); @@ -161,11 +209,11 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S require(_fill.recipient != address(0), "SignalBuyContract: recipient can not be zero address"); bytes32 fillHash = getEIP712Hash(SignalBuyContractLibEIP712._getFillStructHash(_fill)); + require(!LibSignalBuyContractOrderStorage.getStorage().fillSeen[fillHash], "SignalBuyContract: Fill seen before"); require(isValidSignature(_fill.dealer, fillHash, bytes(""), _fillTakerSig), "SignalBuyContract: Fill is not signed by dealer"); // Set fill seen to avoid replay attack. - // PermanentStorage would throw error if fill is already seen. - permStorage.setLimitOrderTransactionSeen(fillHash); + LibSignalBuyContractOrderStorage.getStorage().fillSeen[fillHash] = true; } function _validateFillPermission( @@ -187,11 +235,11 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S }) ) ); + require(!LibSignalBuyContractOrderStorage.getStorage().fillSeen[allowFillHash], "SignalBuyContract: AllowFill seen before"); require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "SignalBuyContract: AllowFill is not signed by coordinator"); // Set allow fill seen to avoid replay attack - // PermanentStorage would throw error if allow fill is already seen. - permStorage.setLimitOrderAllowFillSeen(allowFillHash); + LibSignalBuyContractOrderStorage.getStorage().allowFillSeen[allowFillHash] = true; return allowFillHash; } @@ -214,7 +262,6 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S function _settleForTrader(TraderSettlement memory _settlement) internal { // memory cache - ISpender _spender = spender; address _feeCollector = feeCollector; // Calculate user fee (user receives dealer token so fee is charged in dealer token) @@ -226,14 +273,14 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S require(dealerTokenForUser >= _settlement.minDealerTokenAmount, "SignalBuyContract: dealer token amount not enough"); // trader -> user - _spender.spendFromUserTo(_settlement.trader, address(_settlement.dealerToken), _settlement.user, dealerTokenForUser); + _settlement.dealerToken.safeTransferFrom(_settlement.trader, _settlement.user, dealerTokenForUser); // user -> recipient - _spender.spendFromUserTo(_settlement.user, address(_settlement.userToken), _settlement.recipient, _settlement.userTokenAmount); + _settlement.userToken.safeTransferFrom(_settlement.user, _settlement.recipient, _settlement.userTokenAmount); // Collect user fee (charged in dealer token) if (tokenlonFee > 0) { - _spender.spendFromUserTo(_settlement.trader, address(_settlement.dealerToken), _feeCollector, tokenlonFee); + _settlement.dealerToken.safeTransferFrom(_settlement.trader, _feeCollector, tokenlonFee); } // bypass stack too deep error @@ -256,12 +303,7 @@ contract SignalBuyContract is ISignalBuyContract, StrategyBase, BaseLibEIP712, S } /// @inheritdoc ISignalBuyContract - function cancelSignalBuy(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) - external - override - onlyUserProxy - nonReentrant - { + function cancelSignalBuy(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) external override nonReentrant { require(_order.expiry > uint64(block.timestamp), "SignalBuyContract: Order is expired"); bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); bool isCancelled = LibSignalBuyContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; diff --git a/contracts/interfaces/ISignalBuyContract.sol b/contracts/interfaces/ISignalBuyContract.sol index 4d36717f..3b836462 100644 --- a/contracts/interfaces/ISignalBuyContract.sol +++ b/contracts/interfaces/ISignalBuyContract.sol @@ -4,12 +4,11 @@ pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "./IStrategyBase.sol"; import "../utils/SignalBuyContractLibEIP712.sol"; /// @title ISignalBuyContract Interface /// @author imToken Labs -interface ISignalBuyContract is IStrategyBase { +interface ISignalBuyContract { /// @notice Emitted when coordinator address is updated /// @param newCoordinator The address of the new coordinator event UpgradeCoordinator(address newCoordinator); diff --git a/contracts/utils/LibSignalBuyContractOrderStorage.sol b/contracts/utils/LibSignalBuyContractOrderStorage.sol index 8ee803cd..b7b7a5be 100644 --- a/contracts/utils/LibSignalBuyContractOrderStorage.sol +++ b/contracts/utils/LibSignalBuyContractOrderStorage.sol @@ -5,6 +5,10 @@ library LibSignalBuyContractOrderStorage { bytes32 private constant STORAGE_SLOT = 0x1360fb69f36f46eb45cf50ca3a6184b38e4ef3bde9e5aff734dccec027d7b9f7; /// @dev Storage bucket for this feature. struct Storage { + // Has the fill been executed. + mapping(bytes32 => bool) fillSeen; + // Has the allowFill been executed. + mapping(bytes32 => bool) allowFillSeen; // How much maker token has been filled in order. mapping(bytes32 => uint256) orderHashToUserTokenFilledAmount; // Whether order is cancelled or not. diff --git a/test/forkMainnet/SignalBuyContract.t.sol b/test/forkMainnet/SignalBuyContract.t.sol index 7f550a51..930c1a4e 100644 --- a/test/forkMainnet/SignalBuyContract.t.sol +++ b/test/forkMainnet/SignalBuyContract.t.sol @@ -4,6 +4,7 @@ pragma abicoder v2; import "@openzeppelin/contracts/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "contracts/SignalBuyContract.sol"; @@ -14,11 +15,12 @@ import "contracts/utils/LibConstant.sol"; import "test/mocks/MockERC1271Wallet.sol"; import "test/utils/BalanceSnapshot.sol"; -import "test/utils/StrategySharedSetup.sol"; +import "test/utils/BalanceUtil.sol"; import { computeMainnetEIP712DomainSeparator, getEIP712Hash } from "test/utils/Sig.sol"; -contract SignalBuyContractTest is StrategySharedSetup { +contract SignalBuyContractTest is BalanceUtil { using SafeMath for uint256; + using SafeERC20 for IERC20; using BalanceSnapshot for BalanceSnapshot.Snapshot; event SignalBuyFilledByTrader( @@ -62,7 +64,7 @@ contract SignalBuyContractTest is StrategySharedSetup { // effectively a "beforeEach" block function setUp() public { // Setup - setUpSystemContracts(); + signalBuyContract = new SignalBuyContract(owner, address(weth), coordinator, FACTORSDEALY, feeCollector); DEFAULT_AMM_PATH = [address(dai), address(usdt)]; allowanceAddrs = DEFAULT_AMM_PATH; @@ -132,38 +134,6 @@ contract SignalBuyContractTest is StrategySharedSetup { vm.label(address(mockERC1271Wallet), "MockERC1271Wallet"); } - function _deployStrategyAndUpgrade() internal override returns (address) { - signalBuyContract = new SignalBuyContract( - owner, - address(userProxy), - address(weth), - address(permanentStorage), - address(spender), - coordinator, - FACTORSDEALY, - feeCollector - ); - // Setup - vm.startPrank(tokenlonOperator, tokenlonOperator); - userProxy.upgradeLimitOrder(address(signalBuyContract), true); - permanentStorage.upgradeLimitOrder(address(signalBuyContract)); - permanentStorage.setPermission(permanentStorage.transactionSeenStorageId(), address(signalBuyContract), true); - permanentStorage.setPermission(permanentStorage.allowFillSeenStorageId(), address(signalBuyContract), true); - vm.stopPrank(); - return address(signalBuyContract); - } - - function _setupDeployedStrategy() internal override { - signalBuyContract = SignalBuyContract(payable(vm.envAddress("LIMITORDER_ADDRESS"))); - - // prank owner and update coordinator address - owner = signalBuyContract.owner(); - vm.prank(owner, owner); - signalBuyContract.upgradeCoordinator(coordinator); - // update local feeCollector address - feeCollector = signalBuyContract.feeCollector(); - } - /********************************* * Test: setup * *********************************/ @@ -171,9 +141,6 @@ contract SignalBuyContractTest is StrategySharedSetup { function testSetupSignalBuy() public { assertEq(signalBuyContract.owner(), owner); assertEq(signalBuyContract.coordinator(), coordinator); - assertEq(signalBuyContract.userProxy(), address(userProxy)); - assertEq(address(signalBuyContract.spender()), address(spender)); - assertEq(address(signalBuyContract.permStorage()), address(permanentStorage)); assertEq(address(signalBuyContract.weth()), address(weth)); assertEq(uint256(signalBuyContract.tokenlonFeeFactor()), 0); @@ -203,28 +170,6 @@ contract SignalBuyContractTest is StrategySharedSetup { assertEq(signalBuyContract.owner(), dealer); } - /********************************* - * Test: upgradeSpender * - *********************************/ - - function testCannotUpgradeSpenderByNotOwner() public { - vm.expectRevert("not owner"); - vm.prank(dealer); - signalBuyContract.upgradeSpender(dealer); - } - - function testCannotUpgradeSpenderToZeroAddr() public { - vm.expectRevert("Strategy: spender can not be zero address"); - vm.prank(owner, owner); - signalBuyContract.upgradeSpender(address(0)); - } - - function testUpgradeSpender() public { - vm.prank(owner, owner); - signalBuyContract.upgradeSpender(dealer); - assertEq(address(signalBuyContract.spender()), dealer); - } - /********************************* * Test: upgradeCoordinator * *********************************/ @@ -254,27 +199,27 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotSetAllowanceByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - signalBuyContract.setAllowance(allowanceAddrs, address(allowanceTarget)); + signalBuyContract.setAllowance(allowanceAddrs, address(receiver)); } function testCannotCloseAllowanceByNotOwner() public { vm.expectRevert("not owner"); vm.prank(dealer); - signalBuyContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); + signalBuyContract.closeAllowance(allowanceAddrs, address(receiver)); } function testSetAndCloseAllowance() public { // Set allowance vm.prank(owner, owner); - signalBuyContract.setAllowance(allowanceAddrs, address(allowanceTarget)); - assertEq(usdt.allowance(address(signalBuyContract), address(allowanceTarget)), LibConstant.MAX_UINT); - assertEq(dai.allowance(address(signalBuyContract), address(allowanceTarget)), LibConstant.MAX_UINT); + signalBuyContract.setAllowance(allowanceAddrs, address(receiver)); + assertEq(usdt.allowance(address(signalBuyContract), address(receiver)), LibConstant.MAX_UINT); + assertEq(dai.allowance(address(signalBuyContract), address(receiver)), LibConstant.MAX_UINT); // Close allowance vm.prank(owner, owner); - signalBuyContract.closeAllowance(allowanceAddrs, address(allowanceTarget)); - assertEq(usdt.allowance(address(signalBuyContract), address(allowanceTarget)), 0); - assertEq(dai.allowance(address(signalBuyContract), address(allowanceTarget)), 0); + signalBuyContract.closeAllowance(allowanceAddrs, address(receiver)); + assertEq(usdt.allowance(address(signalBuyContract), address(receiver)), 0); + assertEq(dai.allowance(address(signalBuyContract), address(receiver)), 0); } /********************************* @@ -345,17 +290,9 @@ contract SignalBuyContractTest is StrategySharedSetup { * Test: fillSignalBuy * *********************************/ - function testCannotFillByTraderIfNotFromUserProxy() public { - vm.expectRevert("Strategy: not from UserProxy contract"); - // Call limit order contract directly will get reverted since msg.sender is not from UserProxy - signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - } - function testCannotFillFilledOrderByTrader() public { // Fullly fill the default order first - bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload1); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); // Try to fill the default order, should fail SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; @@ -372,10 +309,8 @@ contract SignalBuyContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); crdParams.salt = allowFill.salt; - bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectRevert("SignalBuyContract: Order is filled"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload2); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); } function testCannotFillExpiredOrderByTrader() public { @@ -397,29 +332,23 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); vm.expectRevert("SignalBuyContract: Order is expired"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams); } function testCannotFillByTraderWithWrongMakerSig() public { bytes memory wrongMakerSig = _signOrder(dealerPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: Order is not signed by user"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, wrongMakerSig, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); } function testCannotFillByTraderWithWrongTakerSig() public { ISignalBuyContract.TraderParams memory wrongTraderParams = DEFAULT_TRADER_PARAMS; wrongTraderParams.dealerSig = _signFill(userPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: Fill is not signed by dealer"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, wrongTraderParams, DEFAULT_CRD_PARAMS); } function testCannotFillByTraderWithTakerOtherThanOrderSpecified() public { @@ -442,10 +371,8 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); vm.expectRevert("SignalBuyContract: Order cannot be filled by this dealer"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams); } function testCannotFillByTraderWithExpiredFill() public { @@ -456,17 +383,13 @@ contract SignalBuyContractTest is StrategySharedSetup { traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.expiry = fill.expiry; - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: Fill request is expired"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); } function testCannotReplayFill() public { // Fill with DEFAULT_FILL - bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload1); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); // Try to fill with same fill request with differnt allowFill (otherwise will revert by dup allowFill) SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; @@ -476,10 +399,8 @@ contract SignalBuyContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); crdParams.salt = allowFill.salt; - bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); - vm.expectRevert("PermanentStorage: transaction seen before"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload2); + vm.expectRevert("SignalBuyContract: Fill seen before"); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByTraderWithAlteredTakerTokenAmount() public { @@ -493,20 +414,16 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectRevert("SignalBuyContract: Fill is not signed by dealer"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); } function testCannotFillByTraderWithAlteredRecipient() public { // Replace recipient in traderParams without corresponded signature ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = coordinator; - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: Fill is not signed by dealer"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); } function testCannotFillByTraderWithExpiredAllowFill() public { @@ -517,10 +434,8 @@ contract SignalBuyContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); crdParams.expiry = allowFill.expiry; - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("SignalBuyContract: Fill permission is expired"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByTraderWithAlteredOrderHash() public { @@ -531,10 +446,8 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByTraderWithAlteredExecutor() public { @@ -546,10 +459,8 @@ contract SignalBuyContractTest is StrategySharedSetup { crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); // Fill order using dealer (not executor) - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByTraderWithAlteredFillAmount() public { @@ -560,10 +471,8 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByTraderWithAllowFillNotSignedByCoordinator() public { @@ -571,17 +480,13 @@ contract SignalBuyContractTest is StrategySharedSetup { // Sign allow fill using dealer's private key crdParams.sig = _signAllowFill(dealerPrivateKey, DEFAULT_ALLOW_FILL, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); vm.expectRevert("SignalBuyContract: AllowFill is not signed by coordinator"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByTraderWithReplayedAllowFill() public { // Fill with default allow fill - bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload1); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; fill.dealerSalt = uint256(8001); @@ -589,20 +494,16 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); - vm.expectRevert("PermanentStorage: allow fill seen before"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload2); + vm.expectRevert("SignalBuyContract: Fill seen before"); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); } function testCannotFillByZeroTrader() public { ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.recipient = address(0); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: recipient can not be zero address"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); } function testCannotFillByTraderWithWorseTakerMakerTokenRatio() public { @@ -614,10 +515,8 @@ contract SignalBuyContractTest is StrategySharedSetup { traderParams.userTokenAmount = fill.userTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: dealer token amount not enough"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); } function testCannotFullyFillByTraderWithWorseTakerTokenAmountDueToFee() public { @@ -626,10 +525,8 @@ contract SignalBuyContractTest is StrategySharedSetup { traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5% traderParams.dealerSig = _signFill(dealerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: dealer token amount not enough"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); } function testFullyFillByTraderWithNoFee() public { @@ -640,7 +537,6 @@ contract SignalBuyContractTest is StrategySharedSetup { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, @@ -658,8 +554,7 @@ contract SignalBuyContractTest is StrategySharedSetup { 0 // dealerStrategyFee = 0 ) ); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); @@ -699,7 +594,6 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, @@ -717,8 +611,7 @@ contract SignalBuyContractTest is StrategySharedSetup { 0 // dealerStrategyFee = 0 ) ); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); dealerTakerAsset.assertChange(-int256(traderParams.dealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); @@ -753,7 +646,6 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, @@ -771,8 +663,7 @@ contract SignalBuyContractTest is StrategySharedSetup { traderParams.dealerTokenAmount.mul(3).div(100) // dealerStrategyFee = 0.5% + 2.5% = 3% dealerTokenAmount ) ); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); dealerTakerAsset.assertChange(-int256(traderParams.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy is deducted from dealerTokenAmount directly receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); @@ -804,7 +695,6 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( DEFAULT_ORDER_HASH, @@ -822,8 +712,7 @@ contract SignalBuyContractTest is StrategySharedSetup { 0 ) ); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); dealerTakerAsset.assertChange(-int256(fill.dealerTokenAmount)); receiverMakerAsset.assertChange(int256(DEFAULT_ORDER.userTokenAmount)); @@ -848,9 +737,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); } function testFillBySpecificTaker() public { @@ -872,9 +759,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams); } function testFillBySpecificTakerWithOldEIP712Method() public { @@ -896,9 +781,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFillWithOldEIP712Method(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(order, orderMakerSig, traderParams, crdParams); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams); } function testOverFillByTrader() public { @@ -923,9 +806,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); // Balance change should be bound by order amount (not affected by 2x fill amount) dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount)); @@ -956,9 +837,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, crdParams); // Balance change should be bound by order amount (not affected by 2x fill amount) dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount.mul(11).div(10))); // 10% more @@ -988,9 +867,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); - bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload1); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); // Second fill amount : 36 USDT SignalBuyContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; @@ -1008,9 +885,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); - bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload2); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); // Half of the order filled after 2 txs dealerTakerAsset.assertChange(-int256(DEFAULT_ORDER.minDealerTokenAmount.div(2))); @@ -1040,9 +915,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; crdParams1.sig = _signAllowFill(coordinatorPrivateKey, allowFill1, SignatureValidator.SignatureType.EIP712); - bytes memory payload1 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload1); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); // Second fill amount : 36 USDT and better dealerToken/userToken ratio SignalBuyContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; @@ -1060,9 +933,7 @@ contract SignalBuyContractTest is StrategySharedSetup { ISignalBuyContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; crdParams2.sig = _signAllowFill(coordinatorPrivateKey, allowFill2, SignatureValidator.SignatureType.EIP712); - bytes memory payload2 = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload2); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams2, crdParams2); // Half of the order filled after 2 txs dealerTakerAsset.assertChange(-int256(fill1.dealerTokenAmount.add(fill2.dealerTokenAmount))); @@ -1078,50 +949,40 @@ contract SignalBuyContractTest is StrategySharedSetup { function testCannotFillCanceledOrder() public { SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; + bytes memory cancelSig = _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712); - bytes memory cancelPayload = _genCancelSignalBuyPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(cancelPayload); + signalBuyContract.cancelSignalBuy(DEFAULT_ORDER, cancelSig); - bytes memory payload = _genFillByTraderPayload(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); vm.expectRevert("SignalBuyContract: Order is cancelled"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); } function testCannotCancelIfNotMaker() public { SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; + bytes memory cancelSig = _signOrder(dealerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712); - bytes memory cancelPayload = _genCancelSignalBuyPayload( - DEFAULT_ORDER, - _signOrder(dealerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712) - ); vm.expectRevert("SignalBuyContract: Cancel request is not signed by user"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(cancelPayload); + signalBuyContract.cancelSignalBuy(DEFAULT_ORDER, cancelSig); } function testCannotCancelExpiredOrder() public { SignalBuyContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; expiredOrder.expiry = 0; + bytes memory cancelSig = _signOrder(userPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genCancelSignalBuyPayload(expiredOrder, _signOrder(dealerPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712)); vm.expectRevert("SignalBuyContract: Order is expired"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.cancelSignalBuy(expiredOrder, cancelSig); } function testCannotCancelTwice() public { SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; + bytes memory cancelSig = _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712); - bytes memory payload = _genCancelSignalBuyPayload(DEFAULT_ORDER, _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712)); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.cancelSignalBuy(DEFAULT_ORDER, cancelSig); vm.expectRevert("SignalBuyContract: Order is cancelled already"); - vm.prank(dealer, dealer); // Only EOA - userProxy.toLimitOrder(payload); + signalBuyContract.cancelSignalBuy(DEFAULT_ORDER, cancelSig); } function _signOrderEIP712( @@ -1161,6 +1022,27 @@ contract SignalBuyContractTest is StrategySharedSetup { * Helpers * *********************************/ + function dealWallet(address[] memory _wallet, uint256 _amount) internal { + // Deal 100 ETH to each account + for (uint256 i = 0; i < _wallet.length; i++) { + deal(_wallet[i], _amount); + } + } + + function setEOABalanceAndApprove( + address eoa, + IERC20[] memory tokens, + uint256 amount + ) internal { + require(address(signalBuyContract) != address(0), "System contracts not setup yet"); + vm.startPrank(eoa); + for (uint256 i = 0; i < tokens.length; i++) { + setERC20Balance(address(tokens[i]), eoa, amount); + tokens[i].safeApprove(address(signalBuyContract), type(uint256).max); + } + vm.stopPrank(); + } + function _signOrder( uint256 privateKey, SignalBuyContractLibEIP712.Order memory order, @@ -1237,21 +1119,4 @@ contract SignalBuyContractTest is StrategySharedSetup { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(sigType)); } - - function _genFillByTraderPayload( - SignalBuyContractLibEIP712.Order memory order, - bytes memory orderMakerSig, - ISignalBuyContract.TraderParams memory params, - ISignalBuyContract.CoordinatorParams memory crdParams - ) internal view returns (bytes memory payload) { - return abi.encodeWithSelector(signalBuyContract.fillSignalBuy.selector, order, orderMakerSig, params, crdParams); - } - - function _genCancelSignalBuyPayload(SignalBuyContractLibEIP712.Order memory order, bytes memory cancelOrderMakerSig) - internal - view - returns (bytes memory payload) - { - return abi.encodeWithSelector(signalBuyContract.cancelSignalBuy.selector, order, cancelOrderMakerSig); - } } From 91938e229740251c12bc210297590e1c45c49ffa Mon Sep 17 00:00:00 2001 From: NIC619 Date: Wed, 14 Jun 2023 17:19:12 +0800 Subject: [PATCH 33/41] Remove unused --- contracts/SignalBuyContract.sol | 2 -- contracts/interfaces/ISignalBuyContract.sol | 2 -- 2 files changed, 4 deletions(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index d90e0d0b..b778155d 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -9,8 +9,6 @@ import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "./interfaces/ISignalBuyContract.sol"; -import "./interfaces/IPermanentStorage.sol"; -import "./interfaces/ISpender.sol"; import "./interfaces/IWeth.sol"; import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; diff --git a/contracts/interfaces/ISignalBuyContract.sol b/contracts/interfaces/ISignalBuyContract.sol index 3b836462..4ab7630c 100644 --- a/contracts/interfaces/ISignalBuyContract.sol +++ b/contracts/interfaces/ISignalBuyContract.sol @@ -2,8 +2,6 @@ pragma solidity >=0.7.0; pragma abicoder v2; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - import "../utils/SignalBuyContractLibEIP712.sol"; /// @title ISignalBuyContract Interface From 3323a1adfd597efb4f6473267ee5a03ffa50136d Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 16 Jun 2023 00:02:47 +0800 Subject: [PATCH 34/41] Handle ETH/WETH dealer token conversion for dealer --- contracts/SignalBuyContract.sol | 45 +++++++++++++++++++-- contracts/interfaces/ISignalBuyContract.sol | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index b778155d..d90cc388 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -10,6 +10,7 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "./interfaces/ISignalBuyContract.sol"; import "./interfaces/IWeth.sol"; +import { Asset } from "./utils/Asset.sol"; import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; import "./utils/LibSignalBuyContractOrderStorage.sol"; @@ -23,6 +24,7 @@ import "./utils/SignatureValidator.sol"; contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValidator, ReentrancyGuard, Ownable { using SafeMath for uint256; using SafeERC20 for IERC20; + using Asset for address; IWETH public immutable weth; uint256 public immutable factorActivateDelay; @@ -145,7 +147,7 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams - ) external override nonReentrant returns (uint256, uint256) { + ) external payable override nonReentrant returns (uint256, uint256) { bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); _validateOrder(_order, orderHash, _orderUserSig); @@ -267,18 +269,53 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida uint256 tokenlonFee = _mulFactor(_settlement.dealerTokenAmount, tokenlonFeeFactor); // 2. Fee for SignalBuy, including gas fee and strategy fee uint256 dealerFee = _mulFactor(_settlement.dealerTokenAmount, _settlement.gasFeeFactor + _settlement.dealerStrategyFeeFactor); - uint256 dealerTokenForUser = _settlement.dealerTokenAmount.sub(tokenlonFee).sub(dealerFee); + uint256 dealerTokenForUserAndTokenlon = _settlement.dealerTokenAmount.sub(dealerFee); + uint256 dealerTokenForUser = dealerTokenForUserAndTokenlon.sub(tokenlonFee); require(dealerTokenForUser >= _settlement.minDealerTokenAmount, "SignalBuyContract: dealer token amount not enough"); // trader -> user - _settlement.dealerToken.safeTransferFrom(_settlement.trader, _settlement.user, dealerTokenForUser); + address _weth = address(weth); // cache + if (address(_settlement.dealerToken).isETH()) { + if (msg.value > 0) { + // User wants ETH and dealer pays in ETH + require(msg.value == dealerTokenForUserAndTokenlon, "SignalBuyContract: mismatch dealer token (ETH) amount"); + } else { + // User wants ETH but dealer pays in WETH + IERC20(_weth).safeTransferFrom(_settlement.trader, address(this), dealerTokenForUserAndTokenlon); + weth.withdraw(dealerTokenForUserAndTokenlon); + } + // Send ETH to user + LibConstant.ETH_ADDRESS.transferTo(payable(_settlement.user), dealerTokenForUser); + } else if (address(_settlement.dealerToken) == _weth) { + if (msg.value > 0) { + // User wants WETH but dealer pays in ETH + require(msg.value == dealerTokenForUserAndTokenlon, "SignalBuyContract: mismatch dealer token (ETH) amount"); + weth.deposit{ value: dealerTokenForUserAndTokenlon }(); + weth.transfer(_settlement.user, dealerTokenForUser); + } else { + // User wants WETH and dealer pays in WETH + IERC20(_weth).safeTransferFrom(_settlement.trader, _settlement.user, dealerTokenForUser); + } + } else { + _settlement.dealerToken.safeTransferFrom(_settlement.trader, _settlement.user, dealerTokenForUser); + } // user -> recipient _settlement.userToken.safeTransferFrom(_settlement.user, _settlement.recipient, _settlement.userTokenAmount); // Collect user fee (charged in dealer token) if (tokenlonFee > 0) { - _settlement.dealerToken.safeTransferFrom(_settlement.trader, _feeCollector, tokenlonFee); + if (address(_settlement.dealerToken).isETH()) { + LibConstant.ETH_ADDRESS.transferTo(payable(_feeCollector), tokenlonFee); + } else if (address(_settlement.dealerToken) == _weth) { + if (msg.value > 0) { + weth.transfer(_feeCollector, tokenlonFee); + } else { + weth.transferFrom(_settlement.trader, _feeCollector, tokenlonFee); + } + } else { + _settlement.dealerToken.safeTransferFrom(_settlement.trader, _feeCollector, tokenlonFee); + } } // bypass stack too deep error diff --git a/contracts/interfaces/ISignalBuyContract.sol b/contracts/interfaces/ISignalBuyContract.sol index 4ab7630c..6bbc8665 100644 --- a/contracts/interfaces/ISignalBuyContract.sol +++ b/contracts/interfaces/ISignalBuyContract.sol @@ -79,7 +79,7 @@ interface ISignalBuyContract { bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams - ) external returns (uint256, uint256); + ) external payable returns (uint256, uint256); /// @notice Cancel an order /// @notice Only user proxy can call From bc2bf4678927b7af58015c53d4ce421eb7463378 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 16 Jun 2023 00:19:25 +0800 Subject: [PATCH 35/41] Add ETH/WETH settlement tests --- test/forkMainnet/SignalBuyContract.t.sol | 257 +++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/test/forkMainnet/SignalBuyContract.t.sol b/test/forkMainnet/SignalBuyContract.t.sol index 930c1a4e..160d8792 100644 --- a/test/forkMainnet/SignalBuyContract.t.sol +++ b/test/forkMainnet/SignalBuyContract.t.sol @@ -942,6 +942,263 @@ contract SignalBuyContractTest is BalanceUtil { userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2))); } + /********************************* + * ETH/WETH settlement * + *********************************/ + + struct ETHandWETHAssetSnapshot { + BalanceSnapshot.Snapshot dealerETHAsset; + BalanceSnapshot.Snapshot dealerWETHAsset; + BalanceSnapshot.Snapshot userETHAsset; + BalanceSnapshot.Snapshot userWETHAsset; + } + ETHandWETHAssetSnapshot assetSnapshots; + + function testSettlementETHToETHWithNoFee() public { + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.dealerToken = IERC20(LibConstant.ETH_ADDRESS); + order.minDealerTokenAmount = 1e18; + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + fill.dealerTokenAmount = order.minDealerTokenAmount; + + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + allowFill.fillAmount = traderParams.dealerTokenAmount; + + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS); + assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth)); + assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS); + assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth)); + + // Case 1: Tx failed due to mismatch msg.value + vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount"); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy{ value: fill.dealerTokenAmount - 1 }(order, orderMakerSig, traderParams, crdParams); + + // Case 2: Tx succeeded + vm.expectEmit(true, true, true, true); + emit SignalBuyFilledByTrader( + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + order.user, + dealer, + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + DEFAULT_TRADER_PARAMS.recipient, + ISignalBuyContract.FillReceipt( + address(order.userToken), + address(order.dealerToken), + order.userTokenAmount, + order.minDealerTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + 0, // tokenlonFee = 0 + 0 // dealerStrategyFee = 0 + ) + ); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy{ value: fill.dealerTokenAmount }(order, orderMakerSig, traderParams, crdParams); + + assetSnapshots.dealerETHAsset.assertChange(-int256(order.minDealerTokenAmount)); + assetSnapshots.dealerWETHAsset.assertChange(0); + assetSnapshots.userETHAsset.assertChange(int256(order.minDealerTokenAmount)); + assetSnapshots.userWETHAsset.assertChange(0); + } + + function testSettlementWETHToWETHWithNoFee() public { + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.dealerToken = weth; + order.minDealerTokenAmount = 1e18; + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + fill.dealerTokenAmount = order.minDealerTokenAmount; + + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + allowFill.fillAmount = traderParams.dealerTokenAmount; + + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS); + assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth)); + assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS); + assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth)); + + // Case 1: Tx failed due to invalid msg.value + vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount"); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy{ value: 1 }(order, orderMakerSig, traderParams, crdParams); + + // Case 2: Tx succeeded + vm.expectEmit(true, true, true, true); + emit SignalBuyFilledByTrader( + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + order.user, + dealer, + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + DEFAULT_TRADER_PARAMS.recipient, + ISignalBuyContract.FillReceipt( + address(order.userToken), + address(order.dealerToken), + order.userTokenAmount, + order.minDealerTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + 0, // tokenlonFee = 0 + 0 // dealerStrategyFee = 0 + ) + ); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams); + + assetSnapshots.dealerETHAsset.assertChange(0); + assetSnapshots.dealerWETHAsset.assertChange(-int256(order.minDealerTokenAmount)); + assetSnapshots.userETHAsset.assertChange(0); + assetSnapshots.userWETHAsset.assertChange(int256(order.minDealerTokenAmount)); + } + + function testSettlementETHToWETHWithAddedTokenlonFee() public { + // tokenlonFeeFactor : 10% + vm.startPrank(owner, owner); + signalBuyContract.setFactors(1000); + vm.warp(block.timestamp + signalBuyContract.factorActivateDelay()); + signalBuyContract.activateFactors(); + vm.stopPrank(); + + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.dealerToken = weth; + order.minDealerTokenAmount = 1e18; + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio + // to account for tokenlon fee + fill.dealerTokenAmount = order.minDealerTokenAmount.mul(115).div(100); // 15% more + + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + allowFill.fillAmount = traderParams.dealerTokenAmount; + + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS); + assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth)); + assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS); + assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth)); + + // Case 1: Tx failed due to invalid msg.value + vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount"); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy{ value: 1 }(order, orderMakerSig, traderParams, crdParams); + + // Case 2: Tx succeeded + vm.expectEmit(true, true, true, true); + emit SignalBuyFilledByTrader( + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + order.user, + dealer, + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + DEFAULT_TRADER_PARAMS.recipient, + ISignalBuyContract.FillReceipt( + address(order.userToken), + address(order.dealerToken), + order.userTokenAmount, + fill.dealerTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + fill.dealerTokenAmount.div(10), // tokenlonFee = 10% dealerTokenAmount + 0 // dealerStrategyFee = 0 + ) + ); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy{ value: fill.dealerTokenAmount }(order, orderMakerSig, traderParams, crdParams); + + assetSnapshots.dealerETHAsset.assertChange(-int256(fill.dealerTokenAmount)); + assetSnapshots.dealerWETHAsset.assertChange(0); + assetSnapshots.userETHAsset.assertChange(0); + assetSnapshots.userWETHAsset.assertChange(int256(fill.dealerTokenAmount.mul(9).div(10))); // 10% fee for Tokenlon + } + + function testSettlementWETHToETHWithAddedGasFeeAndStrategyFee() public { + SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + order.dealerToken = IERC20(LibConstant.ETH_ADDRESS); + order.minDealerTokenAmount = 1e18; + bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio + // to account for gas fee and dealer strategy fee + fill.dealerTokenAmount = order.minDealerTokenAmount.mul(11).div(10); // 10% more + + ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; + traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5% + traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5% + traderParams.dealerTokenAmount = fill.dealerTokenAmount; + traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + + SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + allowFill.fillAmount = traderParams.dealerTokenAmount; + + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); + + assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS); + assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth)); + assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS); + assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth)); + + // Case 1: Tx failed due to invalid msg.value + vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount"); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy{ value: 1 }(order, orderMakerSig, traderParams, crdParams); + + // Case 2: Tx succeeded + vm.expectEmit(true, true, true, true); + emit SignalBuyFilledByTrader( + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + order.user, + dealer, + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + DEFAULT_TRADER_PARAMS.recipient, + ISignalBuyContract.FillReceipt( + address(order.userToken), + address(order.dealerToken), + order.userTokenAmount, + fill.dealerTokenAmount, + 0, // remainingUserTokenAmount should be zero after order fully filled + 0, // tokenlonFee = 0 + fill.dealerTokenAmount.mul(3).div(100) // dealerStrategyFee = 0.5% + 2.5% = 3% dealerTokenAmount + ) + ); + vm.prank(dealer, dealer); + signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams); + + assetSnapshots.dealerETHAsset.assertChange(0); + assetSnapshots.dealerWETHAsset.assertChange(-int256(fill.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy is deducted from dealerTokenAmount directly + assetSnapshots.userETHAsset.assertChange(int256(fill.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy + assetSnapshots.userWETHAsset.assertChange(0); + } + /********************************* * cancelSignalBuy * *********************************/ From f8612acf257aa1b35f0afe94825afe5615c9b2e6 Mon Sep 17 00:00:00 2001 From: NIC619 Date: Fri, 7 Jul 2023 17:52:07 +0800 Subject: [PATCH 36/41] Fix ORDER_TYPEHASH --- contracts/utils/SignalBuyContractLibEIP712.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/SignalBuyContractLibEIP712.sol b/contracts/utils/SignalBuyContractLibEIP712.sol index 0746ab84..ef8e5c82 100644 --- a/contracts/utils/SignalBuyContractLibEIP712.sol +++ b/contracts/utils/SignalBuyContractLibEIP712.sol @@ -33,7 +33,7 @@ library SignalBuyContractLibEIP712 { ) ); */ - bytes32 private constant ORDER_TYPEHASH = 0x2f0bead1a08e744d3b433a8d66c0a8f920a802838bc159ace4322e432f51458d; + bytes32 private constant ORDER_TYPEHASH = 0xf3ab25d0577fbc8769db2380dba0706d4977c70ca7b697c4677d88bbc972fbce; function _getOrderStructHash(Order memory _order) internal pure returns (bytes32) { return From d3ce5d90af1167e29143dd8385fc171ecaf58bf3 Mon Sep 17 00:00:00 2001 From: Charles Jhong Date: Mon, 14 Aug 2023 15:52:47 +0800 Subject: [PATCH 37/41] refactor SignalBuyContract 712 lib --- contracts/SignalBuyContract.sol | 36 ++- contracts/interfaces/ISignalBuyContract.sol | 6 +- .../utils/SignalBuyContractLibEIP712.sol | 156 +++++------- test/forkMainnet/SignalBuyContract.t.sol | 226 +++++++++--------- 4 files changed, 189 insertions(+), 235 deletions(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index d90cc388..00e2c9e4 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -15,7 +15,7 @@ import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; import "./utils/LibSignalBuyContractOrderStorage.sol"; import "./utils/Ownable.sol"; -import "./utils/SignalBuyContractLibEIP712.sol"; +import { Order, getOrderStructHash, Fill, getFillStructHash, AllowFill, getAllowFillStructHash } from "./utils/SignalBuyContractLibEIP712.sol"; import "./utils/SignatureValidator.sol"; /// @title SignalBuy Contract @@ -143,12 +143,12 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida /// @inheritdoc ISignalBuyContract function fillSignalBuy( - SignalBuyContractLibEIP712.Order calldata _order, + Order calldata _order, bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams ) external payable override nonReentrant returns (uint256, uint256) { - bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); + bytes32 orderHash = getEIP712Hash(getOrderStructHash(_order)); _validateOrder(_order, orderHash, _orderUserSig); bytes32 allowFillHash = _validateFillPermission(orderHash, _params.dealerTokenAmount, _params.dealer, _crdParams); @@ -163,7 +163,7 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida ); { - SignalBuyContractLibEIP712.Fill memory fill = SignalBuyContractLibEIP712.Fill({ + Fill memory fill = Fill({ orderHash: orderHash, dealer: _params.dealer, recipient: _params.recipient, @@ -204,11 +204,11 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida return (dealerTokenAmount, userTokenAmount); } - function _validateTraderFill(SignalBuyContractLibEIP712.Fill memory _fill, bytes memory _fillTakerSig) internal { + function _validateTraderFill(Fill memory _fill, bytes memory _fillTakerSig) internal { require(_fill.expiry > uint64(block.timestamp), "SignalBuyContract: Fill request is expired"); require(_fill.recipient != address(0), "SignalBuyContract: recipient can not be zero address"); - bytes32 fillHash = getEIP712Hash(SignalBuyContractLibEIP712._getFillStructHash(_fill)); + bytes32 fillHash = getEIP712Hash(getFillStructHash(_fill)); require(!LibSignalBuyContractOrderStorage.getStorage().fillSeen[fillHash], "SignalBuyContract: Fill seen before"); require(isValidSignature(_fill.dealer, fillHash, bytes(""), _fillTakerSig), "SignalBuyContract: Fill is not signed by dealer"); @@ -225,14 +225,8 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida require(_crdParams.expiry > uint64(block.timestamp), "SignalBuyContract: Fill permission is expired"); bytes32 allowFillHash = getEIP712Hash( - SignalBuyContractLibEIP712._getAllowFillStructHash( - SignalBuyContractLibEIP712.AllowFill({ - orderHash: _orderHash, - executor: _executor, - fillAmount: _fillAmount, - salt: _crdParams.salt, - expiry: _crdParams.expiry - }) + getAllowFillStructHash( + AllowFill({ orderHash: _orderHash, executor: _executor, fillAmount: _fillAmount, salt: _crdParams.salt, expiry: _crdParams.expiry }) ) ); require(!LibSignalBuyContractOrderStorage.getStorage().fillSeen[allowFillHash], "SignalBuyContract: AllowFill seen before"); @@ -338,16 +332,16 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida } /// @inheritdoc ISignalBuyContract - function cancelSignalBuy(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelOrderUserSig) external override nonReentrant { + function cancelSignalBuy(Order calldata _order, bytes calldata _cancelOrderUserSig) external override nonReentrant { require(_order.expiry > uint64(block.timestamp), "SignalBuyContract: Order is expired"); - bytes32 orderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(_order)); + bytes32 orderHash = getEIP712Hash(getOrderStructHash(_order)); bool isCancelled = LibSignalBuyContractOrderStorage.getStorage().orderHashToCancelled[orderHash]; require(!isCancelled, "SignalBuyContract: Order is cancelled already"); { - SignalBuyContractLibEIP712.Order memory cancelledOrder = _order; + Order memory cancelledOrder = _order; cancelledOrder.minDealerTokenAmount = 0; - bytes32 cancelledOrderHash = getEIP712Hash(SignalBuyContractLibEIP712._getOrderStructHash(cancelledOrder)); + bytes32 cancelledOrderHash = getEIP712Hash(getOrderStructHash(cancelledOrder)); require( isValidSignature(_order.user, cancelledOrderHash, bytes(""), _cancelOrderUserSig), "SignalBuyContract: Cancel request is not signed by user" @@ -362,7 +356,7 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida /* order utils */ function _validateOrder( - SignalBuyContractLibEIP712.Order memory _order, + Order memory _order, bytes32 _orderHash, bytes memory _orderUserSig ) internal view { @@ -373,14 +367,14 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida require(isValidSignature(_order.user, _orderHash, bytes(""), _orderUserSig), "SignalBuyContract: Order is not signed by user"); } - function _validateOrderTaker(SignalBuyContractLibEIP712.Order memory _order, address _dealer) internal pure { + function _validateOrderTaker(Order memory _order, address _dealer) internal pure { if (_order.dealer != address(0)) { require(_order.dealer == _dealer, "SignalBuyContract: Order cannot be filled by this dealer"); } } function _quoteOrderFromUserToken( - SignalBuyContractLibEIP712.Order memory _order, + Order memory _order, bytes32 _orderHash, uint256 _userTokenAmount ) internal view returns (uint256, uint256) { diff --git a/contracts/interfaces/ISignalBuyContract.sol b/contracts/interfaces/ISignalBuyContract.sol index 6bbc8665..d4095c33 100644 --- a/contracts/interfaces/ISignalBuyContract.sol +++ b/contracts/interfaces/ISignalBuyContract.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.0; pragma abicoder v2; -import "../utils/SignalBuyContractLibEIP712.sol"; +import { Order } from "../utils/SignalBuyContractLibEIP712.sol"; /// @title ISignalBuyContract Interface /// @author imToken Labs @@ -75,7 +75,7 @@ interface ISignalBuyContract { /// @param _params Trader specific filling parameters /// @param _crdParams Contains details of the fill permit function fillSignalBuy( - SignalBuyContractLibEIP712.Order calldata _order, + Order calldata _order, bytes calldata _orderUserSig, TraderParams calldata _params, CoordinatorParams calldata _crdParams @@ -85,5 +85,5 @@ interface ISignalBuyContract { /// @notice Only user proxy can call /// @param _order The order that is going to be cancelled /// @param _cancelUserSig The cancelling signature signed by user - function cancelSignalBuy(SignalBuyContractLibEIP712.Order calldata _order, bytes calldata _cancelUserSig) external; + function cancelSignalBuy(Order calldata _order, bytes calldata _cancelUserSig) external; } diff --git a/contracts/utils/SignalBuyContractLibEIP712.sol b/contracts/utils/SignalBuyContractLibEIP712.sol index ef8e5c82..44fc45fe 100644 --- a/contracts/utils/SignalBuyContractLibEIP712.sol +++ b/contracts/utils/SignalBuyContractLibEIP712.sol @@ -1,114 +1,82 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.7.6; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "../interfaces/ISignalBuyContract.sol"; +struct Order { + IERC20 userToken; + IERC20 dealerToken; + uint256 userTokenAmount; + uint256 minDealerTokenAmount; + address user; + address dealer; + uint256 salt; + uint64 expiry; +} + +string constant ORDER_TYPESTRING = "Order(address userToken,address dealerToken,uint256 userTokenAmount,uint256 minDealerTokenAmount,address user,address dealer,uint256 salt,uint64 expiry)"; -library SignalBuyContractLibEIP712 { - struct Order { - IERC20 userToken; - IERC20 dealerToken; - uint256 userTokenAmount; - uint256 minDealerTokenAmount; - address user; - address dealer; - uint256 salt; - uint64 expiry; - } +bytes32 constant ORDER_TYPEHASH = keccak256(bytes(ORDER_TYPESTRING)); - /* +function getOrderStructHash(Order memory _order) pure returns (bytes32) { + return keccak256( - abi.encodePacked( - "Order(", - "address userToken,", - "address dealerToken,", - "uint256 userTokenAmount,", - "uint256 minDealerTokenAmount,", - "address user,", - "address dealer,", - "uint256 salt,", - "uint64 expiry", - ")" + abi.encode( + ORDER_TYPEHASH, + address(_order.userToken), + address(_order.dealerToken), + _order.userTokenAmount, + _order.minDealerTokenAmount, + _order.user, + _order.dealer, + _order.salt, + _order.expiry ) ); - */ - bytes32 private constant ORDER_TYPEHASH = 0xf3ab25d0577fbc8769db2380dba0706d4977c70ca7b697c4677d88bbc972fbce; +} - function _getOrderStructHash(Order memory _order) internal pure returns (bytes32) { - return - keccak256( - abi.encode( - ORDER_TYPEHASH, - address(_order.userToken), - address(_order.dealerToken), - _order.userTokenAmount, - _order.minDealerTokenAmount, - _order.user, - _order.dealer, - _order.salt, - _order.expiry - ) - ); - } +struct Fill { + bytes32 orderHash; // EIP712 hash + address dealer; + address recipient; + uint256 userTokenAmount; + uint256 dealerTokenAmount; + uint256 dealerSalt; + uint64 expiry; +} - struct Fill { - bytes32 orderHash; // EIP712 hash - address dealer; - address recipient; - uint256 userTokenAmount; - uint256 dealerTokenAmount; - uint256 dealerSalt; - uint64 expiry; - } +string constant FILL_TYPESTRING = "Fill(bytes32 orderHash,address dealer,address recipient,uint256 userTokenAmount,uint256 dealerTokenAmount,uint256 dealerSalt,uint64 expiry)"; - /* +bytes32 constant FILL_TYPEHASH = keccak256(bytes(FILL_TYPESTRING)); + +function getFillStructHash(Fill memory _fill) pure returns (bytes32) { + return keccak256( - abi.encodePacked( - "Fill(", - "bytes32 orderHash,", - "address dealer,", - "address recipient,", - "uint256 userTokenAmount,", - "uint256 dealerTokenAmount,", - "uint256 dealerSalt,", - "uint64 expiry", - ")" + abi.encode( + FILL_TYPEHASH, + _fill.orderHash, + _fill.dealer, + _fill.recipient, + _fill.userTokenAmount, + _fill.dealerTokenAmount, + _fill.dealerSalt, + _fill.expiry ) ); - */ - bytes32 private constant FILL_TYPEHASH = 0xd368a73a41233a76912e96676a984799852399878d2dc3ae8ddd0480b42aec88; +} - function _getFillStructHash(Fill memory _fill) internal pure returns (bytes32) { - return - keccak256( - abi.encode( - FILL_TYPEHASH, - _fill.orderHash, - _fill.dealer, - _fill.recipient, - _fill.userTokenAmount, - _fill.dealerTokenAmount, - _fill.dealerSalt, - _fill.expiry - ) - ); - } +struct AllowFill { + bytes32 orderHash; // EIP712 hash + address executor; + uint256 fillAmount; + uint256 salt; + uint64 expiry; +} - struct AllowFill { - bytes32 orderHash; // EIP712 hash - address executor; - uint256 fillAmount; - uint256 salt; - uint64 expiry; - } +string constant ALLOW_FILL_TYPESTRING = "AllowFill(bytes32 orderHash,address executor,uint256 fillAmount,uint256 salt,uint64 expiry)"; - /* - keccak256(abi.encodePacked("AllowFill(", "bytes32 orderHash,", "address executor,", "uint256 fillAmount,", "uint256 salt,", "uint64 expiry", ")")); - */ - bytes32 private constant ALLOW_FILL_TYPEHASH = 0xa471a3189b88889758f25ee2ce05f58964c40b03edc9cc9066079fd2b547f074; +bytes32 constant ALLOW_FILL_TYPEHASH = keccak256(bytes(ALLOW_FILL_TYPESTRING)); - function _getAllowFillStructHash(AllowFill memory _allowFill) internal pure returns (bytes32) { - return keccak256(abi.encode(ALLOW_FILL_TYPEHASH, _allowFill.orderHash, _allowFill.executor, _allowFill.fillAmount, _allowFill.salt, _allowFill.expiry)); - } +function getAllowFillStructHash(AllowFill memory _allowFill) pure returns (bytes32) { + return keccak256(abi.encode(ALLOW_FILL_TYPEHASH, _allowFill.orderHash, _allowFill.executor, _allowFill.fillAmount, _allowFill.salt, _allowFill.expiry)); } diff --git a/test/forkMainnet/SignalBuyContract.t.sol b/test/forkMainnet/SignalBuyContract.t.sol index 160d8792..405b473d 100644 --- a/test/forkMainnet/SignalBuyContract.t.sol +++ b/test/forkMainnet/SignalBuyContract.t.sol @@ -10,7 +10,7 @@ import "@openzeppelin/contracts/math/SafeMath.sol"; import "contracts/SignalBuyContract.sol"; import "contracts/interfaces/ISignalBuyContract.sol"; import "contracts/utils/SignatureValidator.sol"; -import "contracts/utils/SignalBuyContractLibEIP712.sol"; +import { Order, getOrderStructHash, Fill, getFillStructHash, AllowFill, getAllowFillStructHash } from "contracts/utils/SignalBuyContractLibEIP712.sol"; import "contracts/utils/LibConstant.sol"; import "test/mocks/MockERC1271Wallet.sol"; @@ -47,11 +47,11 @@ contract SignalBuyContractTest is BalanceUtil { address[] allowanceAddrs; address[] DEFAULT_AMM_PATH; - SignalBuyContractLibEIP712.Order DEFAULT_ORDER; + Order DEFAULT_ORDER; bytes32 DEFAULT_ORDER_HASH; bytes DEFAULT_ORDER_MAKER_SIG; - SignalBuyContractLibEIP712.Fill DEFAULT_FILL; - SignalBuyContractLibEIP712.AllowFill DEFAULT_ALLOW_FILL; + Fill DEFAULT_FILL; + AllowFill DEFAULT_ALLOW_FILL; uint16 DEFAULT_GAS_FEE_FACTOR = 0; uint16 DEFAULT_PIONEX_STRATEGY_FEE_FACTOR = 0; ISignalBuyContract.TraderParams DEFAULT_TRADER_PARAMS; @@ -70,7 +70,7 @@ contract SignalBuyContractTest is BalanceUtil { allowanceAddrs = DEFAULT_AMM_PATH; // Default params - DEFAULT_ORDER = SignalBuyContractLibEIP712.Order( + DEFAULT_ORDER = Order( dai, // userToken usdt, // dealerToken 100 * 1e18, // userTokenAmount @@ -80,17 +80,9 @@ contract SignalBuyContractTest is BalanceUtil { uint256(1001), // salt DEADLINE // expiry ); - DEFAULT_ORDER_HASH = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(DEFAULT_ORDER)); + DEFAULT_ORDER_HASH = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(DEFAULT_ORDER)); DEFAULT_ORDER_MAKER_SIG = _signOrder(userPrivateKey, DEFAULT_ORDER, SignatureValidator.SignatureType.EIP712); - DEFAULT_FILL = SignalBuyContractLibEIP712.Fill( - DEFAULT_ORDER_HASH, - dealer, - receiver, - DEFAULT_ORDER.userTokenAmount, - DEFAULT_ORDER.minDealerTokenAmount, - uint256(1002), - DEADLINE - ); + DEFAULT_FILL = Fill(DEFAULT_ORDER_HASH, dealer, receiver, DEFAULT_ORDER.userTokenAmount, DEFAULT_ORDER.minDealerTokenAmount, uint256(1002), DEADLINE); DEFAULT_TRADER_PARAMS = ISignalBuyContract.TraderParams( dealer, // dealer receiver, // recipient @@ -102,7 +94,7 @@ contract SignalBuyContractTest is BalanceUtil { DEADLINE, // expiry _signFill(dealerPrivateKey, DEFAULT_FILL, SignatureValidator.SignatureType.EIP712) // dealerSig ); - DEFAULT_ALLOW_FILL = SignalBuyContractLibEIP712.AllowFill( + DEFAULT_ALLOW_FILL = AllowFill( DEFAULT_ORDER_HASH, // orderHash dealer, // executor DEFAULT_FILL.dealerTokenAmount, // fillAmount @@ -295,14 +287,14 @@ contract SignalBuyContractTest is BalanceUtil { signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); // Try to fill the default order, should fail - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.dealerSalt = uint256(8001); ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); traderParams.salt = fill.dealerSalt; - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.salt = uint256(8002); ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -314,19 +306,19 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotFillExpiredOrderByTrader() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; order.expiry = uint64(block.timestamp - 1); - bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -352,20 +344,20 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotFillByTraderWithTakerOtherThanOrderSpecified() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = coordinator; - bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; // dealer try to fill this order traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -376,7 +368,7 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotFillByTraderWithExpiredFill() public { - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.expiry = uint64(block.timestamp - 1); ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; @@ -392,7 +384,7 @@ contract SignalBuyContractTest is BalanceUtil { signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); // Try to fill with same fill request with differnt allowFill (otherwise will revert by dup allowFill) - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.salt = uint256(9001); ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -408,7 +400,7 @@ contract SignalBuyContractTest is BalanceUtil { ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerTokenAmount = DEFAULT_TRADER_PARAMS.dealerTokenAmount.mul(2); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -427,7 +419,7 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotFillByTraderWithExpiredAllowFill() public { - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.expiry = uint64(block.timestamp - 1); ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -440,7 +432,7 @@ contract SignalBuyContractTest is BalanceUtil { function testCannotFillByTraderWithAlteredOrderHash() public { // Replace orderHash in allowFill - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = bytes32(0); ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -452,7 +444,7 @@ contract SignalBuyContractTest is BalanceUtil { function testCannotFillByTraderWithAlteredExecutor() public { // Set the executor to user (not dealer) - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = user; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -465,7 +457,7 @@ contract SignalBuyContractTest is BalanceUtil { function testCannotFillByTraderWithAlteredFillAmount() public { // Change fill amount in allow fill - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = DEFAULT_ALLOW_FILL.fillAmount.div(2); ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -488,7 +480,7 @@ contract SignalBuyContractTest is BalanceUtil { // Fill with default allow fill signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.dealerSalt = uint256(8001); ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; @@ -507,7 +499,7 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotFillByTraderWithWorseTakerMakerTokenRatio() public { - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; // Increase user token amount so the dealerToken/userToken ratio is worse than order's dealerToken/userToken ratio fill.userTokenAmount = DEFAULT_FILL.userTokenAmount.add(1); @@ -542,7 +534,7 @@ contract SignalBuyContractTest is BalanceUtil { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(DEFAULT_ALLOW_FILL)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(DEFAULT_ALLOW_FILL)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -579,7 +571,7 @@ contract SignalBuyContractTest is BalanceUtil { signalBuyContract.activateFactors(); vm.stopPrank(); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for tokenlon fee fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(115).div(100); // 15% more @@ -588,7 +580,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -599,7 +591,7 @@ contract SignalBuyContractTest is BalanceUtil { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -629,7 +621,7 @@ contract SignalBuyContractTest is BalanceUtil { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for gas fee and dealer strategy fee fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(11).div(10); // 10% more @@ -640,7 +632,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -651,7 +643,7 @@ contract SignalBuyContractTest is BalanceUtil { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -681,7 +673,7 @@ contract SignalBuyContractTest is BalanceUtil { BalanceSnapshot.Snapshot memory fcMakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.userToken)); BalanceSnapshot.Snapshot memory fcTakerAsset = BalanceSnapshot.take(feeCollector, address(DEFAULT_ORDER.dealerToken)); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio fill.dealerTokenAmount = DEFAULT_FILL.dealerTokenAmount.mul(11).div(10); // 10% more @@ -689,7 +681,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -700,7 +692,7 @@ contract SignalBuyContractTest is BalanceUtil { DEFAULT_ORDER_HASH, DEFAULT_ORDER.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), traderParams.recipient, ISignalBuyContract.FillReceipt( address(DEFAULT_ORDER.userToken), @@ -724,14 +716,14 @@ contract SignalBuyContractTest is BalanceUtil { function testFullyFillByContractWalletTrader() public { // Contract mockERC1271Wallet as dealer which always return valid ERC-1271 magic value no matter what. - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.dealer = address(mockERC1271Wallet); ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealer = address(mockERC1271Wallet); traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.WalletBytes32); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.executor = address(mockERC1271Wallet); ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -741,19 +733,19 @@ contract SignalBuyContractTest is BalanceUtil { } function testFillBySpecificTaker() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = dealer; - bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -763,19 +755,19 @@ contract SignalBuyContractTest is BalanceUtil { } function testFillBySpecificTakerWithOldEIP712Method() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; // order specify dealer address order.dealer = dealer; - bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + bytes32 orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); bytes memory orderMakerSig = _signOrderWithOldEIP712Method(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; fill.orderHash = orderHash; ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerSig = _signFillWithOldEIP712Method(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.orderHash = orderHash; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -790,7 +782,7 @@ contract SignalBuyContractTest is BalanceUtil { BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); fill.dealerTokenAmount = DEFAULT_ORDER.minDealerTokenAmount.mul(2); @@ -800,7 +792,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = fill.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -821,7 +813,7 @@ contract SignalBuyContractTest is BalanceUtil { BalanceSnapshot.Snapshot memory userTakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.dealerToken)); BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; + Fill memory fill = DEFAULT_FILL; // set the fill amount to 2x of order quota fill.userTokenAmount = DEFAULT_ORDER.userTokenAmount.mul(2); fill.dealerTokenAmount = DEFAULT_ORDER.minDealerTokenAmount.mul(2).mul(11).div(10); // 10% more @@ -831,7 +823,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; allowFill.fillAmount = fill.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -853,7 +845,7 @@ contract SignalBuyContractTest is BalanceUtil { BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); // First fill amount : 9 USDT - SignalBuyContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + Fill memory fill1 = DEFAULT_FILL; fill1.userTokenAmount = 10 * 1e18; fill1.dealerTokenAmount = 9 * 1e6; ISignalBuyContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; @@ -861,7 +853,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams1.dealerTokenAmount = fill1.dealerTokenAmount; traderParams1.dealerSig = _signFill(dealerPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; allowFill1.fillAmount = fill1.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; @@ -870,7 +862,7 @@ contract SignalBuyContractTest is BalanceUtil { signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); // Second fill amount : 36 USDT - SignalBuyContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + Fill memory fill2 = DEFAULT_FILL; fill2.userTokenAmount = 40 * 1e18; fill2.dealerTokenAmount = 36 * 1e6; @@ -879,7 +871,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams2.dealerTokenAmount = fill2.dealerTokenAmount; traderParams2.dealerSig = _signFill(dealerPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; allowFill2.fillAmount = fill2.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; @@ -901,7 +893,7 @@ contract SignalBuyContractTest is BalanceUtil { BalanceSnapshot.Snapshot memory userMakerAsset = BalanceSnapshot.take(user, address(DEFAULT_ORDER.userToken)); // First fill amount : 9 USDT and same dealerToken/userToken ratio - SignalBuyContractLibEIP712.Fill memory fill1 = DEFAULT_FILL; + Fill memory fill1 = DEFAULT_FILL; fill1.userTokenAmount = 10 * 1e18; fill1.dealerTokenAmount = 9 * 1e6; ISignalBuyContract.TraderParams memory traderParams1 = DEFAULT_TRADER_PARAMS; @@ -909,7 +901,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams1.dealerTokenAmount = fill1.dealerTokenAmount; traderParams1.dealerSig = _signFill(dealerPrivateKey, fill1, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill1 = DEFAULT_ALLOW_FILL; allowFill1.fillAmount = fill1.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams1 = DEFAULT_CRD_PARAMS; @@ -918,7 +910,7 @@ contract SignalBuyContractTest is BalanceUtil { signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams1, crdParams1); // Second fill amount : 36 USDT and better dealerToken/userToken ratio - SignalBuyContractLibEIP712.Fill memory fill2 = DEFAULT_FILL; + Fill memory fill2 = DEFAULT_FILL; fill2.userTokenAmount = 40 * 1e18; fill2.dealerTokenAmount = uint256(36 * 1e6).mul(11).div(10); // 10% more @@ -927,7 +919,7 @@ contract SignalBuyContractTest is BalanceUtil { traderParams2.dealerTokenAmount = fill2.dealerTokenAmount; traderParams2.dealerSig = _signFill(dealerPrivateKey, fill2, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; + AllowFill memory allowFill2 = DEFAULT_ALLOW_FILL; allowFill2.fillAmount = fill2.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams2 = DEFAULT_CRD_PARAMS; @@ -955,21 +947,21 @@ contract SignalBuyContractTest is BalanceUtil { ETHandWETHAssetSnapshot assetSnapshots; function testSettlementETHToETHWithNoFee() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; order.dealerToken = IERC20(LibConstant.ETH_ADDRESS); order.minDealerTokenAmount = 1e18; bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); fill.dealerTokenAmount = order.minDealerTokenAmount; ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -988,10 +980,10 @@ contract SignalBuyContractTest is BalanceUtil { // Case 2: Tx succeeded vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)), order.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(order.userToken), @@ -1013,21 +1005,21 @@ contract SignalBuyContractTest is BalanceUtil { } function testSettlementWETHToWETHWithNoFee() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; order.dealerToken = weth; order.minDealerTokenAmount = 1e18; bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); fill.dealerTokenAmount = order.minDealerTokenAmount; ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -1046,10 +1038,10 @@ contract SignalBuyContractTest is BalanceUtil { // Case 2: Tx succeeded vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)), order.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(order.userToken), @@ -1078,13 +1070,13 @@ contract SignalBuyContractTest is BalanceUtil { signalBuyContract.activateFactors(); vm.stopPrank(); - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; order.dealerToken = weth; order.minDealerTokenAmount = 1e18; bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for tokenlon fee fill.dealerTokenAmount = order.minDealerTokenAmount.mul(115).div(100); // 15% more @@ -1093,8 +1085,8 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -1113,10 +1105,10 @@ contract SignalBuyContractTest is BalanceUtil { // Case 2: Tx succeeded vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)), order.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(order.userToken), @@ -1138,13 +1130,13 @@ contract SignalBuyContractTest is BalanceUtil { } function testSettlementWETHToETHWithAddedGasFeeAndStrategyFee() public { - SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER; + Order memory order = DEFAULT_ORDER; order.dealerToken = IERC20(LibConstant.ETH_ADDRESS); order.minDealerTokenAmount = 1e18; bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL; - fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + Fill memory fill = DEFAULT_FILL; + fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); // Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio // to account for gas fee and dealer strategy fee fill.dealerTokenAmount = order.minDealerTokenAmount.mul(11).div(10); // 10% more @@ -1155,8 +1147,8 @@ contract SignalBuyContractTest is BalanceUtil { traderParams.dealerTokenAmount = fill.dealerTokenAmount; traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); - SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL; - allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)); + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)); allowFill.fillAmount = traderParams.dealerTokenAmount; ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; @@ -1175,10 +1167,10 @@ contract SignalBuyContractTest is BalanceUtil { // Case 2: Tx succeeded vm.expectEmit(true, true, true, true); emit SignalBuyFilledByTrader( - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getOrderStructHash(order)), order.user, dealer, - getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)), + getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), getAllowFillStructHash(allowFill)), DEFAULT_TRADER_PARAMS.recipient, ISignalBuyContract.FillReceipt( address(order.userToken), @@ -1204,7 +1196,7 @@ contract SignalBuyContractTest is BalanceUtil { *********************************/ function testCannotFillCanceledOrder() public { - SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; bytes memory cancelSig = _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712); @@ -1215,7 +1207,7 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotCancelIfNotMaker() public { - SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; bytes memory cancelSig = _signOrder(dealerPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712); @@ -1224,7 +1216,7 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotCancelExpiredOrder() public { - SignalBuyContractLibEIP712.Order memory expiredOrder = DEFAULT_ORDER; + Order memory expiredOrder = DEFAULT_ORDER; expiredOrder.expiry = 0; bytes memory cancelSig = _signOrder(userPrivateKey, expiredOrder, SignatureValidator.SignatureType.EIP712); @@ -1233,7 +1225,7 @@ contract SignalBuyContractTest is BalanceUtil { } function testCannotCancelTwice() public { - SignalBuyContractLibEIP712.Order memory zeroOrder = DEFAULT_ORDER; + Order memory zeroOrder = DEFAULT_ORDER; zeroOrder.minDealerTokenAmount = 0; bytes memory cancelSig = _signOrder(userPrivateKey, zeroOrder, SignatureValidator.SignatureType.EIP712); @@ -1245,9 +1237,9 @@ contract SignalBuyContractTest is BalanceUtil { function _signOrderEIP712( address limitOrderAddr, uint256 privateKey, - SignalBuyContractLibEIP712.Order memory order + Order memory order ) internal returns (bytes memory sig) { - bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); + bytes32 orderHash = getOrderStructHash(order); bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), orderHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); @@ -1256,9 +1248,9 @@ contract SignalBuyContractTest is BalanceUtil { function _signFillEIP712( address limitOrderAddr, uint256 privateKey, - SignalBuyContractLibEIP712.Fill memory fill + Fill memory fill ) internal returns (bytes memory sig) { - bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); + bytes32 fillHash = getFillStructHash(fill); bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), fillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); @@ -1267,9 +1259,9 @@ contract SignalBuyContractTest is BalanceUtil { function _signAllowFillEIP712( address limitOrderAddr, uint256 privateKey, - SignalBuyContractLibEIP712.AllowFill memory allowFill + AllowFill memory allowFill ) internal returns (bytes memory sig) { - bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 allowFillHash = getAllowFillStructHash(allowFill); bytes32 EIP712SignDigest = getEIP712Hash(computeMainnetEIP712DomainSeparator(limitOrderAddr), allowFillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, bytes32(0), uint8(2)); @@ -1302,10 +1294,10 @@ contract SignalBuyContractTest is BalanceUtil { function _signOrder( uint256 privateKey, - SignalBuyContractLibEIP712.Order memory order, + Order memory order, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); + bytes32 orderHash = getOrderStructHash(order); bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), orderHash); if (sigType == SignatureValidator.SignatureType.EIP712) { @@ -1321,10 +1313,10 @@ contract SignalBuyContractTest is BalanceUtil { function _signOrderWithOldEIP712Method( uint256 privateKey, - SignalBuyContractLibEIP712.Order memory order, + Order memory order, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 orderHash = SignalBuyContractLibEIP712._getOrderStructHash(order); + bytes32 orderHash = getOrderStructHash(order); bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), orderHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1333,10 +1325,10 @@ contract SignalBuyContractTest is BalanceUtil { function _signFill( uint256 privateKey, - SignalBuyContractLibEIP712.Fill memory fill, + Fill memory fill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); + bytes32 fillHash = getFillStructHash(fill); bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), fillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); @@ -1344,10 +1336,10 @@ contract SignalBuyContractTest is BalanceUtil { function _signFillWithOldEIP712Method( uint256 privateKey, - SignalBuyContractLibEIP712.Fill memory fill, + Fill memory fill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 fillHash = SignalBuyContractLibEIP712._getFillStructHash(fill); + bytes32 fillHash = getFillStructHash(fill); bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), fillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); @@ -1356,10 +1348,10 @@ contract SignalBuyContractTest is BalanceUtil { function _signAllowFill( uint256 privateKey, - SignalBuyContractLibEIP712.AllowFill memory allowFill, + AllowFill memory allowFill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 allowFillHash = getAllowFillStructHash(allowFill); bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); sig = abi.encodePacked(r, s, v, uint8(sigType)); @@ -1367,10 +1359,10 @@ contract SignalBuyContractTest is BalanceUtil { function _signAllowFillWithOldEIP712Method( uint256 privateKey, - SignalBuyContractLibEIP712.AllowFill memory allowFill, + AllowFill memory allowFill, SignatureValidator.SignatureType sigType ) internal returns (bytes memory sig) { - bytes32 allowFillHash = SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill); + bytes32 allowFillHash = getAllowFillStructHash(allowFill); bytes32 EIP712SignDigest = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), allowFillHash); require(sigType == SignatureValidator.SignatureType.EIP712, "Invalid signature type"); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, EIP712SignDigest); From 2cd05c23c450f4f94cbfbcf81b27cb4da92ed0eb Mon Sep 17 00:00:00 2001 From: Charles Jhong Date: Mon, 14 Aug 2023 15:57:59 +0800 Subject: [PATCH 38/41] fix solidity lint --- contracts/utils/SignalBuyContractLibEIP712.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/utils/SignalBuyContractLibEIP712.sol b/contracts/utils/SignalBuyContractLibEIP712.sol index 44fc45fe..d0b36676 100644 --- a/contracts/utils/SignalBuyContractLibEIP712.sol +++ b/contracts/utils/SignalBuyContractLibEIP712.sol @@ -18,6 +18,7 @@ string constant ORDER_TYPESTRING = "Order(address userToken,address dealerToken, bytes32 constant ORDER_TYPEHASH = keccak256(bytes(ORDER_TYPESTRING)); +// solhint-disable-next-line func-visibility function getOrderStructHash(Order memory _order) pure returns (bytes32) { return keccak256( @@ -49,6 +50,7 @@ string constant FILL_TYPESTRING = "Fill(bytes32 orderHash,address dealer,address bytes32 constant FILL_TYPEHASH = keccak256(bytes(FILL_TYPESTRING)); +// solhint-disable-next-line func-visibility function getFillStructHash(Fill memory _fill) pure returns (bytes32) { return keccak256( @@ -77,6 +79,7 @@ string constant ALLOW_FILL_TYPESTRING = "AllowFill(bytes32 orderHash,address exe bytes32 constant ALLOW_FILL_TYPEHASH = keccak256(bytes(ALLOW_FILL_TYPESTRING)); +// solhint-disable-next-line func-visibility function getAllowFillStructHash(AllowFill memory _allowFill) pure returns (bytes32) { return keccak256(abi.encode(ALLOW_FILL_TYPEHASH, _allowFill.orderHash, _allowFill.executor, _allowFill.fillAmount, _allowFill.salt, _allowFill.expiry)); } From a01444267e5fe36a7d3332e18ba2de286eb81e41 Mon Sep 17 00:00:00 2001 From: Charles Jhong Date: Wed, 16 Aug 2023 15:31:59 +0800 Subject: [PATCH 39/41] fix IWETH import path --- contracts/SignalBuyContract.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index 00e2c9e4..a39d778e 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -9,7 +9,7 @@ import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "./interfaces/ISignalBuyContract.sol"; -import "./interfaces/IWeth.sol"; +import "./interfaces/IWETH.sol"; import { Asset } from "./utils/Asset.sol"; import "./utils/BaseLibEIP712.sol"; import "./utils/LibConstant.sol"; From b4082caa251fcc3a924b6e0c0d6b6ef28ba62c6a Mon Sep 17 00:00:00 2001 From: Charles Jhong Date: Mon, 11 Sep 2023 15:32:21 +0800 Subject: [PATCH 40/41] fix allowFill seen check --- contracts/SignalBuyContract.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index a39d778e..d7344062 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -229,7 +229,7 @@ contract SignalBuyContract is ISignalBuyContract, BaseLibEIP712, SignatureValida AllowFill({ orderHash: _orderHash, executor: _executor, fillAmount: _fillAmount, salt: _crdParams.salt, expiry: _crdParams.expiry }) ) ); - require(!LibSignalBuyContractOrderStorage.getStorage().fillSeen[allowFillHash], "SignalBuyContract: AllowFill seen before"); + require(!LibSignalBuyContractOrderStorage.getStorage().allowFillSeen[allowFillHash], "SignalBuyContract: AllowFill seen before"); require(isValidSignature(coordinator, allowFillHash, bytes(""), _crdParams.sig), "SignalBuyContract: AllowFill is not signed by coordinator"); // Set allow fill seen to avoid replay attack From 095161643bcd6d026d9703cbb80bf0f945dba08e Mon Sep 17 00:00:00 2001 From: Charles Jhong Date: Mon, 11 Sep 2023 16:02:26 +0800 Subject: [PATCH 41/41] fix replay sig tests and import style --- contracts/SignalBuyContract.sol | 26 ++++++++++++------------ test/forkMainnet/SignalBuyContract.t.sol | 19 ++++++++++++----- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/contracts/SignalBuyContract.sol b/contracts/SignalBuyContract.sol index d7344062..6798ee5b 100644 --- a/contracts/SignalBuyContract.sol +++ b/contracts/SignalBuyContract.sol @@ -2,21 +2,21 @@ pragma solidity 0.7.6; pragma abicoder v2; -import "@openzeppelin/contracts/math/Math.sol"; -import "@openzeppelin/contracts/math/SafeMath.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; -import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; - -import "./interfaces/ISignalBuyContract.sol"; -import "./interfaces/IWETH.sol"; +import { Math } from "@openzeppelin/contracts/math/Math.sol"; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; +import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; + +import { ISignalBuyContract } from "./interfaces/ISignalBuyContract.sol"; +import { IWETH } from "./interfaces/IWETH.sol"; import { Asset } from "./utils/Asset.sol"; -import "./utils/BaseLibEIP712.sol"; -import "./utils/LibConstant.sol"; -import "./utils/LibSignalBuyContractOrderStorage.sol"; -import "./utils/Ownable.sol"; +import { BaseLibEIP712 } from "./utils/BaseLibEIP712.sol"; +import { LibConstant } from "./utils/LibConstant.sol"; +import { LibSignalBuyContractOrderStorage } from "./utils/LibSignalBuyContractOrderStorage.sol"; +import { Ownable } from "./utils/Ownable.sol"; import { Order, getOrderStructHash, Fill, getFillStructHash, AllowFill, getAllowFillStructHash } from "./utils/SignalBuyContractLibEIP712.sol"; -import "./utils/SignatureValidator.sol"; +import { SignatureValidator } from "./utils/SignatureValidator.sol"; /// @title SignalBuy Contract /// @notice Order can be filled as long as the provided dealerToken/userToken ratio is better than or equal to user's specfied dealerToken/userToken ratio. diff --git a/test/forkMainnet/SignalBuyContract.t.sol b/test/forkMainnet/SignalBuyContract.t.sol index 405b473d..cb7ec435 100644 --- a/test/forkMainnet/SignalBuyContract.t.sol +++ b/test/forkMainnet/SignalBuyContract.t.sol @@ -480,14 +480,23 @@ contract SignalBuyContractTest is BalanceUtil { // Fill with default allow fill signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); - Fill memory fill = DEFAULT_FILL; - fill.dealerSalt = uint256(8001); + vm.expectRevert("SignalBuyContract: AllowFill seen before"); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + } - ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS; - traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712); + function testCannotFillByTraderWithReplayedFill() public { + // Fill with default allow fill + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, DEFAULT_CRD_PARAMS); + + AllowFill memory allowFill = DEFAULT_ALLOW_FILL; + allowFill.salt = allowFill.salt + 1; + + ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS; + crdParams.salt = allowFill.salt; + crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712); vm.expectRevert("SignalBuyContract: Fill seen before"); - signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, traderParams, DEFAULT_CRD_PARAMS); + signalBuyContract.fillSignalBuy(DEFAULT_ORDER, DEFAULT_ORDER_MAKER_SIG, DEFAULT_TRADER_PARAMS, crdParams); } function testCannotFillByZeroTrader() public {