@0x/contracts-exchange: Rename marketSellOrders and marketBuyOrders back to marketSellOrdersNoThrow and marketBuyOrdersNoThrow.

`@0x/contracts-exchange`: Introduce new `marketSellOrdersFillOrKill` and `marketBuyOrdersFillOrKill` functions.
`@0x/contracts-exchange`: Add new rich error types: `IncompleteMarketBuyError` and `IncompleteMarketSellError`.
`@0x/contracts-exchange`: Use `abi.decode()` in `LibExchangeRichErrorDecoder` over `LibBytes`.
This commit is contained in:
Lawrence Forman
2019-08-16 16:51:35 -04:00
parent 1698519a6a
commit 96bef08ac2
10 changed files with 964 additions and 537 deletions

View File

@@ -170,7 +170,7 @@ contract MixinWrapperFunctions is
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketSellOrders(
function marketSellOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
bytes[] memory signatures
@@ -214,7 +214,7 @@ contract MixinWrapperFunctions is
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketBuyOrders(
function marketBuyOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
bytes[] memory signatures
@@ -261,6 +261,50 @@ contract MixinWrapperFunctions is
return fillResults;
}
/// @dev Calls marketSellOrdersNoThrow then reverts if < takerAssetFillAmount has been sold.
/// @param orders Array of order specifications.
/// @param takerAssetFillAmount Minimum amount of takerAsset to sell.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketSellOrdersFillOrKill(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
bytes[] memory signatures
)
public
returns (LibFillResults.FillResults memory fillResults)
{
fillResults = marketSellOrdersNoThrow(orders, takerAssetFillAmount, signatures);
if (fillResults.takerAssetFilledAmount < takerAssetFillAmount) {
LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteMarketSellError(
takerAssetFillAmount,
_getOrderHashes(orders)
));
}
}
/// @dev Calls marketBuyOrdersNoThrow then reverts if < makerAssetFillAmount has been bought.
/// @param orders Array of order specifications.
/// @param makerAssetFillAmount Minimum amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketBuyOrdersFillOrKill(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
bytes[] memory signatures
)
public
returns (LibFillResults.FillResults memory fillResults)
{
fillResults = marketBuyOrdersNoThrow(orders, makerAssetFillAmount, signatures);
if (fillResults.makerAssetFilledAmount < makerAssetFillAmount) {
LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteMarketBuyError(
makerAssetFillAmount,
_getOrderHashes(orders)
));
}
}
/// @dev Executes multiple calls of cancelOrder.
/// @param orders Array of order specifications.
function batchCancelOrders(LibOrder.Order[] memory orders)
@@ -308,9 +352,25 @@ contract MixinWrapperFunctions is
);
if (fillResults.takerAssetFilledAmount != takerAssetFillAmount) {
LibRichErrors.rrevert(LibExchangeRichErrors.IncompleteFillError(
takerAssetFillAmount,
getOrderInfo(order).orderHash
));
}
return fillResults;
}
/// @dev Computes the hashes of multiple orders.
/// @param orders Array of orders.
/// @return orderHashes Array of order hashes for each respective order in `orders`.
function _getOrderHashes(LibOrder.Order[] memory orders)
internal
view
returns (bytes32[] memory orderHashes)
{
uint256 ordersLength = orders.length;
orderHashes = new bytes32[](ordersLength);
for (uint256 i = 0; i != ordersLength; i++) {
orderHashes[i] = orders[i].getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH);
}
}
}

View File

