update contracts and tests to support different maker assets
This commit is contained in:
parent
0ff8b12770
commit
8077123e9f
@ -27,10 +27,12 @@ import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
|||||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
import "./libs/LibForwarderRichErrors.sol";
|
import "./libs/LibForwarderRichErrors.sol";
|
||||||
|
import "./MixinAssets.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinExchangeWrapper is
|
contract MixinExchangeWrapper is
|
||||||
LibConstants
|
LibConstants,
|
||||||
|
MixinAssets
|
||||||
{
|
{
|
||||||
using LibSafeMath for uint256;
|
using LibSafeMath for uint256;
|
||||||
|
|
||||||
@ -72,14 +74,12 @@ contract MixinExchangeWrapper is
|
|||||||
/// @param order A single order specification.
|
/// @param order A single order specification.
|
||||||
/// @param signature Signature for the given order.
|
/// @param signature Signature for the given order.
|
||||||
/// @param remainingTakerAssetFillAmount Remaining amount of WETH to sell.
|
/// @param remainingTakerAssetFillAmount Remaining amount of WETH to sell.
|
||||||
/// @param protocolFee Amount of WETH that will be spent on the protocol fee for each order.
|
|
||||||
/// @return wethSpentAmount Amount of WETH spent on the given order.
|
/// @return wethSpentAmount Amount of WETH spent on the given order.
|
||||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given order.
|
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given order.
|
||||||
function _marketSellSingleOrder(
|
function _marketSellSingleOrder(
|
||||||
LibOrder.Order memory order,
|
LibOrder.Order memory order,
|
||||||
bytes memory signature,
|
bytes memory signature,
|
||||||
uint256 remainingTakerAssetFillAmount,
|
uint256 remainingTakerAssetFillAmount
|
||||||
uint256 protocolFee
|
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
returns (
|
returns (
|
||||||
@ -92,7 +92,7 @@ contract MixinExchangeWrapper is
|
|||||||
// Attempt to sell the remaining amount of WETH
|
// Attempt to sell the remaining amount of WETH
|
||||||
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
||||||
order,
|
order,
|
||||||
remainingTakerAssetFillAmount.safeSub(protocolFee),
|
remainingTakerAssetFillAmount,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ contract MixinExchangeWrapper is
|
|||||||
uint256 takerAssetFillAmount = LibMath.getPartialAmountCeil(
|
uint256 takerAssetFillAmount = LibMath.getPartialAmountCeil(
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.takerAssetAmount.safeAdd(order.takerFee),
|
order.takerAssetAmount.safeAdd(order.takerFee),
|
||||||
remainingTakerAssetFillAmount.safeSub(protocolFee)
|
remainingTakerAssetFillAmount
|
||||||
);
|
);
|
||||||
|
|
||||||
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
||||||
@ -161,7 +161,8 @@ contract MixinExchangeWrapper is
|
|||||||
|
|
||||||
// The remaining amount of WETH to sell
|
// The remaining amount of WETH to sell
|
||||||
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||||
.safeSub(totalWethSpentAmount);
|
.safeSub(totalWethSpentAmount)
|
||||||
|
.safeSub(protocolFee);
|
||||||
|
|
||||||
(
|
(
|
||||||
uint256 wethSpentAmount,
|
uint256 wethSpentAmount,
|
||||||
@ -169,10 +170,11 @@ contract MixinExchangeWrapper is
|
|||||||
) = _marketSellSingleOrder(
|
) = _marketSellSingleOrder(
|
||||||
orders[i],
|
orders[i],
|
||||||
signatures[i],
|
signatures[i],
|
||||||
remainingTakerAssetFillAmount,
|
remainingTakerAssetFillAmount
|
||||||
protocolFee
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||||
|
|
||||||
totalWethSpentAmount = totalWethSpentAmount
|
totalWethSpentAmount = totalWethSpentAmount
|
||||||
.safeAdd(wethSpentAmount);
|
.safeAdd(wethSpentAmount);
|
||||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||||
@ -294,6 +296,8 @@ contract MixinExchangeWrapper is
|
|||||||
remainingMakerAssetFillAmount
|
remainingMakerAssetFillAmount
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||||
|
|
||||||
totalWethSpentAmount = totalWethSpentAmount
|
totalWethSpentAmount = totalWethSpentAmount
|
||||||
.safeAdd(wethSpentAmount);
|
.safeAdd(wethSpentAmount);
|
||||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||||
|
@ -28,7 +28,6 @@ import "./libs/LibConstants.sol";
|
|||||||
import "./libs/LibForwarderRichErrors.sol";
|
import "./libs/LibForwarderRichErrors.sol";
|
||||||
import "./interfaces/IAssets.sol";
|
import "./interfaces/IAssets.sol";
|
||||||
import "./interfaces/IForwarderCore.sol";
|
import "./interfaces/IForwarderCore.sol";
|
||||||
import "./MixinAssets.sol";
|
|
||||||
import "./MixinExchangeWrapper.sol";
|
import "./MixinExchangeWrapper.sol";
|
||||||
import "./MixinWeth.sol";
|
import "./MixinWeth.sol";
|
||||||
|
|
||||||
@ -38,7 +37,6 @@ contract MixinForwarderCore is
|
|||||||
IAssets,
|
IAssets,
|
||||||
IForwarderCore,
|
IForwarderCore,
|
||||||
MixinWeth,
|
MixinWeth,
|
||||||
MixinAssets,
|
|
||||||
MixinExchangeWrapper
|
MixinExchangeWrapper
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
@ -93,7 +91,8 @@ contract MixinForwarderCore is
|
|||||||
msg.value
|
msg.value
|
||||||
);
|
);
|
||||||
|
|
||||||
// Spends up to wethSellAmount to fill orders and pay WETH order fees.
|
// Spends up to wethSellAmount to fill orders, transfers purchased assets to msg.sender,
|
||||||
|
// and pays WETH order fees.
|
||||||
(
|
(
|
||||||
wethSpentAmount,
|
wethSpentAmount,
|
||||||
makerAssetAcquiredAmount
|
makerAssetAcquiredAmount
|
||||||
@ -110,12 +109,6 @@ contract MixinForwarderCore is
|
|||||||
feePercentage,
|
feePercentage,
|
||||||
feeRecipient
|
feeRecipient
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transfer purchased assets to msg.sender.
|
|
||||||
_transferAssetToSender(
|
|
||||||
orders[0].makerAssetData,
|
|
||||||
makerAssetAcquiredAmount
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||||
@ -148,9 +141,7 @@ contract MixinForwarderCore is
|
|||||||
// Convert ETH to WETH.
|
// Convert ETH to WETH.
|
||||||
_convertEthToWeth();
|
_convertEthToWeth();
|
||||||
|
|
||||||
// Attempt to fill the desired amount of makerAsset. Note that makerAssetAcquiredAmount < makerAssetBuyAmount
|
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||||
// if any of the orders filled have an takerFee denominated in makerAsset, since these fees will be paid out
|
|
||||||
// from the Forwarder's temporary makerAsset balance.
|
|
||||||
(
|
(
|
||||||
wethSpentAmount,
|
wethSpentAmount,
|
||||||
makerAssetAcquiredAmount
|
makerAssetAcquiredAmount
|
||||||
@ -167,11 +158,5 @@ contract MixinForwarderCore is
|
|||||||
feePercentage,
|
feePercentage,
|
||||||
feeRecipient
|
feeRecipient
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transfer acquired assets to msg.sender.
|
|
||||||
_transferAssetToSender(
|
|
||||||
orders[0].makerAssetData,
|
|
||||||
makerAssetAcquiredAmount
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
wethAssetData,
|
wethAssetData,
|
||||||
);
|
);
|
||||||
forwarderWrapper = new ForwarderWrapper(forwarderContract, env.provider);
|
forwarderWrapper = new ForwarderWrapper(forwarderContract, env.provider);
|
||||||
await forwarderWrapper.approveMakerAssetProxyAsync(assetDataUtils.encodeERC20AssetData(erc20Token.address), {
|
await forwarderWrapper.approveMakerAssetProxyAsync(defaultOrderParams.makerAssetData, {
|
||||||
from: takerAddress,
|
from: takerAddress,
|
||||||
});
|
});
|
||||||
erc20Wrapper.addTokenOwnerAddress(forwarderContract.address);
|
erc20Wrapper.addTokenOwnerAddress(forwarderContract.address);
|
||||||
@ -203,7 +203,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
blockchainTests.resets('marketSellOrdersWithEth without extra fees', () => {
|
blockchainTests.resets('marketSellOrdersWithEth without extra fees', () => {
|
||||||
it('should fill a single order without a taker fee', async () => {
|
it('should fill a single order without a taker fee', async () => {
|
||||||
const orderWithoutFee = await orderFactory.newSignedOrderAsync();
|
const orderWithoutFee = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([orderWithoutFee], 0.78, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([orderWithoutFee], 0.78, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill multiple orders without taker fees', async () => {
|
it('should fill multiple orders without taker fees', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync();
|
const firstOrder = await orderFactory.newSignedOrderAsync();
|
||||||
@ -212,14 +212,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(21, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(21, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.51, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.51, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill a single order with a percentage fee', async () => {
|
it('should fill a single order with a percentage fee', async () => {
|
||||||
const orderWithPercentageFee = await orderFactory.newSignedOrderAsync({
|
const orderWithPercentageFee = await orderFactory.newSignedOrderAsync({
|
||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketSellTestAsync([orderWithPercentageFee], 0.58, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([orderWithPercentageFee], 0.58, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill multiple orders with percentage fees', async () => {
|
it('should fill multiple orders with percentage fees', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -233,7 +233,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.34, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.34, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fail to fill an order with a percentage fee if the asset proxy is not yet approved', async () => {
|
it('should fail to fill an order with a percentage fee if the asset proxy is not yet approved', async () => {
|
||||||
const unapprovedAsset = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
const unapprovedAsset = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||||
@ -280,7 +280,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketSellTestAsync([orderWithWethFee], 0.13, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([orderWithWethFee], 0.13, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill multiple orders with WETH fees', async () => {
|
it('should fill multiple orders with WETH fees', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -294,7 +294,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrderWithWethFee];
|
const orders = [firstOrder, secondOrderWithWethFee];
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.25, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.25, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => {
|
it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
@ -310,6 +310,21 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
|
|
||||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||||
});
|
});
|
||||||
|
it('should fill orders with different makerAssetData', async () => {
|
||||||
|
const firstOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: firstOrderMakerAssetData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const secondOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||||
|
const secondOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: secondOrderMakerAssetData,
|
||||||
|
});
|
||||||
|
await forwarderWrapper.approveMakerAssetProxyAsync(secondOrderMakerAssetData, { from: takerAddress });
|
||||||
|
|
||||||
|
const orders = [firstOrder, secondOrder];
|
||||||
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.5, [erc20Token, secondErc20Token]);
|
||||||
|
});
|
||||||
it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => {
|
it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => {
|
||||||
const makerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
const makerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
const takerFeeAssetData = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
const takerFeeAssetData = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||||
@ -321,14 +336,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketSellTestAsync([order], 0.5, [erc20Token], {
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should fill a partially-filled order without a taker fee', async () => {
|
it('should fill a partially-filled order without a taker fee', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.3, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([order], 0.3, [erc20Token]);
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.8, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([order], 0.8, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid maker asset amount', async () => {
|
it('should skip over an order with an invalid maker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -336,7 +351,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid taker asset amount', async () => {
|
it('should skip over an order with an invalid taker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -344,7 +359,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an expired order', async () => {
|
it('should skip over an expired order', async () => {
|
||||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||||
@ -353,21 +368,21 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a fully filled order', async () => {
|
it('should skip over a fully filled order', async () => {
|
||||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder], 1, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder], 1, [erc20Token]);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a cancelled order', async () => {
|
it('should skip over a cancelled order', async () => {
|
||||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
blockchainTests.resets('marketSellOrdersWithEth with extra fees', () => {
|
blockchainTests.resets('marketSellOrdersWithEth with extra fees', () => {
|
||||||
@ -376,7 +391,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(157, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(157, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(36, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(36, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.67, erc20Token, {
|
await forwarderTestFactory.marketSellTestAsync([order], 0.67, [erc20Token], {
|
||||||
forwarderFeePercentage: new BigNumber(2),
|
forwarderFeePercentage: new BigNumber(2),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -387,7 +402,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
|
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
|
||||||
);
|
);
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketSellTestAsync([order], 0.5, [erc20Token], {
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
@ -399,7 +414,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(131, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(131, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(20, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(20, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.62, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.62, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should buy the exact amount of makerAsset in multiple orders', async () => {
|
it('should buy the exact amount of makerAsset in multiple orders', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync();
|
const firstOrder = await orderFactory.newSignedOrderAsync();
|
||||||
@ -408,14 +423,29 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
await forwarderTestFactory.marketBuyTestAsync(orders, 1.96, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync(orders, 1.96, [erc20Token]);
|
||||||
|
});
|
||||||
|
it('should buy exactly makerAssetBuyAmount in orders with different makerAssetData', async () => {
|
||||||
|
const firstOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: firstOrderMakerAssetData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const secondOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||||
|
const secondOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: secondOrderMakerAssetData,
|
||||||
|
});
|
||||||
|
await forwarderWrapper.approveMakerAssetProxyAsync(secondOrderMakerAssetData, { from: takerAddress });
|
||||||
|
|
||||||
|
const orders = [firstOrder, secondOrder];
|
||||||
|
await forwarderTestFactory.marketBuyTestAsync(orders, 1.5, [erc20Token, secondErc20Token]);
|
||||||
});
|
});
|
||||||
it('should buy the exact amount of makerAsset and return excess ETH', async () => {
|
it('should buy the exact amount of makerAsset and return excess ETH', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync({
|
const order = await orderFactory.newSignedOrderAsync({
|
||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(80, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(80, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.57, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.57, [erc20Token], {
|
||||||
ethValueAdjustment: 2,
|
ethValueAdjustment: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -426,7 +456,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.38, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.38, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should buy the exact amount of makerAsset from a single order with a percentage fee', async () => {
|
it('should buy the exact amount of makerAsset from a single order with a percentage fee', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync({
|
const order = await orderFactory.newSignedOrderAsync({
|
||||||
@ -435,7 +465,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.52, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.52, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
|
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
@ -444,7 +474,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
);
|
);
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
ethValueAdjustment: -2,
|
ethValueAdjustment: -2,
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
@ -456,7 +486,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([erc721Order], 1, erc721Token, {
|
await forwarderTestFactory.marketBuyTestAsync([erc721Order], 1, [erc721Token], {
|
||||||
makerAssetId,
|
makerAssetId,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -468,7 +498,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], 1, erc721Token, {
|
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], 1, [erc721Token], {
|
||||||
makerAssetId,
|
makerAssetId,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -483,14 +513,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should fill a partially-filled order without a taker fee', async () => {
|
it('should fill a partially-filled order without a taker fee', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.3, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.3, [erc20Token]);
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.8, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.8, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid maker asset amount', async () => {
|
it('should skip over an order with an invalid maker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -498,7 +528,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid taker asset amount', async () => {
|
it('should skip over an order with an invalid taker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -506,7 +536,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an expired order', async () => {
|
it('should skip over an expired order', async () => {
|
||||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||||
@ -515,21 +545,21 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a fully filled order', async () => {
|
it('should skip over a fully filled order', async () => {
|
||||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder], 1, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder], 1, [erc20Token]);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a cancelled order', async () => {
|
it('should skip over a cancelled order', async () => {
|
||||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('Should buy slightly greater makerAsset when exchange rate is rounded', async () => {
|
it('Should buy slightly greater makerAsset when exchange rate is rounded', async () => {
|
||||||
// The 0x Protocol contracts round the exchange rate in favor of the Maker.
|
// The 0x Protocol contracts round the exchange rate in favor of the Maker.
|
||||||
@ -649,7 +679,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(125, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(125, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.33, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.33, [erc20Token], {
|
||||||
forwarderFeePercentage: new BigNumber(2),
|
forwarderFeePercentage: new BigNumber(2),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -658,7 +688,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
|
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
|
||||||
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, new BigNumber(6)),
|
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, new BigNumber(6)),
|
||||||
);
|
);
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
forwarderFeePercentage: new BigNumber(6),
|
forwarderFeePercentage: new BigNumber(6),
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
@ -674,7 +704,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const revertError = new ForwarderRevertErrors.InsufficientEthForFeeError(ethFee, ethFee.minus(1));
|
const revertError = new ForwarderRevertErrors.InsufficientEthForFeeError(ethFee, ethFee.minus(1));
|
||||||
|
|
||||||
// -2 to compensate for the extra 1 wei added in ForwarderTestFactory to account for rounding
|
// -2 to compensate for the extra 1 wei added in ForwarderTestFactory to account for rounding
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
ethValueAdjustment: -2,
|
ethValueAdjustment: -2,
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
revertError,
|
revertError,
|
||||||
|
@ -3,6 +3,7 @@ import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
|||||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||||
import { ExchangeWrapper } from '@0x/contracts-exchange';
|
import { ExchangeWrapper } from '@0x/contracts-exchange';
|
||||||
import { constants, ERC20BalancesByOwner, expect, OrderStatus, web3Wrapper } from '@0x/contracts-test-utils';
|
import { constants, ERC20BalancesByOwner, expect, OrderStatus, web3Wrapper } from '@0x/contracts-test-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { OrderInfo, SignedOrder } from '@0x/types';
|
import { OrderInfo, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber, RevertError } from '@0x/utils';
|
import { BigNumber, RevertError } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -12,10 +13,14 @@ import { ForwarderWrapper } from './forwarder_wrapper';
|
|||||||
// Necessary bookkeeping to validate Forwarder results
|
// Necessary bookkeeping to validate Forwarder results
|
||||||
interface ForwarderFillState {
|
interface ForwarderFillState {
|
||||||
takerAssetFillAmount: BigNumber;
|
takerAssetFillAmount: BigNumber;
|
||||||
makerAssetFillAmount: BigNumber;
|
makerAssetFillAmount: {
|
||||||
|
[makerAssetData: string]: BigNumber;
|
||||||
|
};
|
||||||
protocolFees: BigNumber;
|
protocolFees: BigNumber;
|
||||||
wethFees: BigNumber;
|
wethFees: BigNumber;
|
||||||
percentageFees: BigNumber;
|
percentageFees: {
|
||||||
|
[makerAssetData: string]: BigNumber;
|
||||||
|
};
|
||||||
maxOversoldWeth: BigNumber;
|
maxOversoldWeth: BigNumber;
|
||||||
maxOverboughtMakerAsset: BigNumber;
|
maxOverboughtMakerAsset: BigNumber;
|
||||||
}
|
}
|
||||||
@ -51,7 +56,7 @@ export class ForwarderTestFactory {
|
|||||||
public async marketBuyTestAsync(
|
public async marketBuyTestAsync(
|
||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
||||||
fractionalNumberOfOrdersToFill: number,
|
fractionalNumberOfOrdersToFill: number,
|
||||||
makerAssetContract: DummyERC20TokenContract | DummyERC721TokenContract,
|
makerAssetContracts: Array<DummyERC20TokenContract | DummyERC721TokenContract>,
|
||||||
options: {
|
options: {
|
||||||
ethValueAdjustment?: number; // Used to provided insufficient/excess ETH
|
ethValueAdjustment?: number; // Used to provided insufficient/excess ETH
|
||||||
forwarderFeePercentage?: BigNumber;
|
forwarderFeePercentage?: BigNumber;
|
||||||
@ -83,9 +88,16 @@ export class ForwarderTestFactory {
|
|||||||
constants.PERCENTAGE_DENOMINATOR,
|
constants.PERCENTAGE_DENOMINATOR,
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const totalMakerAssetFillAmount = Object.values(expectedResults.makerAssetFillAmount).reduce((prev, current) =>
|
||||||
|
prev.plus(current),
|
||||||
|
);
|
||||||
|
const totalPercentageFees = Object.values(expectedResults.percentageFees).reduce((prev, current) =>
|
||||||
|
prev.plus(current),
|
||||||
|
);
|
||||||
const tx = this._forwarderWrapper.marketBuyOrdersWithEthAsync(
|
const tx = this._forwarderWrapper.marketBuyOrdersWithEthAsync(
|
||||||
orders,
|
orders,
|
||||||
expectedResults.makerAssetFillAmount.minus(expectedResults.percentageFees),
|
totalMakerAssetFillAmount.minus(totalPercentageFees),
|
||||||
{
|
{
|
||||||
value: ethValue,
|
value: ethValue,
|
||||||
from: this._takerAddress,
|
from: this._takerAddress,
|
||||||
@ -110,7 +122,7 @@ export class ForwarderTestFactory {
|
|||||||
expectedResults,
|
expectedResults,
|
||||||
takerEthBalanceBefore,
|
takerEthBalanceBefore,
|
||||||
erc20Balances,
|
erc20Balances,
|
||||||
makerAssetContract,
|
makerAssetContracts,
|
||||||
{
|
{
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
forwarderFeeRecipientEthBalanceBefore,
|
forwarderFeeRecipientEthBalanceBefore,
|
||||||
@ -123,7 +135,7 @@ export class ForwarderTestFactory {
|
|||||||
public async marketSellTestAsync(
|
public async marketSellTestAsync(
|
||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
||||||
fractionalNumberOfOrdersToFill: number,
|
fractionalNumberOfOrdersToFill: number,
|
||||||
makerAssetContract: DummyERC20TokenContract,
|
makerAssetContracts: DummyERC20TokenContract[],
|
||||||
options: {
|
options: {
|
||||||
forwarderFeePercentage?: BigNumber;
|
forwarderFeePercentage?: BigNumber;
|
||||||
revertError?: RevertError;
|
revertError?: RevertError;
|
||||||
@ -179,7 +191,7 @@ export class ForwarderTestFactory {
|
|||||||
expectedResults,
|
expectedResults,
|
||||||
takerEthBalanceBefore,
|
takerEthBalanceBefore,
|
||||||
erc20Balances,
|
erc20Balances,
|
||||||
makerAssetContract,
|
makerAssetContracts,
|
||||||
{
|
{
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
forwarderFeeRecipientEthBalanceBefore,
|
forwarderFeeRecipientEthBalanceBefore,
|
||||||
@ -195,31 +207,35 @@ export class ForwarderTestFactory {
|
|||||||
makerAssetContract: DummyERC20TokenContract,
|
makerAssetContract: DummyERC20TokenContract,
|
||||||
): void {
|
): void {
|
||||||
const makerAssetAddress = makerAssetContract.address;
|
const makerAssetAddress = makerAssetContract.address;
|
||||||
|
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerAssetAddress);
|
||||||
|
|
||||||
|
const {
|
||||||
|
maxOverboughtMakerAsset,
|
||||||
|
makerAssetFillAmount: { [makerAssetData]: makerAssetFillAmount },
|
||||||
|
percentageFees: { [makerAssetData]: percentageFees },
|
||||||
|
} = expectedResults;
|
||||||
|
|
||||||
expectBalanceWithin(
|
expectBalanceWithin(
|
||||||
newBalances[this._makerAddress][makerAssetAddress],
|
newBalances[this._makerAddress][makerAssetAddress],
|
||||||
oldBalances[this._makerAddress][makerAssetAddress]
|
oldBalances[this._makerAddress][makerAssetAddress]
|
||||||
.minus(expectedResults.makerAssetFillAmount)
|
.minus(makerAssetFillAmount)
|
||||||
.minus(expectedResults.maxOverboughtMakerAsset),
|
.minus(maxOverboughtMakerAsset),
|
||||||
oldBalances[this._makerAddress][makerAssetAddress].minus(expectedResults.makerAssetFillAmount),
|
oldBalances[this._makerAddress][makerAssetAddress].minus(makerAssetFillAmount),
|
||||||
'Maker makerAsset balance',
|
'Maker makerAsset balance',
|
||||||
);
|
);
|
||||||
expectBalanceWithin(
|
expectBalanceWithin(
|
||||||
newBalances[this._takerAddress][makerAssetAddress],
|
newBalances[this._takerAddress][makerAssetAddress],
|
||||||
|
oldBalances[this._takerAddress][makerAssetAddress].plus(makerAssetFillAmount).minus(percentageFees),
|
||||||
oldBalances[this._takerAddress][makerAssetAddress]
|
oldBalances[this._takerAddress][makerAssetAddress]
|
||||||
.plus(expectedResults.makerAssetFillAmount)
|
.plus(makerAssetFillAmount)
|
||||||
.minus(expectedResults.percentageFees),
|
.minus(percentageFees)
|
||||||
oldBalances[this._takerAddress][makerAssetAddress]
|
.plus(maxOverboughtMakerAsset),
|
||||||
.plus(expectedResults.makerAssetFillAmount)
|
|
||||||
.minus(expectedResults.percentageFees)
|
|
||||||
.plus(expectedResults.maxOverboughtMakerAsset),
|
|
||||||
'Taker makerAsset balance',
|
'Taker makerAsset balance',
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
newBalances[this._orderFeeRecipientAddress][makerAssetAddress],
|
newBalances[this._orderFeeRecipientAddress][makerAssetAddress],
|
||||||
'Order fee recipient makerAsset balance',
|
'Order fee recipient makerAsset balance',
|
||||||
).to.be.bignumber.equal(
|
).to.be.bignumber.equal(oldBalances[this._orderFeeRecipientAddress][makerAssetAddress].plus(percentageFees));
|
||||||
oldBalances[this._orderFeeRecipientAddress][makerAssetAddress].plus(expectedResults.percentageFees),
|
|
||||||
);
|
|
||||||
expect(
|
expect(
|
||||||
newBalances[this._forwarderAddress][makerAssetAddress],
|
newBalances[this._forwarderAddress][makerAssetAddress],
|
||||||
'Forwarder contract makerAsset balance',
|
'Forwarder contract makerAsset balance',
|
||||||
@ -234,7 +250,7 @@ export class ForwarderTestFactory {
|
|||||||
expectedResults: ForwarderFillState,
|
expectedResults: ForwarderFillState,
|
||||||
takerEthBalanceBefore: BigNumber,
|
takerEthBalanceBefore: BigNumber,
|
||||||
erc20Balances: ERC20BalancesByOwner,
|
erc20Balances: ERC20BalancesByOwner,
|
||||||
makerAssetContract: DummyERC20TokenContract | DummyERC721TokenContract,
|
makerAssetContracts: Array<DummyERC20TokenContract | DummyERC721TokenContract>,
|
||||||
options: {
|
options: {
|
||||||
forwarderFeePercentage?: BigNumber;
|
forwarderFeePercentage?: BigNumber;
|
||||||
forwarderFeeRecipientEthBalanceBefore?: BigNumber;
|
forwarderFeeRecipientEthBalanceBefore?: BigNumber;
|
||||||
@ -277,11 +293,13 @@ export class ForwarderTestFactory {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (makerAssetContract instanceof DummyERC20TokenContract) {
|
for (const makerAssetContract of makerAssetContracts) {
|
||||||
this._checkErc20Balances(erc20Balances, newBalances, expectedResults, makerAssetContract);
|
if (makerAssetContract instanceof DummyERC20TokenContract) {
|
||||||
} else if (options.makerAssetId !== undefined) {
|
this._checkErc20Balances(erc20Balances, newBalances, expectedResults, makerAssetContract);
|
||||||
const newOwner = await makerAssetContract.ownerOf.callAsync(options.makerAssetId);
|
} else if (options.makerAssetId !== undefined) {
|
||||||
expect(newOwner, 'New ERC721 owner').to.be.bignumber.equal(this._takerAddress);
|
const newOwner = await makerAssetContract.ownerOf.callAsync(options.makerAssetId);
|
||||||
|
expect(newOwner, 'New ERC721 owner').to.be.bignumber.equal(this._takerAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expectBalanceWithin(
|
expectBalanceWithin(
|
||||||
@ -313,18 +331,25 @@ export class ForwarderTestFactory {
|
|||||||
ordersInfoBefore: OrderInfo[],
|
ordersInfoBefore: OrderInfo[],
|
||||||
fractionalNumberOfOrdersToFill: number,
|
fractionalNumberOfOrdersToFill: number,
|
||||||
): ForwarderFillState {
|
): ForwarderFillState {
|
||||||
const currentState = {
|
const currentState: ForwarderFillState = {
|
||||||
takerAssetFillAmount: constants.ZERO_AMOUNT,
|
takerAssetFillAmount: constants.ZERO_AMOUNT,
|
||||||
makerAssetFillAmount: constants.ZERO_AMOUNT,
|
makerAssetFillAmount: {},
|
||||||
protocolFees: constants.ZERO_AMOUNT,
|
protocolFees: constants.ZERO_AMOUNT,
|
||||||
wethFees: constants.ZERO_AMOUNT,
|
wethFees: constants.ZERO_AMOUNT,
|
||||||
percentageFees: constants.ZERO_AMOUNT,
|
percentageFees: {},
|
||||||
maxOversoldWeth: constants.ZERO_AMOUNT,
|
maxOversoldWeth: constants.ZERO_AMOUNT,
|
||||||
maxOverboughtMakerAsset: constants.ZERO_AMOUNT,
|
maxOverboughtMakerAsset: constants.ZERO_AMOUNT,
|
||||||
};
|
};
|
||||||
let remainingOrdersToFill = fractionalNumberOfOrdersToFill;
|
let remainingOrdersToFill = fractionalNumberOfOrdersToFill;
|
||||||
|
|
||||||
for (const [i, order] of orders.entries()) {
|
for (const [i, order] of orders.entries()) {
|
||||||
|
if (currentState.makerAssetFillAmount[order.makerAssetData] === undefined) {
|
||||||
|
currentState.makerAssetFillAmount[order.makerAssetData] = new BigNumber(0);
|
||||||
|
}
|
||||||
|
if (currentState.percentageFees[order.makerAssetData] === undefined) {
|
||||||
|
currentState.percentageFees[order.makerAssetData] = new BigNumber(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (remainingOrdersToFill === 0) {
|
if (remainingOrdersToFill === 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -365,7 +390,9 @@ export class ForwarderTestFactory {
|
|||||||
makerAssetAmount = BigNumber.max(makerAssetAmount.minus(makerAssetFilled), constants.ZERO_AMOUNT);
|
makerAssetAmount = BigNumber.max(makerAssetAmount.minus(makerAssetFilled), constants.ZERO_AMOUNT);
|
||||||
|
|
||||||
currentState.takerAssetFillAmount = currentState.takerAssetFillAmount.plus(takerAssetAmount);
|
currentState.takerAssetFillAmount = currentState.takerAssetFillAmount.plus(takerAssetAmount);
|
||||||
currentState.makerAssetFillAmount = currentState.makerAssetFillAmount.plus(makerAssetAmount);
|
currentState.makerAssetFillAmount[order.makerAssetData] = currentState.makerAssetFillAmount[
|
||||||
|
order.makerAssetData
|
||||||
|
].plus(makerAssetAmount);
|
||||||
|
|
||||||
if (this._protocolFeeCollectorAddress !== constants.NULL_ADDRESS) {
|
if (this._protocolFeeCollectorAddress !== constants.NULL_ADDRESS) {
|
||||||
currentState.protocolFees = currentState.protocolFees.plus(
|
currentState.protocolFees = currentState.protocolFees.plus(
|
||||||
@ -373,7 +400,9 @@ export class ForwarderTestFactory {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (order.takerFeeAssetData === order.makerAssetData) {
|
if (order.takerFeeAssetData === order.makerAssetData) {
|
||||||
currentState.percentageFees = currentState.percentageFees.plus(takerFee);
|
currentState.percentageFees[order.makerAssetData] = currentState.percentageFees[
|
||||||
|
order.makerAssetData
|
||||||
|
].plus(takerFee);
|
||||||
} else if (order.takerFeeAssetData === order.takerAssetData) {
|
} else if (order.takerFeeAssetData === order.takerAssetData) {
|
||||||
currentState.wethFees = currentState.wethFees.plus(takerFee);
|
currentState.wethFees = currentState.wethFees.plus(takerFee);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user