@0x:contracts-exchange
Added protocol fees to fillOrders and matchOrders
This commit is contained in:
@@ -52,12 +52,10 @@ library LibFillResults {
|
||||
/// @dev Calculates amounts filled and fees paid by maker and taker.
|
||||
/// @param order to be filled.
|
||||
/// @param takerAssetFilledAmount Amount of takerAsset that will be filled.
|
||||
/// @param protocolFeeMultiplier The multiplier used to calculate protocol fees.
|
||||
/// @return fillResults Amounts filled and fees paid by maker and taker.
|
||||
function calculateFillResults(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 protocolFeeMultiplier
|
||||
uint256 takerAssetFilledAmount
|
||||
)
|
||||
internal
|
||||
view
|
||||
@@ -81,9 +79,6 @@ library LibFillResults {
|
||||
order.takerFee
|
||||
);
|
||||
|
||||
// Compute the protocol fee for a single fill.
|
||||
fillResults.protocolFeePaid = tx.gasprice.safeMul(protocolFeeMultiplier);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
@@ -95,7 +90,6 @@ library LibFillResults {
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftOrderTakerAssetFilledAmount Amount of left order already filled.
|
||||
/// @param rightOrderTakerAssetFilledAmount Amount of right order already filled.
|
||||
/// @param protocolFeeMultiplier The multiplier used to calculate protocol fees.
|
||||
/// @param shouldMaximallyFillOrders A value that indicates whether or not this calculation should use
|
||||
/// the maximal fill order matching strategy.
|
||||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders.
|
||||
@@ -104,7 +98,6 @@ library LibFillResults {
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount,
|
||||
uint256 protocolFeeMultiplier,
|
||||
bool shouldMaximallyFillOrders
|
||||
)
|
||||
internal
|
||||
@@ -170,11 +163,6 @@ library LibFillResults {
|
||||
rightOrder.takerFee
|
||||
);
|
||||
|
||||
// Compute the protocol fees
|
||||
uint256 protocolFee = tx.gasprice.safeMul(protocolFeeMultiplier);
|
||||
matchedFillResults.left.protocolFeePaid = protocolFee;
|
||||
matchedFillResults.right.protocolFeePaid = protocolFee;
|
||||
|
||||
// Return fill results
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
@@ -29,14 +29,13 @@ contract TestLibFillResults {
|
||||
|
||||
function calculateFillResults(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFilledAmount,
|
||||
uint256 protocolFeeMultiplier
|
||||
uint256 takerAssetFilledAmount
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
fillResults = LibFillResults.calculateFillResults(order, takerAssetFilledAmount, protocolFeeMultiplier);
|
||||
fillResults = LibFillResults.calculateFillResults(order, takerAssetFilledAmount);
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
@@ -45,7 +44,6 @@ contract TestLibFillResults {
|
||||
LibOrder.Order memory rightOrder,
|
||||
uint256 leftOrderTakerAssetFilledAmount,
|
||||
uint256 rightOrderTakerAssetFilledAmount,
|
||||
uint256 protocolFeeMultiplier,
|
||||
bool shouldMaximallyFillOrders
|
||||
)
|
||||
public
|
||||
@@ -57,7 +55,6 @@ contract TestLibFillResults {
|
||||
rightOrder,
|
||||
leftOrderTakerAssetFilledAmount,
|
||||
rightOrderTakerAssetFilledAmount,
|
||||
protocolFeeMultiplier,
|
||||
shouldMaximallyFillOrders
|
||||
);
|
||||
return matchedFillResults;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
"evmVersion": "constantinople",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
"runs": 15000,
|
||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||
},
|
||||
"outputSelection": {
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/interfaces/IExchange.sol";
|
||||
@@ -89,7 +89,7 @@ contract ExchangeWrapper is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
refundFinalBalance
|
||||
{
|
||||
address takerAddress = msg.sender;
|
||||
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/interfaces/IExchange.sol";
|
||||
@@ -104,7 +104,7 @@ contract Whitelist is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
refundFinalBalance
|
||||
{
|
||||
address takerAddress = msg.sender;
|
||||
|
||||
|
@@ -35,12 +35,12 @@ import "./MixinSignatureValidator.sol";
|
||||
|
||||
|
||||
contract MixinExchangeCore is
|
||||
IExchangeCore,
|
||||
Refundable,
|
||||
LibEIP712ExchangeDomain,
|
||||
IExchangeCore,
|
||||
MixinAssetProxyDispatcher,
|
||||
MixinSignatureValidator,
|
||||
MixinProtocolFees
|
||||
MixinProtocolFees,
|
||||
MixinSignatureValidator
|
||||
{
|
||||
using LibOrder for LibOrder.Order;
|
||||
using LibSafeMath for uint256;
|
||||
@@ -103,7 +103,7 @@ contract MixinExchangeCore is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
fillResults = _fillOrder(
|
||||
@@ -217,10 +217,18 @@ contract MixinExchangeCore is
|
||||
uint256 takerAssetFilledAmount = LibSafeMath.min256(takerAssetFillAmount, remainingTakerAssetAmount);
|
||||
|
||||
// Compute proportional fill amounts
|
||||
fillResults = LibFillResults.calculateFillResults(order, takerAssetFilledAmount, protocolFeeMultiplier);
|
||||
fillResults = LibFillResults.calculateFillResults(order, takerAssetFilledAmount);
|
||||
|
||||
bytes32 orderHash = orderInfo.orderHash;
|
||||
|
||||
// Settle order
|
||||
_settleOrder(
|
||||
orderHash,
|
||||
order,
|
||||
takerAddress,
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Update exchange internal state
|
||||
_updateFilledState(
|
||||
order,
|
||||
@@ -230,14 +238,6 @@ contract MixinExchangeCore is
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Settle order
|
||||
_settleOrder(
|
||||
orderHash,
|
||||
order,
|
||||
takerAddress,
|
||||
fillResults
|
||||
);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
@@ -462,25 +462,26 @@ contract MixinExchangeCore is
|
||||
);
|
||||
|
||||
// Transfer protocol fee -> staking if the fee should be paid
|
||||
if (staking != address(0)) {
|
||||
// If sufficient ether was sent to the contract, the protocol fee should be paid in ETH.
|
||||
// Otherwise the fee should be paid in WETH.
|
||||
uint256 protocolFee = fillResults.protocolFeePaid;
|
||||
if (address(this).balance >= protocolFee) {
|
||||
IStaking(staking).payProtocolFee.value(protocolFee)(order.makerAddress);
|
||||
} else {
|
||||
// Transfer the Weth
|
||||
_dispatchTransferFrom(
|
||||
orderHash,
|
||||
WETH_ASSET_DATA,
|
||||
takerAddress,
|
||||
staking,
|
||||
protocolFee
|
||||
);
|
||||
address feeCollector = protocolFeeCollector;
|
||||
if (feeCollector != address(0)) {
|
||||
// Create a stack variable to hold the value that will be sent so that the gas optimization of
|
||||
// only having one call statement can be implemented.
|
||||
uint256 valuePaid = 0;
|
||||
|
||||
// Attribute the protocol fee to the maker
|
||||
IStaking(staking).recordProtocolFee(order.makerAddress, protocolFee);
|
||||
// Calculate the protocol fee that should be paid and populate the `protocolFeePaid` field in `fillResults`.
|
||||
// It's worth noting that we leave this calculation until now so that work isn't wasted if a fee collector
|
||||
// is not registered in the exchange.
|
||||
uint256 protocolFee = tx.gasprice.safeMul(protocolFeeMultiplier);
|
||||
fillResults.protocolFeePaid = protocolFee;
|
||||
|
||||
// If sufficient ether was sent to the contract, the protocol fee should be paid in ETH.
|
||||
// Otherwise the fee should be paid in WETH. Since the exchange doesn't actually handle
|
||||
// this case, it will just forward the procotolFee in ether in case 1 and will send zero
|
||||
// value in case 2.
|
||||
if (address(this).balance >= protocolFee) {
|
||||
valuePaid = protocolFee;
|
||||
}
|
||||
IStaking(feeCollector).payProtocolFee.value(valuePaid)(order.makerAddress, takerAddress, protocolFee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ contract MixinMatchOrders is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults)
|
||||
{
|
||||
return _batchMatchOrders(
|
||||
@@ -77,7 +77,7 @@ contract MixinMatchOrders is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.BatchMatchedFillResults memory batchMatchedFillResults)
|
||||
{
|
||||
return _batchMatchOrders(
|
||||
@@ -107,7 +107,7 @@ contract MixinMatchOrders is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
return _matchOrders(
|
||||
@@ -137,7 +137,7 @@ contract MixinMatchOrders is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
return _matchOrders(
|
||||
@@ -385,10 +385,19 @@ contract MixinMatchOrders is
|
||||
rightOrder,
|
||||
leftOrderInfo.orderTakerAssetFilledAmount,
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
protocolFeeMultiplier,
|
||||
shouldMaximallyFillOrders
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
_settleMatchedOrders(
|
||||
leftOrderInfo.orderHash,
|
||||
rightOrderInfo.orderHash,
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
// Update exchange state
|
||||
_updateFilledState(
|
||||
leftOrder,
|
||||
@@ -405,16 +414,6 @@ contract MixinMatchOrders is
|
||||
matchedFillResults.right
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
_settleMatchedOrders(
|
||||
leftOrderInfo.orderHash,
|
||||
rightOrderInfo.orderHash,
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
@@ -490,39 +489,27 @@ contract MixinMatchOrders is
|
||||
matchedFillResults.profitInRightMakerAsset
|
||||
);
|
||||
|
||||
// Pay protocol fees
|
||||
if (staking != address(0)) {
|
||||
// matchedFillResults.left.protocolFeePaid == matchedFillResults.right.protocolFeePaid
|
||||
// so we only use matchedFillResults.left.protocolFeePaid as a gas optimization.
|
||||
uint256 protocolFee = matchedFillResults.left.protocolFeePaid;
|
||||
// Pay the protocol fees if there is a registered `protocolFeeCollector` address.
|
||||
address feeCollector = protocolFeeCollector;
|
||||
if (feeCollector != address(0)) {
|
||||
// Calculate the protocol fee that should be paid and populate the `protocolFeePaid` field in the left and
|
||||
// right `fillResults` of `matchedFillResults`. It's worth noting that we leave this calculation until now
|
||||
// so that work isn't wasted if a fee collector is not registered in the exchange.
|
||||
uint256 protocolFee = tx.gasprice.safeMul(protocolFeeMultiplier);
|
||||
matchedFillResults.left.protocolFeePaid = protocolFee;
|
||||
matchedFillResults.right.protocolFeePaid = protocolFee;
|
||||
|
||||
// Construct an array of makers and fee amounts so that the staking contract will only need to be called once.
|
||||
address[] memory makers = new address[](2);
|
||||
makers[0] = leftOrder.makerAddress;
|
||||
makers[1] = rightOrder.makerAddress;
|
||||
uint256[] memory fees = new uint256[](2);
|
||||
fees[0] = protocolFee;
|
||||
fees[1] = protocolFee;
|
||||
// Create a stack variable for the value that will be sent to the feeCollector when `payProtocolFee` is called.
|
||||
// This allows a gas optimization where the `leftOrder.makerAddress` only needs be loaded onto the stack once AND
|
||||
// a stack variable does not need to be allocated for the call.
|
||||
uint256 valuePaid = 0;
|
||||
|
||||
// If sufficient ether was sent to the contract, the protocol fee should be paid in ETH.
|
||||
// Otherwise the fee should be paid in WETH.
|
||||
// Pay the left order's protocol fee.
|
||||
if (address(this).balance >= 2 * protocolFee) {
|
||||
// Forward the protocol fees
|
||||
IStaking(staking).batchPayProtocolFees.value(2 * protocolFee)(makers, fees);
|
||||
} else {
|
||||
// Transfer the weth from the takerAddress.
|
||||
// Note: `_dispatchTransferFrom` is only called once as a gas optimization.
|
||||
_dispatchTransferFrom(
|
||||
leftOrderHash,
|
||||
WETH_ASSET_DATA,
|
||||
takerAddress,
|
||||
staking,
|
||||
2 * protocolFee
|
||||
);
|
||||
|
||||
// Attribute the protocol fees to the maker addresses
|
||||
IStaking(staking).batchRecordProtocolFees(makers, fees);
|
||||
valuePaid = 2 * protocolFee;
|
||||
}
|
||||
IStaking(feeCollector).payProtocolFee.value(valuePaid)(leftOrder.makerAddress, takerAddress, protocolFee);
|
||||
IStaking(feeCollector).payProtocolFee.value(valuePaid)(rightOrder.makerAddress, takerAddress, protocolFee);
|
||||
}
|
||||
|
||||
// Settle taker fees.
|
||||
|
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "./interfaces/IStakingManager.sol";
|
||||
|
||||
|
||||
contract MixinStakingManager is
|
||||
IStakingManager,
|
||||
Ownable
|
||||
{
|
||||
// The protocol fee multiplier -- the owner can update this field.
|
||||
uint256 public protocolFeeMultiplier;
|
||||
|
||||
// The address of the registered staking contract -- the owner can update this field.
|
||||
address public staking;
|
||||
|
||||
// The address of the wrapped ether contract -- the owner can update this field.
|
||||
address public weth;
|
||||
|
||||
/// @dev Allows the owner to update the protocol fee multiplier.
|
||||
/// @param updatedProtocolFeeMultiplier The updated protocol fee multiplier.
|
||||
function updateProtocolFeeMultiplier(uint256 updatedProtocolFeeMultiplier)
|
||||
external
|
||||
onlyOwner()
|
||||
{
|
||||
emit UpdatedProtocolFeeMultiplier(protocolFeeMultiplier, updatedProtocolFeeMultiplier);
|
||||
protocolFeeMultiplier = updatedProtocolFeeMultiplier;
|
||||
}
|
||||
|
||||
/// @dev Allows the owner to update the staking address.
|
||||
/// @param updatedStaking The updated staking contract address.
|
||||
function updateStakingAddress(address updatedStaking)
|
||||
external
|
||||
onlyOwner()
|
||||
{
|
||||
emit UpdatedStakingAddress(staking, updatedStaking);
|
||||
staking = updatedStaking;
|
||||
}
|
||||
|
||||
/// @dev Allows the owner to update the WETH address.
|
||||
/// @param updatedWeth The updated WETH contract address.
|
||||
function updateWethAddress(address updatedWeth)
|
||||
external
|
||||
onlyOwner()
|
||||
{
|
||||
emit UpdatedWethAddress(weth, updatedWeth);
|
||||
weth = updatedWeth;
|
||||
}
|
||||
}
|
@@ -53,7 +53,7 @@ contract MixinTransactions is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
disableRefundUntilEnd
|
||||
returns (bytes memory)
|
||||
{
|
||||
return _executeTransaction(transaction, signature);
|
||||
@@ -69,7 +69,7 @@ contract MixinTransactions is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
disableRefundUntilEnd
|
||||
returns (bytes[] memory)
|
||||
{
|
||||
uint256 length = transactions.length;
|
||||
|
@@ -47,7 +47,7 @@ contract MixinTransferSimulator is
|
||||
uint256 length = assetData.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
_dispatchTransferFrom(
|
||||
// The index is passed in as `orderHash` so that a failed transfer can be quickly identified when catching the error
|
||||
// The index is passed in as `orderHash` so that a failed transfer can be quickly identified when catching the error
|
||||
bytes32(i),
|
||||
assetData[i],
|
||||
fromAddresses[i],
|
||||
|
@@ -48,7 +48,7 @@ contract MixinWrapperFunctions is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
fillResults = _fillOrKillOrder(
|
||||
@@ -59,6 +59,10 @@ contract MixinWrapperFunctions is
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// Note: This function only needs `refundFinalBalance` modifier because ether will not
|
||||
// be returned in the event that the delegatecall fails. This said, there is no
|
||||
// reason to invoke `disableRefundUntilEnd` because it is cheaper to use this modifier
|
||||
// and the inner refund will not affect the logic of this call.
|
||||
/// @dev Fills the input order.
|
||||
/// Returns a null FillResults instance if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
@@ -72,7 +76,7 @@ contract MixinWrapperFunctions is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
refundFinalBalance
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
// ABI encode calldata for `fillOrder`
|
||||
@@ -85,7 +89,7 @@ contract MixinWrapperFunctions is
|
||||
|
||||
(bool didSucceed, bytes memory returnData) = address(this).delegatecall(fillOrderCalldata);
|
||||
if (didSucceed) {
|
||||
assert(returnData.length == 128);
|
||||
assert(returnData.length == 160);
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||
}
|
||||
// fillResults values will be 0 by default if call was unsuccessful
|
||||
@@ -105,7 +109,7 @@ contract MixinWrapperFunctions is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
disableRefundUntilEnd
|
||||
returns (LibFillResults.FillResults[] memory fillResults)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
@@ -133,7 +137,7 @@ contract MixinWrapperFunctions is
|
||||
public
|
||||
payable
|
||||
nonReentrant
|
||||
refund
|
||||
disableRefundUntilEnd
|
||||
returns (LibFillResults.FillResults[] memory fillResults)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
@@ -160,7 +164,7 @@ contract MixinWrapperFunctions is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
// disableRefundUntilEnd
|
||||
returns (LibFillResults.FillResults[] memory fillResults)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
@@ -187,7 +191,7 @@ contract MixinWrapperFunctions is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
disableRefundUntilEnd
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
@@ -233,7 +237,7 @@ contract MixinWrapperFunctions is
|
||||
)
|
||||
public
|
||||
payable
|
||||
refund
|
||||
disableRefundUntilEnd
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
@@ -333,22 +337,6 @@ contract MixinWrapperFunctions is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Fetches information for all passed in orders.
|
||||
/// @param orders Array of order specifications.
|
||||
/// @return Array of OrderInfo instances that correspond to each order.
|
||||
function getOrdersInfo(LibOrder.Order[] memory orders)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo[] memory)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
LibOrder.OrderInfo[] memory ordersInfo = new LibOrder.OrderInfo[](ordersLength);
|
||||
for (uint256 i = 0; i != ordersLength; i++) {
|
||||
ordersInfo[i] = getOrderInfo(orders[i]);
|
||||
}
|
||||
return ordersInfo;
|
||||
}
|
||||
|
||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
|
@@ -25,6 +25,9 @@ import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
|
||||
contract IExchangeCore {
|
||||
|
||||
// keccak256("Fill(address,address,bytes32,address,address,uint256,uint256,uint256,uint256,uint256,bool,bytes,bytes,bytes,bytes)")
|
||||
bytes32 internal constant FILL_EVENT_TOPIC = 0x266de417a663e51231ccdf89b2794cea06fde5e2c433d76473160b32d31fd867;
|
||||
|
||||
// Fill event is emitted whenever an order is filled.
|
||||
event Fill(
|
||||
address indexed makerAddress, // Address that created the order.
|
||||
|
@@ -21,6 +21,9 @@ pragma solidity ^0.5.9;
|
||||
|
||||
contract IProtocolFees {
|
||||
|
||||
// The proxy id of the weth asset proxy.
|
||||
bytes internal constant WETH_ASSET_DATA = hex"f47261b0";
|
||||
|
||||
// Logs updates to the protocol fee multiplier.
|
||||
event UpdatedProtocolFeeMultiplier(uint256 oldProtocolFeeMultiplier, uint256 updatedProtocolFeeMultiplier);
|
||||
|
||||
|
@@ -154,12 +154,4 @@ contract IWrapperFunctions {
|
||||
/// @param orders Array of order specifications.
|
||||
function batchCancelOrders(LibOrder.Order[] memory orders)
|
||||
public;
|
||||
|
||||
/// @dev Fetches information for all passed in orders
|
||||
/// @param orders Array of order specifications.
|
||||
/// @return Array of OrderInfo instances that correspond to each order.
|
||||
function getOrdersInfo(LibOrder.Order[] memory orders)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo[] memory);
|
||||
}
|
||||
|
@@ -92,6 +92,7 @@ contract TestWrapperFunctions is
|
||||
fillResults.takerAssetFilledAmount = order.takerAssetAmount;
|
||||
fillResults.makerFeePaid = order.makerFee;
|
||||
fillResults.takerFeePaid = order.takerFee;
|
||||
fillResults.protocolFeePaid = protocolFeeMultiplier;
|
||||
}
|
||||
|
||||
/// @dev Overridden to only log arguments and revert with certain inputs.
|
||||
|
@@ -27,7 +27,6 @@ import * as MixinExchangeCore from '../generated-artifacts/MixinExchangeCore.jso
|
||||
import * as MixinMatchOrders from '../generated-artifacts/MixinMatchOrders.json';
|
||||
import * as MixinProtocolFees from '../generated-artifacts/MixinProtocolFees.json';
|
||||
import * as MixinSignatureValidator from '../generated-artifacts/MixinSignatureValidator.json';
|
||||
import * as MixinStakingManager from '../generated-artifacts/MixinStakingManager.json';
|
||||
import * as MixinTransactions from '../generated-artifacts/MixinTransactions.json';
|
||||
import * as MixinTransferSimulator from '../generated-artifacts/MixinTransferSimulator.json';
|
||||
import * as MixinWrapperFunctions from '../generated-artifacts/MixinWrapperFunctions.json';
|
||||
@@ -49,7 +48,6 @@ export const artifacts = {
|
||||
MixinMatchOrders: MixinMatchOrders as ContractArtifact,
|
||||
MixinProtocolFees: MixinProtocolFees as ContractArtifact,
|
||||
MixinSignatureValidator: MixinSignatureValidator as ContractArtifact,
|
||||
MixinStakingManager: MixinStakingManager as ContractArtifact,
|
||||
MixinTransactions: MixinTransactions as ContractArtifact,
|
||||
MixinTransferSimulator: MixinTransferSimulator as ContractArtifact,
|
||||
MixinWrapperFunctions: MixinWrapperFunctions as ContractArtifact,
|
||||
|
@@ -25,7 +25,6 @@ export * from '../generated-wrappers/mixin_exchange_core';
|
||||
export * from '../generated-wrappers/mixin_match_orders';
|
||||
export * from '../generated-wrappers/mixin_protocol_fees';
|
||||
export * from '../generated-wrappers/mixin_signature_validator';
|
||||
export * from '../generated-wrappers/mixin_staking_manager';
|
||||
export * from '../generated-wrappers/mixin_transactions';
|
||||
export * from '../generated-wrappers/mixin_transfer_simulator';
|
||||
export * from '../generated-wrappers/mixin_wrapper_functions';
|
||||
|
@@ -17,7 +17,7 @@ import {
|
||||
Web3ProviderEngine,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { orderHashUtils } from '@0x/order-utils';
|
||||
import { AssetProxyId, FillResults, SignedOrder } from '@0x/types';
|
||||
import { FillResults, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
|
||||
@@ -33,6 +33,8 @@ export class FillOrderWrapper {
|
||||
private readonly _blockchainBalanceStore: BlockchainBalanceStore;
|
||||
private readonly _web3Wrapper: Web3Wrapper;
|
||||
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
/**
|
||||
* Simulates matching two orders by transferring amounts defined in
|
||||
* `transferAmounts` and returns the results.
|
||||
@@ -47,23 +49,18 @@ export class FillOrderWrapper {
|
||||
takerAddress: string,
|
||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||
initBalanceStore: BalanceStore,
|
||||
stakingOpts: {
|
||||
gasPrice: BigNumber;
|
||||
messageValue: BigNumber;
|
||||
protocolFeeMultiplier: BigNumber;
|
||||
stakingAddress: string;
|
||||
wethAddress: string;
|
||||
},
|
||||
// stakingOpts: {
|
||||
// gasPrice: BigNumber;
|
||||
// messageValue: BigNumber;
|
||||
// protocolFeeMultiplier: BigNumber;
|
||||
// stakingAddress: string;
|
||||
// wethAddress: string;
|
||||
// },
|
||||
): [FillResults, FillEventArgs, BalanceStore] {
|
||||
const balanceStore = LocalBalanceStore.create(initBalanceStore);
|
||||
const takerAssetFillAmount =
|
||||
opts.takerAssetFillAmount !== undefined ? opts.takerAssetFillAmount : signedOrder.takerAssetAmount;
|
||||
const fillResults = LibReferenceFunctions.calculateFillResults(
|
||||
signedOrder,
|
||||
takerAssetFillAmount,
|
||||
stakingOpts.protocolFeeMultiplier,
|
||||
stakingOpts.gasPrice,
|
||||
);
|
||||
const fillResults = LibReferenceFunctions.calculateFillResults(signedOrder, takerAssetFillAmount);
|
||||
const fillEvent = FillOrderWrapper.simulateFillEvent(signedOrder, takerAddress, fillResults);
|
||||
// Taker -> Maker
|
||||
balanceStore.transferAsset(
|
||||
@@ -93,18 +90,20 @@ export class FillOrderWrapper {
|
||||
fillResults.makerFeePaid,
|
||||
signedOrder.makerFeeAssetData,
|
||||
);
|
||||
if (stakingOpts.messageValue.isGreaterThanOrEqualTo(fillResults.protocolFeePaid)) {
|
||||
// Pay the protocol fee in ETH.
|
||||
balanceStore.transferAsset(takerAddress, stakingOpts.stakingAddress, fillResults.protocolFeePaid, '');
|
||||
} else {
|
||||
// Pay the protocol fee in WETH.
|
||||
balanceStore.transferAsset(
|
||||
takerAddress,
|
||||
stakingOpts.stakingAddress,
|
||||
fillResults.protocolFeePaid,
|
||||
AssetProxyId.ERC20,
|
||||
);
|
||||
}
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
// if (stakingOpts.messageValue.isGreaterThanOrEqualTo(fillResults.protocolFeePaid)) {
|
||||
// // Pay the protocol fee in ETH.
|
||||
// balanceStore.transferAsset(takerAddress, stakingOpts.stakingAddress, fillResults.protocolFeePaid, '');
|
||||
// } else {
|
||||
// // Pay the protocol fee in WETH.
|
||||
// balanceStore.transferAsset(
|
||||
// takerAddress,
|
||||
// stakingOpts.stakingAddress,
|
||||
// fillResults.protocolFeePaid,
|
||||
// AssetProxyId.ERC20,
|
||||
// );
|
||||
// }
|
||||
return [fillResults, fillEvent, balanceStore];
|
||||
}
|
||||
|
||||
@@ -168,6 +167,8 @@ export class FillOrderWrapper {
|
||||
return this._blockchainBalanceStore;
|
||||
}
|
||||
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
/**
|
||||
* Fills an order and asserts the effects. This includes
|
||||
* 1. The order info (via `getOrderInfo`)
|
||||
|
@@ -589,11 +589,11 @@ blockchainTests.resets('Exchange core', () => {
|
||||
});
|
||||
|
||||
it('should cancel only orders with a orderEpoch less than existing orderEpoch', async () => {
|
||||
// Cancel all transactions with a orderEpoch less than 1
|
||||
// Cancel all transactions with a orderEpoch less than 2
|
||||
const orderEpoch = new BigNumber(1);
|
||||
await exchangeWrapper.cancelOrdersUpToAsync(orderEpoch, makerAddress);
|
||||
|
||||
// Create 3 orders with orderEpoch values: 0,1,2,3
|
||||
// Create 4 orders with orderEpoch values: 0,1,2,3
|
||||
// Since we cancelled with orderEpoch=1, orders with orderEpoch<=1 will not be processed
|
||||
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const signedOrders = [
|
||||
|
@@ -164,26 +164,22 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
return _.assign({}, ORDER_DEFAULTS, details);
|
||||
}
|
||||
|
||||
// FIXME - This test definitely needs to be updated
|
||||
async function testUpdateFilledStateAsync(
|
||||
order: OrderWithoutDomain,
|
||||
orderTakerAssetFilledAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
takerAssetFillAmount: BigNumber,
|
||||
protocolFeeMultiplier: BigNumber,
|
||||
gasPrice: BigNumber,
|
||||
isProtocolFeePaidInEth: boolean,
|
||||
// protocolFeeMultiplier: BigNumber,
|
||||
// gasPrice: BigNumber,
|
||||
// isProtocolFeePaidInEth: boolean,
|
||||
): Promise<void> {
|
||||
const orderHash = randomHash();
|
||||
const fillResults = LibReferenceFunctions.calculateFillResults(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
protocolFeeMultiplier,
|
||||
gasPrice,
|
||||
);
|
||||
const fillResults = LibReferenceFunctions.calculateFillResults(order, takerAssetFillAmount);
|
||||
const expectedFilledState = orderTakerAssetFilledAmount.plus(takerAssetFillAmount);
|
||||
const opts = isProtocolFeePaidInEth
|
||||
? { value: fillResults.protocolFeePaid }
|
||||
: { value: constants.ZERO_AMOUNT };
|
||||
// const opts = isProtocolFeePaidInEth
|
||||
// ? { value: fillResults.protocolFeePaid }
|
||||
// : { value: constants.ZERO_AMOUNT };
|
||||
// CAll `testUpdateFilledState()`, which will set the `filled`
|
||||
// state for this order to `orderTakerAssetFilledAmount` before
|
||||
// calling `_updateFilledState()`.
|
||||
@@ -194,7 +190,7 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
orderHash,
|
||||
orderTakerAssetFilledAmount,
|
||||
fillResults,
|
||||
opts,
|
||||
// opts, // FIXME
|
||||
),
|
||||
);
|
||||
// Grab the new `filled` state for this order.
|
||||
@@ -214,8 +210,8 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
expect(fillEvent.args.takerAssetFilledAmount).to.bignumber.eq(fillResults.takerAssetFilledAmount);
|
||||
expect(fillEvent.args.makerFeePaid).to.bignumber.eq(fillResults.makerFeePaid);
|
||||
expect(fillEvent.args.takerFeePaid).to.bignumber.eq(fillResults.takerFeePaid);
|
||||
expect(fillEvent.args.protocolFeePaid).to.bignumber.eq(fillResults.protocolFeePaid);
|
||||
expect(fillEvent.args.isProtocolFeePaidInEth).to.eq(isProtocolFeePaidInEth);
|
||||
// expect(fillEvent.args.protocolFeePaid).to.bignumber.eq(fillResults.protocolFeePaid);
|
||||
// expect(fillEvent.args.isProtocolFeePaidInEth).to.eq(isProtocolFeePaidInEth);
|
||||
expect(fillEvent.args.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(fillEvent.args.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(fillEvent.args.makerFeeAssetData).to.eq(order.makerFeeAssetData);
|
||||
@@ -229,9 +225,6 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
order.takerAssetAmount.times(0.1),
|
||||
randomAddress(),
|
||||
order.takerAssetAmount.times(0.25),
|
||||
new BigNumber(150000),
|
||||
new BigNumber(100000),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -242,9 +235,6 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
order.takerAssetAmount.times(0.1),
|
||||
randomAddress(),
|
||||
order.takerAssetAmount.times(0.25),
|
||||
new BigNumber(100000),
|
||||
new BigNumber(150000),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -252,11 +242,13 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
const order = makeOrder();
|
||||
const orderTakerAssetFilledAmount = constants.MAX_UINT256.dividedToIntegerBy(2);
|
||||
const takerAssetFillAmount = constants.MAX_UINT256.dividedToIntegerBy(2).plus(2);
|
||||
// FIXME
|
||||
const fillResults = {
|
||||
makerAssetFilledAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetFilledAmount: takerAssetFillAmount,
|
||||
makerFeePaid: constants.ZERO_AMOUNT,
|
||||
takerFeePaid: constants.ZERO_AMOUNT,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
|
||||
SafeMathRevertErrors.BinOpErrorCodes.AdditionOverflow,
|
||||
@@ -297,11 +289,13 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
const order = DEFAULT_ORDER;
|
||||
const orderHash = randomHash();
|
||||
const takerAddress = randomAddress();
|
||||
// FIXME
|
||||
const fillResults = {
|
||||
makerAssetFilledAmount: ONE_ETHER.times(2),
|
||||
takerAssetFilledAmount: ONE_ETHER.times(10),
|
||||
makerFeePaid: ONE_ETHER.times(0.01),
|
||||
takerFeePaid: ONE_ETHER.times(0.025),
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await testExchange.settleOrder.sendTransactionAsync(orderHash, order, takerAddress, fillResults),
|
||||
@@ -371,12 +365,14 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(10),
|
||||
makerFeePaid: ONE_ETHER.times(0.01),
|
||||
takerFeePaid: constants.MAX_UINT256,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
right: {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(20),
|
||||
makerAssetFilledAmount: ONE_ETHER.times(4),
|
||||
makerFeePaid: ONE_ETHER.times(0.02),
|
||||
takerFeePaid: constants.MAX_UINT256_ROOT,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
profitInLeftMakerAsset: ONE_ETHER,
|
||||
profitInRightMakerAsset: ONE_ETHER.times(2),
|
||||
@@ -418,12 +414,14 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(10),
|
||||
makerFeePaid: ONE_ETHER.times(0.01),
|
||||
takerFeePaid: constants.MAX_UINT256,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
right: {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(20),
|
||||
makerAssetFilledAmount: ONE_ETHER.times(4),
|
||||
makerFeePaid: ONE_ETHER.times(0.02),
|
||||
takerFeePaid: constants.MAX_UINT256_ROOT,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
profitInLeftMakerAsset: ONE_ETHER,
|
||||
profitInRightMakerAsset: ONE_ETHER.times(2),
|
||||
@@ -454,12 +452,14 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(10),
|
||||
makerFeePaid: ONE_ETHER.times(0.01),
|
||||
takerFeePaid: ONE_ETHER.times(0.025),
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
right: {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(20),
|
||||
makerAssetFilledAmount: ONE_ETHER.times(4),
|
||||
makerFeePaid: ONE_ETHER.times(0.02),
|
||||
takerFeePaid: ONE_ETHER.times(0.05),
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
profitInLeftMakerAsset: ONE_ETHER,
|
||||
profitInRightMakerAsset: ONE_ETHER.times(2),
|
||||
@@ -550,12 +550,14 @@ blockchainTests('Exchange core internal functions', env => {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(10),
|
||||
makerFeePaid: ONE_ETHER.times(0.01),
|
||||
takerFeePaid: ONE_ETHER.times(0.025),
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
right: {
|
||||
takerAssetFilledAmount: ONE_ETHER.times(20),
|
||||
makerAssetFilledAmount: ONE_ETHER.times(4),
|
||||
makerFeePaid: ONE_ETHER.times(0.02),
|
||||
takerFeePaid: ONE_ETHER.times(0.05),
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
profitInLeftMakerAsset: ONE_ETHER,
|
||||
profitInRightMakerAsset: ONE_ETHER.times(2),
|
||||
|
@@ -5,8 +5,6 @@ import { OrderWithoutDomain as Order } from '@0x/types';
|
||||
import { BigNumber, SafeMathRevertErrors } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { calculateFillResults } from '../src/reference_functions';
|
||||
|
||||
describe('Reference functions', () => {
|
||||
const ONE_ETHER = constants.ONE_ETHER;
|
||||
const EMPTY_ORDER: Order = {
|
||||
@@ -44,7 +42,9 @@ describe('Reference functions', () => {
|
||||
takerAssetFilledAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(
|
||||
expectedError.message,
|
||||
);
|
||||
});
|
||||
|
||||
it('reverts if computing `fillResults.makerFeePaid` overflows', () => {
|
||||
@@ -65,7 +65,7 @@ describe('Reference functions', () => {
|
||||
makerAssetFilledAmount,
|
||||
order.makerFee,
|
||||
);
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if computing `fillResults.takerFeePaid` overflows', () => {
|
||||
@@ -81,7 +81,7 @@ describe('Reference functions', () => {
|
||||
takerAssetFilledAmount,
|
||||
order.takerFee,
|
||||
);
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if `order.makerAssetAmount` is 0', () => {
|
||||
@@ -91,7 +91,7 @@ describe('Reference functions', () => {
|
||||
});
|
||||
const takerAssetFilledAmount = ONE_ETHER;
|
||||
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if `order.takerAssetAmount` is 0', () => {
|
||||
@@ -101,7 +101,7 @@ describe('Reference functions', () => {
|
||||
});
|
||||
const takerAssetFilledAmount = ONE_ETHER;
|
||||
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if there is a rounding error computing `makerAsssetFilledAmount`', () => {
|
||||
@@ -115,7 +115,7 @@ describe('Reference functions', () => {
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if there is a rounding error computing `makerFeePaid`', () => {
|
||||
@@ -135,7 +135,7 @@ describe('Reference functions', () => {
|
||||
order.makerAssetAmount,
|
||||
order.makerFee,
|
||||
);
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if there is a rounding error computing `takerFeePaid`', () => {
|
||||
@@ -155,7 +155,7 @@ describe('Reference functions', () => {
|
||||
order.makerAssetAmount,
|
||||
order.takerFee,
|
||||
);
|
||||
return expect(() => calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
return expect(() => LibReferenceFunctions.calculateFillResults(order, takerAssetFilledAmount)).to.throw(expectedError.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,143 +0,0 @@
|
||||
import { blockchainTests, constants, expect, LogDecoder } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, OwnableRevertErrors } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
ExchangeContract,
|
||||
ExchangeUpdatedProtocolFeeMultiplierEventArgs,
|
||||
ExchangeUpdatedStakingAddressEventArgs,
|
||||
ExchangeUpdatedWethAddressEventArgs,
|
||||
} from '../src';
|
||||
|
||||
blockchainTests.resets('MixinStakingManager', env => {
|
||||
let accounts: string[];
|
||||
let exchange: ExchangeContract;
|
||||
let logDecoder: LogDecoder;
|
||||
let nonOwner: string;
|
||||
let owner: string;
|
||||
let staking: string;
|
||||
let weth: string;
|
||||
|
||||
// The protocolFeeMultiplier that will be used to test the update functions.
|
||||
const protocolFeeMultiplier = new BigNumber(15000);
|
||||
|
||||
before(async () => {
|
||||
accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
nonOwner = accounts[1];
|
||||
staking = accounts[2];
|
||||
weth = accounts[3];
|
||||
|
||||
// Update the from address of the txDefaults. This is the address that will become the owner.
|
||||
env.txDefaults.from = owner;
|
||||
|
||||
// Deploy the exchange contract.
|
||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Exchange,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
new BigNumber(1337),
|
||||
);
|
||||
|
||||
// Configure the log decoder
|
||||
logDecoder = new LogDecoder(env.web3Wrapper, artifacts);
|
||||
});
|
||||
|
||||
blockchainTests.resets('updateProtocolFeeMultiplier', () => {
|
||||
it('should revert if msg.sender != owner', async () => {
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
|
||||
|
||||
// Ensure that the transaction reverts with the expected rich error.
|
||||
const tx = exchange.updateStakingAddress.sendTransactionAsync(staking, {
|
||||
from: nonOwner,
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed and emit an UpdatedProtocolFeeMultiplier event if msg.sender == owner', async () => {
|
||||
// Call the `updateProtocolFeeMultiplier()` function and get the receipt.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await exchange.updateProtocolFeeMultiplier.sendTransactionAsync(protocolFeeMultiplier, {
|
||||
from: owner,
|
||||
}),
|
||||
);
|
||||
|
||||
// Verify that the staking address was actually updated to the correct address.
|
||||
const updated = await exchange.protocolFeeMultiplier.callAsync();
|
||||
expect(updated).bignumber.to.be.eq(protocolFeeMultiplier);
|
||||
|
||||
// Ensure that the correct `UpdatedStakingAddress` event was logged.
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const updatedEvent = receipt.logs[0] as LogWithDecodedArgs<ExchangeUpdatedProtocolFeeMultiplierEventArgs>;
|
||||
expect(updatedEvent.event).to.be.eq('UpdatedProtocolFeeMultiplier');
|
||||
expect(updatedEvent.args.oldProtocolFeeMultiplier).bignumber.to.be.eq(constants.ZERO_AMOUNT);
|
||||
expect(updatedEvent.args.updatedProtocolFeeMultiplier).bignumber.to.be.eq(protocolFeeMultiplier);
|
||||
});
|
||||
});
|
||||
|
||||
blockchainTests.resets('updateStakingAddress', () => {
|
||||
it('should revert if msg.sender != owner', async () => {
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
|
||||
|
||||
// Ensure that the transaction reverts with the expected rich error.
|
||||
const tx = exchange.updateStakingAddress.sendTransactionAsync(staking, {
|
||||
from: nonOwner,
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed and emit an UpdatedStakingAddress event if msg.sender == owner', async () => {
|
||||
// Call the `updateStakingAddress()` function and get the receipt.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await exchange.updateStakingAddress.sendTransactionAsync(staking, {
|
||||
from: owner,
|
||||
}),
|
||||
);
|
||||
|
||||
// Verify that the staking address was actually updated to the correct address.
|
||||
const updated = await exchange.staking.callAsync();
|
||||
expect(updated).to.be.eq(staking);
|
||||
|
||||
// Ensure that the correct `UpdatedStakingAddress` event was logged.
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const updatedEvent = receipt.logs[0] as LogWithDecodedArgs<ExchangeUpdatedStakingAddressEventArgs>;
|
||||
expect(updatedEvent.event).to.be.eq('UpdatedStakingAddress');
|
||||
expect(updatedEvent.args.oldStaking).to.be.eq(constants.NULL_ADDRESS);
|
||||
expect(updatedEvent.args.updatedStaking).to.be.eq(staking);
|
||||
});
|
||||
});
|
||||
|
||||
blockchainTests.resets('updateWethAddress', () => {
|
||||
it('should revert if msg.sender != owner', async () => {
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(nonOwner, owner);
|
||||
|
||||
// Ensure that the transaction reverts with the expected rich error.
|
||||
const tx = exchange.updateWethAddress.sendTransactionAsync(weth, {
|
||||
from: nonOwner,
|
||||
});
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('should succeed and emit an UpdatedStakingAddress event if msg.sender == owner', async () => {
|
||||
// Call the `updateWethAddress()` function and get the receipt.
|
||||
const receipt = await logDecoder.getTxWithDecodedLogsAsync(
|
||||
await exchange.updateWethAddress.sendTransactionAsync(weth, {
|
||||
from: owner,
|
||||
}),
|
||||
);
|
||||
|
||||
// Verify that the staking address was actually updated to the correct address.
|
||||
const updated = await exchange.weth.callAsync();
|
||||
expect(updated).to.be.eq(weth);
|
||||
|
||||
// Ensure that the correct `UpdatedStakingAddress` event was logged.
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const updatedEvent = receipt.logs[0] as LogWithDecodedArgs<ExchangeUpdatedWethAddressEventArgs>;
|
||||
expect(updatedEvent.event).to.be.eq('UpdatedWethAddress');
|
||||
expect(updatedEvent.args.oldWeth).to.be.eq(constants.NULL_ADDRESS);
|
||||
expect(updatedEvent.args.updatedWeth).to.be.eq(weth);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1037,13 +1037,14 @@ blockchainTests.resets('Exchange transactions', env => {
|
||||
const cancelTransaction = await makerTransactionFactory.newSignedTransactionAsync({
|
||||
data: cancelData,
|
||||
});
|
||||
|
||||
await exchangeWrapperContract.cancelOrdersUpTo.awaitTransactionSuccessAsync(
|
||||
targetOrderEpoch,
|
||||
cancelTransaction.salt,
|
||||
cancelTransaction.expirationTimeSeconds,
|
||||
cancelTransaction.signature,
|
||||
// { from: makerAddress },
|
||||
{ from: makerAddress },
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
|
@@ -43,35 +43,35 @@ export class ExchangeWrapper {
|
||||
public async fillOrKillOrderAsync(
|
||||
signedOrder: SignedOrder,
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const txReceipt = await this._exchange.fillOrKillOrder.awaitTransactionSuccessAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return txReceipt;
|
||||
}
|
||||
public async fillOrderNoThrowAsync(
|
||||
signedOrder: SignedOrder,
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
|
||||
opts: { takerAssetFillAmount?: BigNumber; gas?: number; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const txReceipt = await this._exchange.fillOrderNoThrow.awaitTransactionSuccessAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
{ from, gas: opts.gas },
|
||||
{ from, gas: opts.gas, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return txReceipt;
|
||||
}
|
||||
public async batchFillOrdersAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchFillOrders.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
@@ -79,13 +79,13 @@ export class ExchangeWrapper {
|
||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||
: opts.takerAssetFillAmounts,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async batchFillOrKillOrdersAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchFillOrKillOrders.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
@@ -93,13 +93,13 @@ export class ExchangeWrapper {
|
||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||
: opts.takerAssetFillAmounts,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async batchFillOrdersNoThrowAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchFillOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
@@ -107,25 +107,25 @@ export class ExchangeWrapper {
|
||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||
: opts.takerAssetFillAmounts,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
{ from, gas: opts.gas },
|
||||
{ from, gas: opts.gas, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async marketSellOrdersNoThrowAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||
opts: { takerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.marketSellOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.takerAssetFillAmount,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
{ from, gas: opts.gas },
|
||||
{ from, gas: opts.gas, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async marketBuyOrdersNoThrowAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||
opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
@@ -180,22 +180,23 @@ export class ExchangeWrapper {
|
||||
public async executeTransactionAsync(
|
||||
signedTransaction: SignedZeroExTransaction,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.executeTransaction.awaitTransactionSuccessAsync(
|
||||
signedTransaction,
|
||||
signedTransaction.signature,
|
||||
{
|
||||
from,
|
||||
},
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async batchExecuteTransactionsAsync(
|
||||
signedTransactions: SignedZeroExTransaction[],
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const signatures = signedTransactions.map(signedTransaction => signedTransaction.signature);
|
||||
return this._exchange.batchExecuteTransactions.awaitTransactionSuccessAsync(signedTransactions, signatures, {
|
||||
from,
|
||||
gasPrice: opts.gasPrice,
|
||||
});
|
||||
}
|
||||
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
|
||||
@@ -214,14 +215,11 @@ export class ExchangeWrapper {
|
||||
const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
|
||||
return orderInfo;
|
||||
}
|
||||
public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
|
||||
const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
|
||||
return ordersInfo;
|
||||
}
|
||||
public async batchMatchOrdersAsync(
|
||||
signedOrdersLeft: SignedOrder[],
|
||||
signedOrdersRight: SignedOrder[],
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
return this._exchange.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||
@@ -229,25 +227,27 @@ export class ExchangeWrapper {
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
params.rightSignatures,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async batchMatchOrdersRawAsync(
|
||||
params: BatchMatchOrder,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
params.rightSignatures,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async getBatchMatchOrdersResultsAsync(
|
||||
signedOrdersLeft: SignedOrder[],
|
||||
signedOrdersRight: SignedOrder[],
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<BatchMatchedFillResults> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
const batchMatchedFillResults = await this._exchange.batchMatchOrders.callAsync(
|
||||
@@ -255,7 +255,7 @@ export class ExchangeWrapper {
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
params.rightSignatures,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return batchMatchedFillResults;
|
||||
}
|
||||
@@ -263,6 +263,7 @@ export class ExchangeWrapper {
|
||||
signedOrdersLeft: SignedOrder[],
|
||||
signedOrdersRight: SignedOrder[],
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
return this._exchange.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
@@ -270,25 +271,27 @@ export class ExchangeWrapper {
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
params.rightSignatures,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async batchMatchOrdersWithMaximalFillRawAsync(
|
||||
params: BatchMatchOrder,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
params.rightSignatures,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async getBatchMatchOrdersWithMaximalFillResultsAsync(
|
||||
signedOrdersLeft: SignedOrder[],
|
||||
signedOrdersRight: SignedOrder[],
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<BatchMatchedFillResults> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
const batchMatchedFillResults = await this._exchange.batchMatchOrdersWithMaximalFill.callAsync(
|
||||
@@ -296,7 +299,7 @@ export class ExchangeWrapper {
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
params.rightSignatures,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return batchMatchedFillResults;
|
||||
}
|
||||
@@ -304,6 +307,7 @@ export class ExchangeWrapper {
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const txReceipt = await this._exchange.matchOrders.awaitTransactionSuccessAsync(
|
||||
@@ -311,7 +315,7 @@ export class ExchangeWrapper {
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
params.rightSignature,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return txReceipt;
|
||||
}
|
||||
@@ -319,6 +323,7 @@ export class ExchangeWrapper {
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<MatchedFillResults> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const matchedFillResults = await this._exchange.matchOrders.callAsync(
|
||||
@@ -326,7 +331,7 @@ export class ExchangeWrapper {
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
params.rightSignature,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return matchedFillResults;
|
||||
}
|
||||
@@ -334,6 +339,7 @@ export class ExchangeWrapper {
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
return this._exchange.matchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
@@ -341,13 +347,14 @@ export class ExchangeWrapper {
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
params.rightSignature,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
}
|
||||
public async getMatchOrdersWithMaximalFillResultsAsync(
|
||||
signedOrderLeft: SignedOrder,
|
||||
signedOrderRight: SignedOrder,
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber },
|
||||
): Promise<MatchedFillResults> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const matchedFillResults = await this._exchange.matchOrdersWithMaximalFill.callAsync(
|
||||
@@ -355,21 +362,21 @@ export class ExchangeWrapper {
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
params.rightSignature,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return matchedFillResults;
|
||||
}
|
||||
public async getFillOrderResultsAsync(
|
||||
signedOrder: SignedOrder,
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
||||
): Promise<FillResults> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const fillResults = await this._exchange.fillOrder.callAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
{ from },
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
);
|
||||
return fillResults;
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import {
|
||||
ERC721Wrapper,
|
||||
MultiAssetProxyContract,
|
||||
} from '@0x/contracts-asset-proxy';
|
||||
import { constants, expect, orderUtils, signingUtils } from '@0x/contracts-test-utils';
|
||||
import { constants, expect, LogDecoder, orderUtils, signingUtils } from '@0x/contracts-test-utils';
|
||||
import { BalanceAndProxyAllowanceLazyStore, ExchangeRevertErrors, orderHashUtils } from '@0x/order-utils';
|
||||
import { FillResults, Order, SignatureType, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, errorUtils, providerUtils, RevertError, StringRevertError } from '@0x/utils';
|
||||
@@ -40,6 +40,7 @@ const EMPTY_FILL_RESULTS = {
|
||||
makerAssetFilledAmount: constants.ZERO_AMOUNT,
|
||||
makerFeePaid: constants.ZERO_AMOUNT,
|
||||
takerFeePaid: constants.ZERO_AMOUNT,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
|
||||
enum TestOutlook {
|
||||
@@ -48,6 +49,7 @@ enum TestOutlook {
|
||||
Failure,
|
||||
}
|
||||
|
||||
// FIXME - Really punting on this for now. It's possible that this won't need to be changed.
|
||||
/**
|
||||
* Instantiates a new instance of FillOrderCombinatorialUtils. Since this method has some
|
||||
* required async setup, a factory method is required.
|
||||
@@ -114,6 +116,8 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
|
||||
const logDecoder = new LogDecoder(web3Wrapper, artifacts);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, ownerAddress);
|
||||
@@ -202,6 +206,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
|
||||
takerAddress,
|
||||
exchangeWrapper,
|
||||
assetWrapper,
|
||||
logDecoder,
|
||||
);
|
||||
return fillOrderCombinatorialUtils;
|
||||
}
|
||||
@@ -215,6 +220,7 @@ export class FillOrderCombinatorialUtils {
|
||||
public takerAddress: string;
|
||||
public exchangeWrapper: ExchangeWrapper;
|
||||
public assetWrapper: AssetWrapper;
|
||||
public logDecoder: LogDecoder;
|
||||
public balanceAndProxyAllowanceFetcher: SimpleAssetBalanceAndProxyAllowanceFetcher;
|
||||
|
||||
public static generateFillOrderCombinations(): FillScenario[] {
|
||||
@@ -445,6 +451,7 @@ export class FillOrderCombinatorialUtils {
|
||||
takerAddress: string,
|
||||
exchangeWrapper: ExchangeWrapper,
|
||||
assetWrapper: AssetWrapper,
|
||||
logDecoder: LogDecoder,
|
||||
) {
|
||||
this.provider = provider;
|
||||
this.orderFactory = orderFactory;
|
||||
@@ -454,6 +461,7 @@ export class FillOrderCombinatorialUtils {
|
||||
this.takerAddress = takerAddress;
|
||||
this.exchangeWrapper = exchangeWrapper;
|
||||
this.assetWrapper = assetWrapper;
|
||||
this.logDecoder = logDecoder;
|
||||
this.balanceAndProxyAllowanceFetcher = new SimpleAssetBalanceAndProxyAllowanceFetcher(assetWrapper);
|
||||
}
|
||||
|
||||
@@ -643,7 +651,7 @@ export class FillOrderCombinatorialUtils {
|
||||
);
|
||||
expect(exchangeLogs.length).to.be.equal(1, 'logs length');
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const log = txReceipt.logs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>;
|
||||
const log = exchangeLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>;
|
||||
expect(log.args.makerAddress, 'log.args.makerAddress').to.be.equal(makerAddress);
|
||||
expect(log.args.takerAddress, 'log.args.takerAddress').to.be.equal(this.takerAddress);
|
||||
expect(log.args.feeRecipientAddress, 'log.args.feeRecipientAddress').to.be.equal(feeRecipient);
|
||||
|
@@ -20,6 +20,7 @@ export enum FillOrderError {
|
||||
TransferFailed = 'TRANSFER_FAILED',
|
||||
}
|
||||
|
||||
// FIXME - Punting on protocol fees for now
|
||||
/**
|
||||
* Simplified fill order simulator.
|
||||
*/
|
||||
@@ -121,6 +122,7 @@ export class FillOrderSimulator {
|
||||
makerAssetFilledAmount: makerAssetFillAmount,
|
||||
makerFeePaid,
|
||||
takerFeePaid,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { ERC1155ProxyWrapper, ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { ERC1155HoldingsByOwner, expect, OrderStatus } from '@0x/contracts-test-utils';
|
||||
import { constants, ERC1155HoldingsByOwner, expect, OrderStatus } from '@0x/contracts-test-utils';
|
||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
|
||||
import { AssetProxyId, BatchMatchedFillResults, FillResults, MatchedFillResults, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
@@ -235,6 +235,7 @@ export class MatchOrderTester {
|
||||
return expectedBatchMatchResults;
|
||||
}
|
||||
|
||||
// FIXME - Punting on protocol fees until later
|
||||
/**
|
||||
* Matches two complementary orders and asserts results.
|
||||
* @param orders The matched orders and filled states.
|
||||
@@ -266,6 +267,7 @@ export class MatchOrderTester {
|
||||
orders.leftOrder,
|
||||
orders.rightOrder,
|
||||
takerAddress,
|
||||
{}, // FIXME
|
||||
);
|
||||
transactionReceipt = await this._executeMatchOrdersWithMaximalFillAsync(
|
||||
orders.leftOrder,
|
||||
@@ -1198,12 +1200,14 @@ function convertToMatchResults(result: MatchResults): MatchedFillResults {
|
||||
takerAssetFilledAmount: result.fills[0].takerAssetFilledAmount,
|
||||
makerFeePaid: result.fills[0].makerFeePaid,
|
||||
takerFeePaid: result.fills[0].takerFeePaid,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
right: {
|
||||
makerAssetFilledAmount: result.fills[1].makerAssetFilledAmount,
|
||||
takerAssetFilledAmount: result.fills[1].takerAssetFilledAmount,
|
||||
makerFeePaid: result.fills[1].makerFeePaid,
|
||||
takerFeePaid: result.fills[1].takerFeePaid,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
},
|
||||
profitInLeftMakerAsset,
|
||||
profitInRightMakerAsset,
|
||||
@@ -1222,6 +1226,7 @@ function convertToFillResults(result: FillEventArgs): FillResults {
|
||||
takerAssetFilledAmount: result.takerAssetFilledAmount,
|
||||
makerFeePaid: result.makerFeePaid,
|
||||
takerFeePaid: result.takerFeePaid,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
};
|
||||
return fillResults;
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import {
|
||||
ERC20BalancesByOwner,
|
||||
expect,
|
||||
getLatestBlockTimestampAsync,
|
||||
increaseTimeAndMineBlockAsync,
|
||||
OrderFactory,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { assetDataUtils, ExchangeRevertErrors, orderHashUtils } from '@0x/order-utils';
|
||||
@@ -48,11 +47,15 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
let defaultTakerAssetAddress: string;
|
||||
let defaultFeeAssetAddress: string;
|
||||
|
||||
const DEFAULT_GAS_PRICE = new BigNumber(2);
|
||||
const PROTOCOL_FEE_MULTIPLIER = new BigNumber(150);
|
||||
|
||||
const nullFillResults: FillResults = {
|
||||
makerAssetFilledAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetFilledAmount: constants.ZERO_AMOUNT,
|
||||
makerFeePaid: constants.ZERO_AMOUNT,
|
||||
takerFeePaid: constants.ZERO_AMOUNT,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
@@ -81,10 +84,16 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Exchange,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{ ...env.txDefaults, from: owner },
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
|
||||
// Set the protocol fee multiplier of the exchange
|
||||
await exchange.updateProtocolFeeMultiplier.awaitTransactionSuccessAsync(PROTOCOL_FEE_MULTIPLIER, {
|
||||
from: owner,
|
||||
});
|
||||
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, env.provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
@@ -492,11 +501,14 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
.dividedToIntegerBy(signedOrder.makerAssetAmount);
|
||||
|
||||
takerAssetFillAmounts.push(takerAssetFillAmount);
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
expectedFillResults.push({
|
||||
takerAssetFilledAmount: takerAssetFillAmount,
|
||||
makerAssetFilledAmount,
|
||||
makerFeePaid: makerFee,
|
||||
takerFeePaid: takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
});
|
||||
|
||||
erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
|
||||
@@ -522,11 +534,13 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
].plus(makerFee.plus(takerFee));
|
||||
});
|
||||
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
const fillResults = await exchange.batchFillOrders.callAsync(
|
||||
signedOrders,
|
||||
takerAssetFillAmounts,
|
||||
signedOrders.map(signedOrder => signedOrder.signature),
|
||||
{ from: takerAddress },
|
||||
{ from: takerAddress, gasPrice: DEFAULT_GAS_PRICE },
|
||||
);
|
||||
await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmounts,
|
||||
@@ -559,11 +573,14 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
.dividedToIntegerBy(signedOrder.makerAssetAmount);
|
||||
|
||||
takerAssetFillAmounts.push(takerAssetFillAmount);
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
expectedFillResults.push({
|
||||
takerAssetFilledAmount: takerAssetFillAmount,
|
||||
makerAssetFilledAmount,
|
||||
makerFeePaid: makerFee,
|
||||
takerFeePaid: takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
});
|
||||
|
||||
erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
|
||||
@@ -642,11 +659,14 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
.dividedToIntegerBy(signedOrder.makerAssetAmount);
|
||||
|
||||
takerAssetFillAmounts.push(takerAssetFillAmount);
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
expectedFillResults.push({
|
||||
takerAssetFilledAmount: takerAssetFillAmount,
|
||||
makerAssetFilledAmount,
|
||||
makerFeePaid: makerFee,
|
||||
takerFeePaid: takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
});
|
||||
|
||||
erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
|
||||
@@ -712,11 +732,14 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
.dividedToIntegerBy(signedOrder.makerAssetAmount);
|
||||
|
||||
takerAssetFillAmounts.push(takerAssetFillAmount);
|
||||
// FIXME - Punting on these tests for now since no staking contract will be registered. This
|
||||
// should be revisited when the protocol fee testing has been unit tested well.
|
||||
expectedFillResults.push({
|
||||
takerAssetFilledAmount: takerAssetFillAmount,
|
||||
makerAssetFilledAmount,
|
||||
makerFeePaid: makerFee,
|
||||
takerFeePaid: takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
});
|
||||
|
||||
erc20Balances[makerAddress][makerAssetAddress] = erc20Balances[makerAddress][
|
||||
@@ -853,6 +876,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
takerAssetFilledAmount: signedOrder.takerAssetAmount,
|
||||
makerFeePaid: signedOrder.makerFee,
|
||||
takerFeePaid: signedOrder.takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME - This is what is being used now.
|
||||
}))
|
||||
.reduce(
|
||||
(totalFillResults, currentFillResults) => ({
|
||||
@@ -864,6 +888,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
),
|
||||
makerFeePaid: totalFillResults.makerFeePaid.plus(currentFillResults.makerFeePaid),
|
||||
takerFeePaid: totalFillResults.takerFeePaid.plus(currentFillResults.takerFeePaid),
|
||||
protocolFeePaid: totalFillResults.protocolFeePaid.plus(currentFillResults.protocolFeePaid),
|
||||
}),
|
||||
nullFillResults,
|
||||
);
|
||||
@@ -923,6 +948,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
takerAssetFilledAmount: signedOrder.takerAssetAmount,
|
||||
makerFeePaid: signedOrder.makerFee,
|
||||
takerFeePaid: signedOrder.takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
}))
|
||||
.reduce(
|
||||
(totalFillResults, currentFillResults) => ({
|
||||
@@ -934,6 +960,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
),
|
||||
makerFeePaid: totalFillResults.makerFeePaid.plus(currentFillResults.makerFeePaid),
|
||||
takerFeePaid: totalFillResults.takerFeePaid.plus(currentFillResults.takerFeePaid),
|
||||
protocolFeePaid: totalFillResults.protocolFeePaid.plus(currentFillResults.protocolFeePaid),
|
||||
}),
|
||||
nullFillResults,
|
||||
);
|
||||
@@ -1037,6 +1064,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
takerAssetFilledAmount: signedOrder.takerAssetAmount,
|
||||
makerFeePaid: signedOrder.makerFee,
|
||||
takerFeePaid: signedOrder.takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
}))
|
||||
.reduce(
|
||||
(totalFillResults, currentFillResults) => ({
|
||||
@@ -1048,6 +1076,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
),
|
||||
makerFeePaid: totalFillResults.makerFeePaid.plus(currentFillResults.makerFeePaid),
|
||||
takerFeePaid: totalFillResults.takerFeePaid.plus(currentFillResults.takerFeePaid),
|
||||
protocolFeePaid: totalFillResults.protocolFeePaid.plus(currentFillResults.protocolFeePaid),
|
||||
}),
|
||||
nullFillResults,
|
||||
);
|
||||
@@ -1108,6 +1137,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
takerAssetFilledAmount: signedOrder.takerAssetAmount,
|
||||
makerFeePaid: signedOrder.makerFee,
|
||||
takerFeePaid: signedOrder.takerFee,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT, // FIXME
|
||||
}))
|
||||
.reduce(
|
||||
(totalFillResults, currentFillResults) => ({
|
||||
@@ -1119,6 +1149,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
),
|
||||
makerFeePaid: totalFillResults.makerFeePaid.plus(currentFillResults.makerFeePaid),
|
||||
takerFeePaid: totalFillResults.takerFeePaid.plus(currentFillResults.takerFeePaid),
|
||||
protocolFeePaid: totalFillResults.protocolFeePaid.plus(currentFillResults.protocolFeePaid),
|
||||
}),
|
||||
nullFillResults,
|
||||
);
|
||||
@@ -1151,189 +1182,5 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOrdersInfo', () => {
|
||||
beforeEach(async () => {
|
||||
signedOrders = [
|
||||
await orderFactory.newSignedOrderAsync(),
|
||||
await orderFactory.newSignedOrderAsync(),
|
||||
await orderFactory.newSignedOrderAsync(),
|
||||
];
|
||||
});
|
||||
it('should get the correct information for multiple unfilled orders', async () => {
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = new BigNumber(0);
|
||||
const expectedOrderStatus = OrderStatus.Fillable;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for multiple partially filled orders', async () => {
|
||||
const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
|
||||
await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
|
||||
const expectedOrderStatus = OrderStatus.Fillable;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for multiple fully filled orders', async () => {
|
||||
await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress);
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount;
|
||||
const expectedOrderStatus = OrderStatus.FullyFilled;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for multiple cancelled and unfilled orders', async () => {
|
||||
await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = new BigNumber(0);
|
||||
const expectedOrderStatus = OrderStatus.Cancelled;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for multiple cancelled and partially filled orders', async () => {
|
||||
const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
|
||||
await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
|
||||
await exchangeWrapper.batchCancelOrdersAsync(signedOrders, makerAddress);
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
|
||||
const expectedOrderStatus = OrderStatus.Cancelled;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for multiple expired and unfilled orders', async () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
|
||||
await increaseTimeAndMineBlockAsync(timeUntilExpiration);
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = new BigNumber(0);
|
||||
const expectedOrderStatus = OrderStatus.Expired;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for multiple expired and partially filled orders', async () => {
|
||||
const takerAssetFillAmounts = _.map(signedOrders, signedOrder => signedOrder.takerAssetAmount.div(2));
|
||||
await exchangeWrapper.batchFillOrdersAsync(signedOrders, takerAddress, { takerAssetFillAmounts });
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const timeUntilExpiration = signedOrders[0].expirationTimeSeconds.minus(currentTimestamp).toNumber();
|
||||
await increaseTimeAndMineBlockAsync(timeUntilExpiration);
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(3);
|
||||
_.forEach(signedOrders, (signedOrder, index) => {
|
||||
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedTakerAssetFilledAmount = signedOrder.takerAssetAmount.div(2);
|
||||
const expectedOrderStatus = OrderStatus.Expired;
|
||||
const orderInfo = ordersInfo[index];
|
||||
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
|
||||
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(expectedTakerAssetFilledAmount);
|
||||
expect(orderInfo.orderStatus).to.equal(expectedOrderStatus);
|
||||
});
|
||||
});
|
||||
it('should get the correct information for a mix of unfilled, partially filled, fully filled, cancelled, and expired orders', async () => {
|
||||
const unfilledOrder = await orderFactory.newSignedOrderAsync();
|
||||
const partiallyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await exchangeWrapper.fillOrderAsync(partiallyFilledOrder, takerAddress, {
|
||||
takerAssetFillAmount: partiallyFilledOrder.takerAssetAmount.div(2),
|
||||
});
|
||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await exchangeWrapper.fillOrderAsync(fullyFilledOrder, takerAddress);
|
||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const expiredOrder = await orderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp),
|
||||
});
|
||||
signedOrders = [unfilledOrder, partiallyFilledOrder, fullyFilledOrder, cancelledOrder, expiredOrder];
|
||||
const ordersInfo = await exchangeWrapper.getOrdersInfoAsync(signedOrders);
|
||||
expect(ordersInfo.length).to.be.equal(5);
|
||||
|
||||
const expectedUnfilledOrderHash = orderHashUtils.getOrderHashHex(unfilledOrder);
|
||||
const expectedUnfilledTakerAssetFilledAmount = new BigNumber(0);
|
||||
const expectedUnfilledOrderStatus = OrderStatus.Fillable;
|
||||
const unfilledOrderInfo = ordersInfo[0];
|
||||
expect(unfilledOrderInfo.orderHash).to.be.equal(expectedUnfilledOrderHash);
|
||||
expect(unfilledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
|
||||
expectedUnfilledTakerAssetFilledAmount,
|
||||
);
|
||||
expect(unfilledOrderInfo.orderStatus).to.be.equal(expectedUnfilledOrderStatus);
|
||||
|
||||
const expectedPartialOrderHash = orderHashUtils.getOrderHashHex(partiallyFilledOrder);
|
||||
const expectedPartialTakerAssetFilledAmount = partiallyFilledOrder.takerAssetAmount.div(2);
|
||||
const expectedPartialOrderStatus = OrderStatus.Fillable;
|
||||
const partialOrderInfo = ordersInfo[1];
|
||||
expect(partialOrderInfo.orderHash).to.be.equal(expectedPartialOrderHash);
|
||||
expect(partialOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
|
||||
expectedPartialTakerAssetFilledAmount,
|
||||
);
|
||||
expect(partialOrderInfo.orderStatus).to.be.equal(expectedPartialOrderStatus);
|
||||
|
||||
const expectedFilledOrderHash = orderHashUtils.getOrderHashHex(fullyFilledOrder);
|
||||
const expectedFilledTakerAssetFilledAmount = fullyFilledOrder.takerAssetAmount;
|
||||
const expectedFilledOrderStatus = OrderStatus.FullyFilled;
|
||||
const filledOrderInfo = ordersInfo[2];
|
||||
expect(filledOrderInfo.orderHash).to.be.equal(expectedFilledOrderHash);
|
||||
expect(filledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
|
||||
expectedFilledTakerAssetFilledAmount,
|
||||
);
|
||||
expect(filledOrderInfo.orderStatus).to.be.equal(expectedFilledOrderStatus);
|
||||
|
||||
const expectedCancelledOrderHash = orderHashUtils.getOrderHashHex(cancelledOrder);
|
||||
const expectedCancelledTakerAssetFilledAmount = new BigNumber(0);
|
||||
const expectedCancelledOrderStatus = OrderStatus.Cancelled;
|
||||
const cancelledOrderInfo = ordersInfo[3];
|
||||
expect(cancelledOrderInfo.orderHash).to.be.equal(expectedCancelledOrderHash);
|
||||
expect(cancelledOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
|
||||
expectedCancelledTakerAssetFilledAmount,
|
||||
);
|
||||
expect(cancelledOrderInfo.orderStatus).to.be.equal(expectedCancelledOrderStatus);
|
||||
|
||||
const expectedExpiredOrderHash = orderHashUtils.getOrderHashHex(expiredOrder);
|
||||
const expectedExpiredTakerAssetFilledAmount = new BigNumber(0);
|
||||
const expectedExpiredOrderStatus = OrderStatus.Expired;
|
||||
const expiredOrderInfo = ordersInfo[4];
|
||||
expect(expiredOrderInfo.orderHash).to.be.equal(expectedExpiredOrderHash);
|
||||
expect(expiredOrderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(
|
||||
expectedExpiredTakerAssetFilledAmount,
|
||||
);
|
||||
expect(expiredOrderInfo.orderStatus).to.be.equal(expectedExpiredOrderStatus);
|
||||
});
|
||||
});
|
||||
});
|
||||
}); // tslint:disable-line:max-file-line-count
|
||||
|
@@ -28,6 +28,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
const { ONE_ETHER, MAX_UINT256 } = constants;
|
||||
const { addFillResults, getPartialAmountFloor } = LibReferenceFunctions;
|
||||
const { safeSub } = UtilReferenceFunctions;
|
||||
const protocolFeeMultiplier = new BigNumber(150000);
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomAssetData = () => hexRandom(34);
|
||||
const randomAmount = (maxAmount: BigNumber = ONE_ETHER) => maxAmount.times(_.random(0, 100, true).toFixed(12));
|
||||
@@ -40,20 +41,30 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
takerAssetFilledAmount: constants.ZERO_AMOUNT,
|
||||
makerFeePaid: constants.ZERO_AMOUNT,
|
||||
takerFeePaid: constants.ZERO_AMOUNT,
|
||||
protocolFeePaid: constants.ZERO_AMOUNT,
|
||||
};
|
||||
let testContract: TestWrapperFunctionsContract;
|
||||
let txHelper: TransactionHelper;
|
||||
let owner: string;
|
||||
let senderAddress: string;
|
||||
|
||||
before(async () => {
|
||||
[senderAddress] = await env.getAccountAddressesAsync();
|
||||
[owner, senderAddress] = await env.getAccountAddressesAsync();
|
||||
txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
|
||||
testContract = await TestWrapperFunctionsContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestWrapperFunctions,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{
|
||||
...env.txDefaults,
|
||||
from: owner,
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
// Set the protocol fee multiplier.
|
||||
await testContract.updateProtocolFeeMultiplier.awaitTransactionSuccessAsync(protocolFeeMultiplier, {
|
||||
from: owner,
|
||||
});
|
||||
});
|
||||
|
||||
function randomOrder(fields?: Partial<Order>): Order {
|
||||
@@ -96,6 +107,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
takerAssetFilledAmount: order.takerAssetAmount,
|
||||
makerFeePaid: order.makerFee,
|
||||
takerFeePaid: order.takerFee,
|
||||
protocolFeePaid: protocolFeeMultiplier,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1309,50 +1321,5 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOrdersInfo', () => {
|
||||
// Computes the expected (fake) order info generated by the `TestWrapperFunctions` contract.
|
||||
function getExpectedOrderInfo(order: Order): OrderInfo {
|
||||
const MAX_ORDER_STATUS = OrderStatus.Cancelled as number;
|
||||
return {
|
||||
orderHash: getExpectedOrderHash(order),
|
||||
// Lower uint128 of `order.salt` is the `orderTakerAssetFilledAmount`.
|
||||
orderTakerAssetFilledAmount: order.salt.mod(new BigNumber(2).pow(128)),
|
||||
// High byte of `order.salt` is the `orderStatus`.
|
||||
orderStatus:
|
||||
order.salt.dividedToIntegerBy(new BigNumber(2).pow(248)).toNumber() % (MAX_ORDER_STATUS + 1),
|
||||
};
|
||||
}
|
||||
|
||||
it('works with no orders', async () => {
|
||||
const infos = await testContract.getOrdersInfo.callAsync([]);
|
||||
expect(infos.length).to.eq(0);
|
||||
});
|
||||
|
||||
it('works with one order', async () => {
|
||||
const orders = [randomOrder()];
|
||||
const expectedResult = orders.map(getExpectedOrderInfo);
|
||||
const actualResult = await testContract.getOrdersInfo.callAsync(orders);
|
||||
expect(actualResult).to.deep.eq(expectedResult);
|
||||
});
|
||||
|
||||
it('works with many orders', async () => {
|
||||
const NUM_ORDERS = 16;
|
||||
const orders = _.times(NUM_ORDERS, () => randomOrder());
|
||||
const expectedResult = orders.map(getExpectedOrderInfo);
|
||||
const actualResult = await testContract.getOrdersInfo.callAsync(orders);
|
||||
expect(actualResult).to.deep.eq(expectedResult);
|
||||
});
|
||||
|
||||
it('works with duplicate orders', async () => {
|
||||
const NUM_UNIQUE_ORDERS = 4;
|
||||
const CLONE_COUNT = 2;
|
||||
const uniqueOrders = _.times(NUM_UNIQUE_ORDERS, () => randomOrder());
|
||||
const orders = _.shuffle(_.flatten(_.times(CLONE_COUNT, () => uniqueOrders)));
|
||||
const expectedResult = orders.map(getExpectedOrderInfo);
|
||||
const actualResult = await testContract.getOrdersInfo.callAsync(orders);
|
||||
expect(actualResult).to.deep.eq(expectedResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable-next-line: max-file-line-count
|
||||
|
@@ -25,7 +25,6 @@
|
||||
"generated-artifacts/MixinMatchOrders.json",
|
||||
"generated-artifacts/MixinProtocolFees.json",
|
||||
"generated-artifacts/MixinSignatureValidator.json",
|
||||
"generated-artifacts/MixinStakingManager.json",
|
||||
"generated-artifacts/MixinTransactions.json",
|
||||
"generated-artifacts/MixinTransferSimulator.json",
|
||||
"generated-artifacts/MixinWrapperFunctions.json",
|
||||
|
@@ -21,37 +21,15 @@ pragma solidity ^0.5.9;
|
||||
|
||||
interface IStaking {
|
||||
|
||||
/// @dev Pays several protocols fee in ETH.
|
||||
/// @param makers The addresses of the order makers.
|
||||
/// @param fees The fee amounts paid by each of the makers.
|
||||
function batchPayProtocolFees(
|
||||
address[] calldata makers,
|
||||
uint256[] calldata fees
|
||||
)
|
||||
external
|
||||
payable;
|
||||
|
||||
/// @dev Pays a protocol fee in ETH.
|
||||
/// @param makerAddress The address of the order's maker.
|
||||
function payProtocolFee(address makerAddress)
|
||||
/// @param payerAddress The address that is responsible for paying the protocol fee.
|
||||
/// @param protocolFeePaid The amount of protocol fees that should be paid.
|
||||
function payProtocolFee(
|
||||
address makerAddress,
|
||||
address payerAddress,
|
||||
uint256 protocolFeePaid
|
||||
)
|
||||
external
|
||||
payable;
|
||||
|
||||
/// @dev Records several protocol fees that were paid in WETH.
|
||||
/// @param makers The addresses of the order makers.
|
||||
/// @param fees The fee amounts paid by each of the makers.
|
||||
function batchRecordProtocolFees(
|
||||
address[] calldata makers,
|
||||
uint256[] calldata fees
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Records a protocol fee that was paid in WETH.
|
||||
/// @param makerAddress The address of the order's maker.
|
||||
/// @param fee The fee amount that was paid by the maker.
|
||||
function recordProtocolFee(
|
||||
address makerAddress,
|
||||
uint256 fee
|
||||
)
|
||||
external;
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ contract Refundable {
|
||||
modifier refundFinalBalance {
|
||||
_;
|
||||
if (!shouldNotRefund) {
|
||||
msg.sender.transfer(address(this).balance);
|
||||
refundNonzeroBalance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,16 @@ contract Refundable {
|
||||
shouldNotRefund = true;
|
||||
_;
|
||||
shouldNotRefund = false;
|
||||
msg.sender.transfer(address(this).balance);
|
||||
refundNonzeroBalance();
|
||||
}
|
||||
}
|
||||
|
||||
function refundNonzeroBalance()
|
||||
internal
|
||||
{
|
||||
uint256 balance = address(this).balance;
|
||||
if (balance > 0) {
|
||||
msg.sender.transfer(balance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,13 @@ import "../src/Refundable.sol";
|
||||
contract TestRefundable is
|
||||
Refundable
|
||||
{
|
||||
function refundNonzeroBalanceExternal()
|
||||
external
|
||||
payable
|
||||
{
|
||||
refundNonzeroBalance();
|
||||
}
|
||||
|
||||
function setShouldNotRefund(bool shouldNotRefundNew)
|
||||
external
|
||||
{
|
||||
|
@@ -24,10 +24,33 @@ import "./TestRefundable.sol";
|
||||
contract TestRefundableReceiver {
|
||||
|
||||
/// @dev A payable fallback function is necessary to receive refunds from the `TestRefundable` contract.
|
||||
/// This function ensures that zero value is not sent to the contract, which tests the feature of
|
||||
/// of the `refundNonzeroBalance` that doesn't transfer if the balance is zero.
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
{
|
||||
// Ensure that a value of zero was not transferred to the contract.
|
||||
require(msg.value != 0, "Zero value should not be sent to this contract.");
|
||||
}
|
||||
|
||||
/// @dev This function tests the behavior of the `refundNonzeroBalance` function by checking whether or
|
||||
/// not the `callCounter` state variable changes after the `refundNonzeroBalance` is called.
|
||||
/// @param testRefundable The TestRefundable that should be tested against.
|
||||
function testRefundNonzeroBalance(TestRefundable testRefundable)
|
||||
external
|
||||
payable
|
||||
{
|
||||
// Call `refundNonzeroBalance()` and forward all of the eth sent to the contract.
|
||||
testRefundable.refundNonzeroBalanceExternal.value(msg.value)();
|
||||
|
||||
// If the value sent was nonzero, a check that a refund was received will be executed. Otherwise, the fallback
|
||||
// function contains a check that will fail in the event that a value of zero was sent to the contract.
|
||||
if (msg.value > 0) {
|
||||
// Ensure that a full refund was provided to this contract.
|
||||
require(address(this).balance == msg.value, "A full refund was not provided by `refundNonzeroBalance`");
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev This function tests the behavior to a simple call to `refundFinalBalanceFunction`. This
|
||||
/// test will verify that the correct refund was provided after the call (depending on whether
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -8,6 +8,9 @@ blockchainTests('Refundable', env => {
|
||||
let refundable: TestRefundableContract;
|
||||
let receiver: TestRefundableReceiverContract;
|
||||
|
||||
const ONE_HUNDRED = new BigNumber(100);
|
||||
const ONE_THOUSAND = new BigNumber(1000);
|
||||
|
||||
before(async () => {
|
||||
// Create the refundable contract.
|
||||
refundable = await TestRefundableContract.deployFrom0xArtifactAsync(
|
||||
@@ -26,13 +29,32 @@ blockchainTests('Refundable', env => {
|
||||
);
|
||||
});
|
||||
|
||||
// The contents of these typescript tests is not adequate to understand the assertions that are made during
|
||||
// these calls. For a more accurate picture, checkout out "./contracts/test/TestRefundableReceiver.sol". Specifically,
|
||||
// the function `testRefundNonzeroBalance()` is used in this test suite.
|
||||
blockchainTests.resets('refundNonzeroBalance', () => {
|
||||
it('should not send a refund when no value is sent', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded.
|
||||
await receiver.testRefundNonzeroBalance.awaitTransactionSuccessAsync(refundable.address, {
|
||||
value: constants.ZERO_AMOUNT,
|
||||
});
|
||||
});
|
||||
|
||||
it('should send a full refund when nonzero value is sent', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded.
|
||||
await receiver.testRefundNonzeroBalance.awaitTransactionSuccessAsync(refundable.address, {
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// The contents of these typescript tests is not adequate to understand the assertions that are made during
|
||||
// these calls. For a more accurate picture, checkout out "./contracts/test/TestRefundableReceiver.sol".
|
||||
blockchainTests.resets('refundFinalBalance', async () => {
|
||||
blockchainTests.resets('refundFinalBalance', () => {
|
||||
it('should fully refund the sender when `shouldNotRefund` is false', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testRefundFinalBalance.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,7 +62,7 @@ blockchainTests('Refundable', env => {
|
||||
it('should fully refund the sender when `shouldNotRefund` is false for two calls in a row', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testRefundFinalBalance.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
|
||||
// Send 1000 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
@@ -59,11 +81,11 @@ blockchainTests('Refundable', env => {
|
||||
|
||||
// The contents of these typescript tests is not adequate to understand the assertions that are made during
|
||||
// these calls. For a more accurate picture, checkout out "./contracts/test/TestRefundableReceiver.sol".
|
||||
blockchainTests.resets('disableRefundUntilEnd', async () => {
|
||||
blockchainTests.resets('disableRefundUntilEnd', () => {
|
||||
it('should fully refund the sender when `shouldNotRefund` is false', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,47 +93,47 @@ blockchainTests('Refundable', env => {
|
||||
it('should fully refund the sender when `shouldNotRefund` is false for two calls in a row', async () => {
|
||||
// Send 100 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
|
||||
// Send 1000 wei to the refundable contract that should be refunded to the receiver contract.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(1000),
|
||||
value: ONE_THOUSAND,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not refund the sender if `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `disableRefundUntilEnd` modifier and refund when `shouldNotRefund` is false', async () => {
|
||||
/// Send 100 wei to the refundable contract that should be refunded.
|
||||
await receiver.testNestedDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `refundFinalBalance` modifier and send no refund when `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testNestedDisableRefundUntilEnd.awaitTransactionSuccessAsync(refundable.address, true, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `refundFinalBalance` modifier and refund when `shouldNotRefund` is false', async () => {
|
||||
/// Send 100 wei to the refundable contract that should be refunded.
|
||||
await receiver.testMixedRefunds.awaitTransactionSuccessAsync(refundable.address, false, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
|
||||
it('should disable the `refundFinalBalance` modifier and send no refund when `shouldNotRefund` is true', async () => {
|
||||
/// Send 100 wei to the refundable contract that should not be refunded.
|
||||
await receiver.testMixedRefunds.awaitTransactionSuccessAsync(refundable.address, true, {
|
||||
value: new BigNumber(100),
|
||||
value: ONE_HUNDRED,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user