@@ -96,7 +96,7 @@ contract IWrapperFunctions {
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketSellOrders(
function marketSellOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
bytes[] memory signatures
@@ -109,7 +109,33 @@ contract IWrapperFunctions {
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketBuyOrders(
function marketBuyOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
bytes[] memory signatures
)
public
returns (LibFillResults.FillResults memory fillResults);
/// @dev Calls marketSellOrdersNoThrow then reverts if < takerAssetFillAmount has been sold.
/// @param orders Array of order specifications.
/// @param takerAssetFillAmount Minimum amount of takerAsset to sell.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketSellOrdersFillOrKill(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
bytes[] memory signatures
)
public
returns (LibFillResults.FillResults memory fillResults);
/// @dev Calls marketBuyOrdersNoThrow then reverts if < makerAssetFillAmount has been bought.
/// @param orders Array of order specifications.
/// @param makerAssetFillAmount Minimum amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
function marketBuyOrdersFillOrKill(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
bytes[] memory signatures

View File

@@ -25,6 +25,8 @@ import "@0x/contracts-utils/contracts/src/LibBytes.sol";
contract LibExchangeRichErrorDecoder {
using LibBytes for bytes;
/// @dev Decompose an ABI-encoded SignatureError.
/// @param encoded ABI-encoded revert error.
/// @return errorCode The error code.
@@ -41,10 +43,12 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureErrorSelector());
errorCode = LibExchangeRichErrors.SignatureErrorCodes(_readErrorParameterAsUint256(encoded, 0));
hash = _readErrorParameterAsBytes32(encoded, 1);
signerAddress = _readErrorParameterAsAddress(encoded, 2);
signature = _readErrorParameterAsBytes(encoded, 3);
uint8 _errorCode;
(_errorCode, hash, signerAddress, signature) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint8, bytes32, address, bytes)
);
errorCode = LibExchangeRichErrors.SignatureErrorCodes(_errorCode);
}
/// @dev Decompose an ABI-encoded SignatureValidatorError.
@@ -64,11 +68,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureValidatorErrorSelector());
hash = _readErrorParameterAsBytes32(encoded, 0);
signerAddress = _readErrorParameterAsAddress(encoded, 1);
validatorAddress = _readErrorParameterAsAddress(encoded, 2);
signature = _readErrorParameterAsBytes(encoded, 3);
errorData = _readErrorParameterAsBytes(encoded, 4);
(hash, signerAddress, validatorAddress, signature, errorData) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, address, address, bytes, bytes)
);
}
/// @dev Decompose an ABI-encoded SignatureValidatorNotApprovedError.
@@ -84,8 +87,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureValidatorNotApprovedErrorSelector());
signerAddress = _readErrorParameterAsAddress(encoded, 0);
validatorAddress = _readErrorParameterAsAddress(encoded, 1);
(signerAddress, validatorAddress) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(address, address)
);
}
/// @dev Decompose an ABI-encoded SignatureWalletError.
@@ -105,10 +110,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.SignatureWalletErrorSelector());
hash = _readErrorParameterAsBytes32(encoded, 0);
signerAddress = _readErrorParameterAsAddress(encoded, 1);
signature = _readErrorParameterAsBytes(encoded, 2);
errorData = _readErrorParameterAsBytes(encoded, 3);
(hash, signerAddress, signature, errorData) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, address, bytes, bytes)
);
}
/// @dev Decompose an ABI-encoded OrderStatusError.
@@ -124,8 +129,12 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.OrderStatusErrorSelector());
orderHash = _readErrorParameterAsBytes32(encoded, 0);
orderStatus = LibOrder.OrderStatus(_readErrorParameterAsUint256(encoded, 1));
uint8 _orderStatus;
(orderHash, _orderStatus) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, uint8)
);
orderStatus = LibOrder.OrderStatus(_orderStatus);
}
/// @dev Decompose an ABI-encoded InvalidSenderError.
@@ -141,8 +150,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.InvalidSenderErrorSelector());
orderHash = _readErrorParameterAsBytes32(encoded, 0);
senderAddress = _readErrorParameterAsAddress(encoded, 1);
(orderHash, senderAddress) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, address)
);
}
/// @dev Decompose an ABI-encoded InvalidMakerError.
@@ -158,8 +169,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.InvalidMakerErrorSelector());
orderHash = _readErrorParameterAsBytes32(encoded, 0);
makerAddress = _readErrorParameterAsAddress(encoded, 1);
(orderHash, makerAddress) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, address)
);
}
/// @dev Decompose an ABI-encoded InvalidTaker.
@@ -175,8 +188,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.InvalidTakerErrorSelector());
orderHash = _readErrorParameterAsBytes32(encoded, 0);
takerAddress = _readErrorParameterAsAddress(encoded, 1);
(orderHash, takerAddress) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, address)
);
}
/// @dev Decompose an ABI-encoded FillError.
@@ -192,8 +207,12 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.FillErrorSelector());
errorCode = LibExchangeRichErrors.FillErrorCodes(_readErrorParameterAsUint256(encoded, 0));
orderHash = _readErrorParameterAsBytes32(encoded, 1);
uint8 _errorCode;
(_errorCode, orderHash) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint8, bytes32)
);
errorCode = LibExchangeRichErrors.FillErrorCodes(_errorCode);
}
/// @dev Decompose an ABI-encoded OrderEpochError.
@@ -211,9 +230,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.OrderEpochErrorSelector());
makerAddress = _readErrorParameterAsAddress(encoded, 0);
orderSenderAddress = _readErrorParameterAsAddress(encoded, 1);
currentEpoch = _readErrorParameterAsUint256(encoded, 2);
(makerAddress, orderSenderAddress, currentEpoch) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(address, address, uint256)
);
}
/// @dev Decompose an ABI-encoded AssetProxyExistsError.
@@ -225,7 +245,10 @@ contract LibExchangeRichErrorDecoder {
returns (address assetProxyAddress)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyExistsErrorSelector());
assetProxyAddress = _readErrorParameterAsAddress(encoded, 0);
(assetProxyAddress) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(address)
);
}
/// @dev Decompose an ABI-encoded AssetProxyDispatchError.
@@ -243,9 +266,12 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyDispatchErrorSelector());
errorCode = LibExchangeRichErrors.AssetProxyDispatchErrorCodes(_readErrorParameterAsUint256(encoded, 0));
orderHash = _readErrorParameterAsBytes32(encoded, 1);
assetData = _readErrorParameterAsBytes(encoded, 2);
uint8 _errorCode;
(_errorCode, orderHash, assetData) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint8, bytes32, bytes)
);
errorCode = LibExchangeRichErrors.AssetProxyDispatchErrorCodes(_errorCode);
}
/// @dev Decompose an ABI-encoded AssetProxyTransferError.
@@ -263,9 +289,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.AssetProxyTransferErrorSelector());
orderHash = _readErrorParameterAsBytes32(encoded, 0);
assetData = _readErrorParameterAsBytes(encoded, 1);
errorData = _readErrorParameterAsBytes(encoded, 2);
(orderHash, assetData, errorData) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, bytes, bytes)
);
}
/// @dev Decompose an ABI-encoded NegativeSpreadError.
@@ -281,8 +308,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.NegativeSpreadErrorSelector());
leftOrderHash = _readErrorParameterAsBytes32(encoded, 0);
rightOrderHash = _readErrorParameterAsBytes32(encoded, 1);
(leftOrderHash, rightOrderHash) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, bytes32)
);
}
/// @dev Decompose an ABI-encoded TransactionError.
@@ -298,8 +327,12 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionErrorSelector());
errorCode = LibExchangeRichErrors.TransactionErrorCodes(_readErrorParameterAsUint256(encoded, 0));
transactionHash = _readErrorParameterAsBytes32(encoded, 1);
uint8 _errorCode;
(_errorCode, transactionHash) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint8, bytes32)
);
errorCode = LibExchangeRichErrors.TransactionErrorCodes(_errorCode);
}
/// @dev Decompose an ABI-encoded TransactionSignatureError.
@@ -317,9 +350,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionSignatureErrorSelector());
transactionHash = _readErrorParameterAsBytes32(encoded, 0);
signerAddress = _readErrorParameterAsAddress(encoded, 1);
signature = _readErrorParameterAsBytes(encoded, 2);
(transactionHash, signerAddress, signature) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, address, bytes)
);
}
/// @dev Decompose an ABI-encoded TransactionExecutionError.
@@ -335,8 +369,10 @@ contract LibExchangeRichErrorDecoder {
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.TransactionExecutionErrorSelector());
transactionHash = _readErrorParameterAsBytes32(encoded, 0);
errorData = _readErrorParameterAsBytes(encoded, 1);
(transactionHash, errorData) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(bytes32, bytes)
);
}
/// @dev Decompose an ABI-encoded IncompleteFillError.
@@ -346,11 +382,51 @@ contract LibExchangeRichErrorDecoder {
public
pure
returns (
uint256 fillAmount,
bytes32 orderHash
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.IncompleteFillErrorSelector());
orderHash = _readErrorParameterAsBytes32(encoded, 0);
(fillAmount, orderHash) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint256, bytes32)
);
}
/// @dev Decompose an ABI-encoded IncompleteMarketSellError.
/// @param encoded ABI-encoded revert error.
/// @return orderHash Hash of the order being filled.
function decodeIncompleteMarketSellError(bytes memory encoded)
public
pure
returns (
uint256 takerAssetFillAmount,
bytes32[] memory orderHashes
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.IncompleteMarketSellErrorSelector());
(takerAssetFillAmount, orderHashes) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint256, bytes32[])
);
}
/// @dev Decompose an ABI-encoded IncompleteMarketBuyError.
/// @param encoded ABI-encoded revert error.
/// @return orderHash Hash of the order being filled.
function decodeIncompleteMarketBuyError(bytes memory encoded)
public
pure
returns (
uint256 makerAssetFillAmount,
bytes32[] memory orderHashes
)
{
_assertSelectorBytes(encoded, LibExchangeRichErrors.IncompleteMarketBuyErrorSelector());
(makerAssetFillAmount, orderHashes) = abi.decode(
encoded.sliceDestructive(4, encoded.length),
(uint256, bytes32[])
);
}
/// @dev Revert if the leading 4 bytes of `encoded` is not `selector`.
@@ -364,53 +440,4 @@ contract LibExchangeRichErrorDecoder {
"BAD_SELECTOR"
);
}
/// @dev Read a parameter at index `index` as a uint256.
function _readErrorParameterAsUint256(bytes memory encoded, uint256 index)
private
pure
returns (uint256 value)
{
uint256 parameterOffset = 4 + index * 32;
return LibBytes.readUint256(encoded, parameterOffset);
}
/// @dev Read a parameter at index `index` as a bytes32.
function _readErrorParameterAsBytes32(bytes memory encoded, uint256 index)
private
pure
returns (bytes32 value)
{
uint256 parameterOffset = 4 + index * 32;
return LibBytes.readBytes32(encoded, parameterOffset);
}
/// @dev Read a parameter at index `index` as an address.
function _readErrorParameterAsAddress(bytes memory encoded, uint256 index)
private
pure
returns (address value)
{
uint256 parameterOffset = 4 + index * 32;
return address(uint160(LibBytes.readUint256(encoded, parameterOffset)));
}
/// @dev Read a parameter at index `index` as a bytes.
function _readErrorParameterAsBytes(bytes memory encoded, uint256 index)
private
pure
returns (bytes memory value)
{
uint256 dataOffset = 4 + _readErrorParameterAsUint256(encoded, index);
return LibBytes.readBytesWithLength(encoded, dataOffset);
}
/// @dev Read a parameter at index `index` as a string.
function _readErrorParameterAsString(bytes memory encoded, uint256 index)
private
pure
returns (string memory value)
{
return string(_readErrorParameterAsBytes(encoded, index));
}
}

View File

@@ -1,6 +1,14 @@
import { addressUtils, blockchainTests, expect, hexRandom, OrderStatus, orderUtils } from '@0x/contracts-test-utils';
import {
addressUtils,
blockchainTests,
constants,
expect,
hexRandom,
OrderStatus,
orderUtils,
} from '@0x/contracts-test-utils';
import { ExchangeRevertErrors, generatePseudoRandomSalt } from '@0x/order-utils';
import { RevertError } from '@0x/utils';
import { BigNumber, RevertError } from '@0x/utils';
import * as _ from 'lodash';
import { artifacts, TestLibExchangeRichErrorDecoderContract } from '../src';
@@ -9,6 +17,7 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })
const SIGNATURE_LENGTH = 66;
const ASSET_DATA_LENGTH = 36;
const ERROR_DATA_LENGTH = 100;
const { WORD_LENGTH } = constants;
let decoder: TestLibExchangeRichErrorDecoderContract;
before(async () => {
@@ -138,6 +147,19 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })
(() => {
const orderHash = orderUtils.generatePseudoRandomOrderHash();
createDecodeTest(ExchangeRevertErrors.IncompleteFillError, [orderHash]);
const amount = new BigNumber(hexRandom(WORD_LENGTH));
createDecodeTest(ExchangeRevertErrors.IncompleteFillError, [amount, orderHash]);
})();
(() => {
const orderHashes = _.times(3, () => orderUtils.generatePseudoRandomOrderHash());
const amount = new BigNumber(hexRandom(WORD_LENGTH));
createDecodeTest(ExchangeRevertErrors.IncompleteMarketSellError, [amount, orderHashes]);
})();
(() => {
const orderHashes = _.times(3, () => orderUtils.generatePseudoRandomOrderHash());
const amount = new BigNumber(hexRandom(WORD_LENGTH));
createDecodeTest(ExchangeRevertErrors.IncompleteMarketBuyError, [amount, orderHashes]);
})();
});

View File

@@ -354,8 +354,10 @@ blockchainTests.resets('Exchange transactions', env => {
[
ExchangeFunctionName.FillOrderNoThrow,
ExchangeFunctionName.BatchFillOrdersNoThrow,
ExchangeFunctionName.MarketBuyOrders,
ExchangeFunctionName.MarketSellOrders,
ExchangeFunctionName.MarketBuyOrdersNoThrow,
ExchangeFunctionName.MarketSellOrdersNoThrow,
ExchangeFunctionName.MarketBuyOrdersFillOrKill,
ExchangeFunctionName.MarketSellOrdersFillOrKill,
].indexOf(fnName) === -1
) {
it(`${fnName} should revert and rethrow error if the underlying function reverts`, async () => {

View File

@@ -20,7 +20,12 @@ export const constants = {
ExchangeFunctionName.BatchFillOrKillOrders,
ExchangeFunctionName.BatchFillOrdersNoThrow,
],
MARKET_FILL_FN_NAMES: [ExchangeFunctionName.MarketBuyOrders, ExchangeFunctionName.MarketSellOrders],
MARKET_FILL_FN_NAMES: [
ExchangeFunctionName.MarketBuyOrdersFillOrKill,
ExchangeFunctionName.MarketSellOrdersFillOrKill,
ExchangeFunctionName.MarketBuyOrdersNoThrow,
ExchangeFunctionName.MarketSellOrdersNoThrow,
],
};
export enum ValidatorWalletAction {

View File

@@ -129,12 +129,12 @@ export class ExchangeWrapper {
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
public async marketSellOrdersAsync(
public async marketSellOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._exchange.marketSellOrders.sendTransactionAsync(
const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync(
orders,
opts.takerAssetFillAmount,
orders.map(signedOrder => signedOrder.signature),
@@ -143,12 +143,40 @@ export class ExchangeWrapper {
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
public async marketBuyOrdersAsync(
public async marketBuyOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { makerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._exchange.marketBuyOrders.sendTransactionAsync(
const txHash = await this._exchange.marketBuyOrdersNoThrow.sendTransactionAsync(
orders,
opts.makerAssetFillAmount,
orders.map(signedOrder => signedOrder.signature),
{ from, gas: opts.gas },
);
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
public async marketSellOrdersFillOrKillAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._exchange.marketSellOrdersFillOrKill.sendTransactionAsync(
orders,
opts.takerAssetFillAmount,
orders.map(signedOrder => signedOrder.signature),
{ from, gas: opts.gas },
);
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
public async marketBuyOrdersFillOrKillAsync(
orders: SignedOrder[],
from: string,
opts: { makerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._exchange.marketBuyOrdersFillOrKill.sendTransactionAsync(
orders,
opts.makerAssetFillAmount,
orders.map(signedOrder => signedOrder.signature),

View File

@@ -21,8 +21,10 @@ export enum ExchangeFunctionName {
FillOrKillOrder = 'fillOrKillOrder',
FillOrder = 'fillOrder',
FillOrderNoThrow = 'fillOrderNoThrow',
MarketBuyOrders = 'marketBuyOrders',
MarketSellOrders = 'marketSellOrders',
MarketBuyOrdersNoThrow = 'marketBuyOrdersNoThrow',
MarketSellOrdersNoThrow = 'marketSellOrdersNoThrow',
MarketBuyOrdersFillOrKill = 'marketBuyOrdersFillOrKill',
MarketSellOrdersFillOrKill = 'marketSellOrdersFillOrKill',
MatchOrders = 'matchOrders',
MatchOrdersWithMaximalFill = 'matchOrdersWithMaximalFill',
PreSign = 'preSign',

View File

@@ -191,13 +191,14 @@ blockchainTests.resets('Exchange wrappers', env => {
it('should revert if entire takerAssetFillAmount not filled', async () => {
const signedOrder = await orderFactory.newSignedOrderAsync();
const takerAssetFillAmount = signedOrder.takerAssetAmount.dividedToIntegerBy(2);
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
takerAssetFillAmount,
});
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
const expectedError = new ExchangeRevertErrors.IncompleteFillError(orderHashHex);
const expectedError = new ExchangeRevertErrors.IncompleteFillError(takerAssetFillAmount, orderHashHex);
const tx = exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress);
return expect(tx).to.revertWith(expectedError);
});
@@ -771,19 +772,19 @@ blockchainTests.resets('Exchange wrappers', env => {
});
});
describe('marketSellOrders', () => {
describe('marketSellOrdersNoThrow', () => {
it('should stop when the entire takerAssetFillAmount is filled', async () => {
const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus(
signedOrders[1].takerAssetAmount.div(2),
);
const fillResults = await exchange.marketSellOrders.callAsync(
const fillResults = await exchange.marketSellOrdersNoThrow.callAsync(
signedOrders,
takerAssetFillAmount,
signedOrders.map(signedOrder => signedOrder.signature),
{ from: takerAddress },
);
await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
@@ -852,13 +853,13 @@ blockchainTests.resets('Exchange wrappers', env => {
].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
});
const fillResults = await exchange.marketSellOrders.callAsync(
const fillResults = await exchange.marketSellOrdersNoThrow.callAsync(
signedOrders,
takerAssetFillAmount,
signedOrders.map(signedOrder => signedOrder.signature),
{ from: takerAddress },
);
await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
@@ -926,13 +927,13 @@ blockchainTests.resets('Exchange wrappers', env => {
].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
});
const fillResults = await exchange.marketSellOrders.callAsync(
const fillResults = await exchange.marketSellOrdersNoThrow.callAsync(
signedOrders,
takerAssetFillAmount,
signedOrders.map(signedOrder => signedOrder.signature),
{ from: takerAddress },
);
await exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
takerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
@@ -967,19 +968,19 @@ blockchainTests.resets('Exchange wrappers', env => {
});
});
describe('marketBuyOrders', () => {
describe('marketBuyOrdersNoThrow', () => {
it('should stop when the entire makerAssetFillAmount is filled', async () => {
const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus(
signedOrders[1].makerAssetAmount.div(2),
);
const fillResults = await exchange.marketBuyOrders.callAsync(
const fillResults = await exchange.marketBuyOrdersNoThrow.callAsync(
signedOrders,
makerAssetFillAmount,
signedOrders.map(signedOrder => signedOrder.signature),
{ from: takerAddress },
);
await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
@@ -1048,13 +1049,13 @@ blockchainTests.resets('Exchange wrappers', env => {
].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
});
const fillResults = await exchange.marketBuyOrders.callAsync(
const fillResults = await exchange.marketBuyOrdersNoThrow.callAsync(
signedOrders,
makerAssetFillAmount,
signedOrders.map(signedOrder => signedOrder.signature),
{ from: takerAddress },
);
await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use
@@ -1123,13 +1124,13 @@ blockchainTests.resets('Exchange wrappers', env => {
].plus(signedOrder.makerFee.plus(signedOrder.takerFee));
});
const fillResults = await exchange.marketBuyOrders.callAsync(
const fillResults = await exchange.marketBuyOrdersNoThrow.callAsync(
signedOrders,
makerAssetFillAmount,
signedOrders.map(signedOrder => signedOrder.signature),
{ from: takerAddress },
);
await exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
await exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
makerAssetFillAmount,
// HACK(albrow): We need to hardcode the gas estimate here because
// the Geth gas estimator doesn't work with the way we use

File diff suppressed because it is too large Load Diff