Pop id from assetData before dispatching to AssetProxies
This commit is contained in:
@@ -47,16 +47,7 @@ contract ERC20Proxy is
|
||||
internal
|
||||
{
|
||||
// Decode asset data.
|
||||
(
|
||||
uint8 proxyId,
|
||||
address token
|
||||
) = decodeERC20AssetData(assetData);
|
||||
|
||||
// Data must be intended for this proxy.
|
||||
require(
|
||||
proxyId == PROXY_ID,
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
address token = readAddress(assetData, 0);
|
||||
|
||||
// Transfer tokens.
|
||||
bool success = IERC20Token(token).transferFrom(from, to, amount);
|
||||
@@ -75,30 +66,4 @@ contract ERC20Proxy is
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC20 proxy id.
|
||||
/// @return token ERC20 token address.
|
||||
function decodeERC20AssetData(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token
|
||||
)
|
||||
{
|
||||
// Validate encoded data length
|
||||
uint256 length = assetData.length;
|
||||
require(
|
||||
length == 21,
|
||||
LENGTH_21_REQUIRED
|
||||
);
|
||||
|
||||
// Decode data
|
||||
token = readAddress(assetData, 0);
|
||||
proxyId = uint8(assetData[length - 1]);
|
||||
|
||||
return (proxyId, token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,30 +46,22 @@ contract ERC721Proxy is
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Decode asset data.
|
||||
(
|
||||
uint8 proxyId,
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
|
||||
// Data must be intended for this proxy.
|
||||
require(
|
||||
proxyId == PROXY_ID,
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// There exists only 1 of each token.
|
||||
require(
|
||||
amount == 1,
|
||||
INVALID_AMOUNT
|
||||
);
|
||||
|
||||
// Decode asset data.
|
||||
(
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
// Transfer token. Saves gas by calling safeTransferFrom only
|
||||
// when there is receiverData present. Either succeeds or throws.
|
||||
if(receiverData.length > 0) {
|
||||
if (receiverData.length > 0) {
|
||||
ERC721Token(token).safeTransferFrom(from, to, tokenId, receiverData);
|
||||
} else {
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
@@ -97,29 +89,19 @@ contract ERC721Proxy is
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
// Validate encoded data length
|
||||
uint256 length = assetData.length;
|
||||
require(
|
||||
length >= 53,
|
||||
LENGTH_AT_LEAST_53_REQUIRED
|
||||
);
|
||||
|
||||
// Decode asset data.
|
||||
token = readAddress(assetData, 0);
|
||||
tokenId = readUint256(assetData, 20);
|
||||
if (length > 53) {
|
||||
if (assetData.length > 52) {
|
||||
receiverData = readBytes(assetData, 52);
|
||||
}
|
||||
proxyId = uint8(assetData[length - 1]);
|
||||
|
||||
return (
|
||||
proxyId,
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
|
||||
@@ -27,11 +27,6 @@ contract LibAssetProxyErrors {
|
||||
string constant AUTHORIZED_ADDRESS_MISMATCH = "AUTHORIZED_ADDRESS_MISMATCH"; // Address at index does not match given target address.
|
||||
|
||||
/// AssetProxy errors ///
|
||||
string constant ASSET_PROXY_ID_MISMATCH = "ASSET_PROXY_ID_MISMATCH"; // Proxy id in metadata does not match this proxy id.
|
||||
string constant INVALID_AMOUNT = "INVALID_AMOUNT"; // Transfer amount must equal 1.
|
||||
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
|
||||
|
||||
/// Length validation errors ///
|
||||
string constant LENGTH_21_REQUIRED = "LENGTH_21_REQUIRED"; // Byte array must have a length of 21.
|
||||
string constant LENGTH_AT_LEAST_53_REQUIRED = "LENGTH_AT_LEAST_53_REQUIRED"; // Byte array must have a length of at least 53.
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../../utils/Ownable/Ownable.sol";
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
import "../AssetProxy/interfaces/IAssetProxy.sol";
|
||||
|
||||
contract MixinAssetProxyDispatcher is
|
||||
Ownable,
|
||||
LibBytes,
|
||||
LibExchangeErrors,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
@@ -81,11 +83,13 @@ contract MixinAssetProxyDispatcher is
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param assetProxyId Id of assetProxy to dispach to.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -94,16 +98,8 @@ contract MixinAssetProxyDispatcher is
|
||||
{
|
||||
// Do nothing if no amount should be transferred.
|
||||
if (amount > 0) {
|
||||
|
||||
// Lookup asset proxy
|
||||
uint256 length = assetData.length;
|
||||
require(
|
||||
length > 0,
|
||||
LENGTH_GREATER_THAN_0_REQUIRED
|
||||
);
|
||||
uint8 assetProxyId = uint8(assetData[length - 1]);
|
||||
// Lookup assetProxy
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetData, from, to, amount);
|
||||
}
|
||||
|
||||
@@ -108,9 +108,6 @@ contract MixinExchangeCore is
|
||||
// Compute proportional fill amounts
|
||||
fillResults = calculateFillResults(order, takerAssetFilledAmount);
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, fillResults);
|
||||
|
||||
// Update exchange internal state
|
||||
updateFilledState(
|
||||
order,
|
||||
@@ -119,6 +116,10 @@ contract MixinExchangeCore is
|
||||
orderInfo.orderTakerAssetFilledAmount,
|
||||
fillResults
|
||||
);
|
||||
|
||||
// Settle order
|
||||
settleOrder(order, takerAddress, fillResults);
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
@@ -25,7 +24,6 @@ import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MTransactions.sol";
|
||||
|
||||
contract MixinMatchOrders is
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibExchangeErrors,
|
||||
MExchangeCore,
|
||||
@@ -94,14 +92,6 @@ contract MixinMatchOrders is
|
||||
rightSignature
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
// Update exchange state
|
||||
updateFilledState(
|
||||
leftOrder,
|
||||
@@ -117,6 +107,14 @@ contract MixinMatchOrders is
|
||||
rightOrderInfo.orderTakerAssetFilledAmount,
|
||||
matchedFillResults.right
|
||||
);
|
||||
|
||||
// Settle matched orders. Succeeds or throws.
|
||||
settleMatchedOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
takerAddress,
|
||||
matchedFillResults
|
||||
);
|
||||
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../utils/LibBytes/LibBytes.sol";
|
||||
import "./libs/LibMath.sol";
|
||||
import "./libs/LibFillResults.sol";
|
||||
import "./libs/LibOrder.sol";
|
||||
@@ -28,6 +29,7 @@ import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
|
||||
contract MixinSettlement is
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibExchangeErrors,
|
||||
MMatchOrders,
|
||||
@@ -37,7 +39,7 @@ contract MixinSettlement is
|
||||
// ZRX metadata used for fee transfers.
|
||||
// This will be constant throughout the life of the Exchange contract,
|
||||
// since ZRX will always be transferred via the ERC20 AssetProxy.
|
||||
bytes internal ZRX_PROXY_DATA;
|
||||
bytes internal ZRX_ASSET_DATA;
|
||||
|
||||
/// @dev Gets the ZRX metadata used for fee transfers.
|
||||
function zrxAssetData()
|
||||
@@ -45,7 +47,7 @@ contract MixinSettlement is
|
||||
view
|
||||
returns (bytes memory)
|
||||
{
|
||||
return ZRX_PROXY_DATA;
|
||||
return ZRX_ASSET_DATA;
|
||||
}
|
||||
|
||||
/// TODO: _zrxAssetData should be a constant in production.
|
||||
@@ -54,7 +56,7 @@ contract MixinSettlement is
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
{
|
||||
ZRX_PROXY_DATA = _zrxAssetData;
|
||||
ZRX_ASSET_DATA = _zrxAssetData;
|
||||
}
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
@@ -68,26 +70,34 @@ contract MixinSettlement is
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 makerAssetProxyId = uint8(popByte(order.makerAssetData));
|
||||
uint8 takerAssetProxyId = uint8(popByte(order.takerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
uint8 zrxProxyId = uint8(popByte(zrxAssetData));
|
||||
dispatchTransferFrom(
|
||||
order.makerAssetData,
|
||||
makerAssetProxyId,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
fillResults.makerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
order.takerAssetData,
|
||||
takerAssetProxyId,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
fillResults.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.takerFeePaid
|
||||
@@ -107,21 +117,28 @@ contract MixinSettlement is
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 leftMakerAssetProxyId = uint8(popByte(leftOrder.makerAssetData));
|
||||
uint8 rightMakerAssetProxyId = uint8(popByte(rightOrder.makerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
uint8 zrxProxyId = uint8(popByte(zrxAssetData));
|
||||
// Order makers and taker
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftMakerAssetProxyId,
|
||||
leftOrder.makerAddress,
|
||||
rightOrder.makerAddress,
|
||||
matchedFillResults.right.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
rightOrder.makerAssetData,
|
||||
rightMakerAssetProxyId,
|
||||
rightOrder.makerAddress,
|
||||
leftOrder.makerAddress,
|
||||
matchedFillResults.left.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
leftOrder.makerAssetData,
|
||||
leftMakerAssetProxyId,
|
||||
leftOrder.makerAddress,
|
||||
takerAddress,
|
||||
matchedFillResults.leftMakerAssetSpreadAmount
|
||||
@@ -129,13 +146,15 @@ contract MixinSettlement is
|
||||
|
||||
// Maker fees
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
leftOrder.makerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
rightOrder.makerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.makerFeePaid
|
||||
@@ -144,7 +163,8 @@ contract MixinSettlement is
|
||||
// Taker fees
|
||||
if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
safeAdd(
|
||||
@@ -154,13 +174,15 @@ contract MixinSettlement is
|
||||
);
|
||||
} else {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.takerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
zrxProxyId,
|
||||
takerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
|
||||
@@ -335,12 +335,13 @@ contract MixinWrapperFunctions is
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being sold by taker must be the same for each order
|
||||
// TODO: optimize by only using takerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
// We assume that asset being sold by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the takerAssetData from the first order onto all later orders.
|
||||
// We cannot reference the same takerAssetData byte array because the array is modified when a trade is settled.
|
||||
uint256 next = i + 1;
|
||||
if (next != orders.length) {
|
||||
deepCopyBytes(orders[next].takerAssetData, orders[i].takerAssetData);
|
||||
}
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
@@ -379,12 +380,13 @@ contract MixinWrapperFunctions is
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being sold by taker must be the same for each order
|
||||
// TODO: optimize by only using takerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].takerAssetData, orders[0].takerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
// We assume that asset being sold by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the takerAssetData from the first order onto all later orders.
|
||||
// We cannot reference the same takerAssetData byte array because the array is modified when a trade is settled.
|
||||
uint256 next = i + 1;
|
||||
if (next != orders.length) {
|
||||
deepCopyBytes(orders[next].takerAssetData, orders[i].takerAssetData);
|
||||
}
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
@@ -422,12 +424,13 @@ contract MixinWrapperFunctions is
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being bought by taker must be the same for each order
|
||||
// TODO: optimize by only using makerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
// We assume that asset being bought by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
|
||||
// We cannot reference the same makerAssetData byte array because the array is modified when a trade is settled.
|
||||
uint256 next = i + 1;
|
||||
if (next != orders.length) {
|
||||
deepCopyBytes(orders[next].makerAssetData, orders[i].makerAssetData);
|
||||
}
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
@@ -474,12 +477,13 @@ contract MixinWrapperFunctions is
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
|
||||
// Token being bought by taker must be the same for each order
|
||||
// TODO: optimize by only using makerAssetData for first order.
|
||||
require(
|
||||
areBytesEqual(orders[i].makerAssetData, orders[0].makerAssetData),
|
||||
ASSET_DATA_MISMATCH
|
||||
);
|
||||
// We assume that asset being bought by taker is the same for each order.
|
||||
// Rather than passing this in as calldata, we copy the makerAssetData from the first order onto all later orders.
|
||||
// We cannot reference the same makerAssetData byte array because the array is modified when a trade is settled.
|
||||
uint256 next = i + 1;
|
||||
if (next != orders.length) {
|
||||
deepCopyBytes(orders[next].makerAssetData, orders[i].makerAssetData);
|
||||
}
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
|
||||
@@ -25,7 +25,6 @@ contract LibExchangeErrors {
|
||||
string constant INVALID_TAKER = "INVALID_TAKER"; // Invalid takerAddress.
|
||||
string constant INVALID_SENDER = "INVALID_SENDER"; // Invalid `msg.sender`.
|
||||
string constant INVALID_ORDER_SIGNATURE = "INVALID_ORDER_SIGNATURE"; // Signature validation failed.
|
||||
string constant ASSET_DATA_MISMATCH = "ASSET_DATA_MISMATCH"; // Asset data must be the same for each order.
|
||||
|
||||
/// fillOrder validation errors ///
|
||||
string constant INVALID_TAKER_AMOUNT = "INVALID_TAKER_AMOUNT"; // takerAssetFillAmount cannot equal 0.
|
||||
|
||||
@@ -34,11 +34,13 @@ contract MAssetProxyDispatcher is
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param assetProxyId Id of assetProxy to dispach to.
|
||||
/// @param from Address to transfer token from.
|
||||
/// @param to Address to transfer token to.
|
||||
/// @param amount Amount of token to transfer.
|
||||
function dispatchTransferFrom(
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
|
||||
@@ -23,26 +23,8 @@ import "../../protocol/AssetProxy/ERC20Proxy.sol";
|
||||
import "../../protocol/AssetProxy/ERC721Proxy.sol";
|
||||
|
||||
contract TestAssetDataDecoders is
|
||||
ERC20Proxy,
|
||||
ERC721Proxy
|
||||
{
|
||||
|
||||
/// @dev Decodes ERC20 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC20 proxy id.
|
||||
/// @return token ERC20 token address.
|
||||
function publicDecodeERC20Data(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token
|
||||
)
|
||||
{
|
||||
(proxyId, token) = decodeERC20AssetData(assetData);
|
||||
return (proxyId, token);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
@@ -54,21 +36,18 @@ contract TestAssetDataDecoders is
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
uint8 proxyId,
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
(
|
||||
proxyId,
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
return (
|
||||
proxyId,
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
|
||||
@@ -24,11 +24,12 @@ import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
|
||||
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
|
||||
function publicDispatchTransferFrom(
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
{
|
||||
dispatchTransferFrom(assetData, from, to, amount);
|
||||
dispatchTransferFrom(assetData, assetProxyId, from, to, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ contract LibBytes is
|
||||
string constant GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED";
|
||||
|
||||
/// @dev Pops the last byte off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
@@ -114,6 +115,29 @@ contract LibBytes is
|
||||
return equal;
|
||||
}
|
||||
|
||||
/// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length.
|
||||
/// @param dest Byte array that will be overwritten with source bytes.
|
||||
/// @param source Byte array to copy onto dest bytes.
|
||||
function deepCopyBytes(
|
||||
bytes memory dest,
|
||||
bytes memory source
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
uint256 sourceLen = source.length;
|
||||
// Dest length must be >= source length, or some bytes would not be copied.
|
||||
require(
|
||||
dest.length >= sourceLen,
|
||||
GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED
|
||||
);
|
||||
memCopy(
|
||||
getMemAddress(dest) + 32, // +32 to skip length of <dest>
|
||||
getMemAddress(source) + 32, // +32 to skip length of <source>
|
||||
sourceLen
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Reads an address from a position in a byte array.
|
||||
/// @param b Byte array containing an address.
|
||||
/// @param index Index in byte array of address.
|
||||
|
||||
@@ -165,7 +165,7 @@ export class ExchangeWrapper {
|
||||
public async marketBuyOrdersNoThrowAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { makerAssetFillAmount: BigNumber },
|
||||
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
|
||||
const txHash = await this._exchange.marketBuyOrdersNoThrow.sendTransactionAsync(
|
||||
|
||||
@@ -28,8 +28,14 @@ export const formatters = {
|
||||
signatures: [],
|
||||
takerAssetFillAmount,
|
||||
};
|
||||
_.forEach(signedOrders, signedOrder => {
|
||||
_.forEach(signedOrders, (signedOrder, i) => {
|
||||
const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
if (i !== 0) {
|
||||
orderWithoutExchangeAddress.takerAssetData = `0x${_.repeat(
|
||||
'0',
|
||||
signedOrders[0].takerAssetData.length - 2,
|
||||
)}`;
|
||||
}
|
||||
marketSellOrders.orders.push(orderWithoutExchangeAddress);
|
||||
marketSellOrders.signatures.push(signedOrder.signature);
|
||||
});
|
||||
@@ -41,8 +47,14 @@ export const formatters = {
|
||||
signatures: [],
|
||||
makerAssetFillAmount,
|
||||
};
|
||||
_.forEach(signedOrders, signedOrder => {
|
||||
_.forEach(signedOrders, (signedOrder, i) => {
|
||||
const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
if (i !== 0) {
|
||||
orderWithoutExchangeAddress.makerAssetData = `0x${_.repeat(
|
||||
'0',
|
||||
signedOrders[0].makerAssetData.length - 2,
|
||||
)}`;
|
||||
}
|
||||
marketBuyOrders.orders.push(orderWithoutExchangeAddress);
|
||||
marketBuyOrders.signatures.push(signedOrder.signature);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { CancelOrder, MatchOrder } from './types';
|
||||
|
||||
export const orderUtils = {
|
||||
@@ -43,6 +44,8 @@ export const orderUtils = {
|
||||
leftSignature: signedOrderLeft.signature,
|
||||
rightSignature: signedOrderRight.signature,
|
||||
};
|
||||
fill.right.makerAssetData = constants.NULL_BYTES;
|
||||
fill.right.takerAssetData = constants.NULL_BYTES;
|
||||
return fill;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -42,33 +42,19 @@ describe('TestAssetDataDecoders', () => {
|
||||
});
|
||||
|
||||
describe('Asset Data Decoders', () => {
|
||||
it('should correctly decode ERC20 asset data)', async () => {
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(testAddress);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC20AssetData(encodedAssetData);
|
||||
let decodedAssetProxyId: number;
|
||||
let decodedTokenAddress: string;
|
||||
[decodedAssetProxyId, decodedTokenAddress] = await testAssetProxyDecoder.publicDecodeERC20Data.callAsync(
|
||||
encodedAssetData,
|
||||
);
|
||||
expect(decodedAssetProxyId).to.be.equal(expectedDecodedAssetData.assetProxyId);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
});
|
||||
|
||||
it('should correctly decode ERC721 asset data', async () => {
|
||||
const tokenId = generatePseudoRandomSalt();
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
|
||||
let decodedAssetProxyId: number;
|
||||
let decodedTokenAddress: string;
|
||||
let decodedTokenId: BigNumber;
|
||||
let decodedData: string;
|
||||
[
|
||||
decodedAssetProxyId,
|
||||
decodedTokenAddress,
|
||||
decodedTokenId,
|
||||
decodedData,
|
||||
] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
|
||||
expect(decodedAssetProxyId).to.be.equal(expectedDecodedAssetData.assetProxyId);
|
||||
] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetDataWithoutProxyId);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
|
||||
expect(decodedData).to.be.equal(expectedDecodedAssetData.receiverData);
|
||||
@@ -84,17 +70,14 @@ describe('TestAssetDataDecoders', () => {
|
||||
const receiverData = receiverDataFirst32Bytes + receiverDataExtraBytes;
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId, receiverData);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
|
||||
let decodedAssetProxyId: number;
|
||||
let decodedTokenAddress: string;
|
||||
let decodedTokenId: BigNumber;
|
||||
let decodedReceiverData: string;
|
||||
[
|
||||
decodedAssetProxyId,
|
||||
decodedTokenAddress,
|
||||
decodedTokenId,
|
||||
decodedReceiverData,
|
||||
] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
|
||||
expect(decodedAssetProxyId).to.be.equal(expectedDecodedAssetData.assetProxyId);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
|
||||
expect(decodedReceiverData).to.be.equal(expectedDecodedAssetData.receiverData);
|
||||
|
||||
@@ -96,12 +96,13 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(10);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -122,12 +123,13 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should do nothing if transferring 0 amount of a token', async () => {
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(0);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -172,12 +174,19 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should throw if requesting address is not authorized', async () => {
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(10);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(encodedAssetData, makerAddress, takerAddress, amount, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{
|
||||
from: notAuthorized,
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -187,9 +196,10 @@ describe('Asset Transfer Proxies', () => {
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
const amount = new BigNumber(10);
|
||||
const numTransfers = 2;
|
||||
const assetData = _.times(numTransfers, () => encodedAssetData);
|
||||
const assetData = _.times(numTransfers, () => encodedAssetDataWithoutProxyId);
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => amount);
|
||||
@@ -218,9 +228,10 @@ describe('Asset Transfer Proxies', () => {
|
||||
|
||||
it('should throw if not called by an authorized address', async () => {
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
const amount = new BigNumber(10);
|
||||
const numTransfers = 2;
|
||||
const assetData = _.times(numTransfers, () => encodedAssetData);
|
||||
const assetData = _.times(numTransfers, () => encodedAssetDataWithoutProxyId);
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => amount);
|
||||
@@ -244,6 +255,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
@@ -251,7 +263,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
const amount = new BigNumber(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -267,13 +279,14 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should not call onERC721Received when transferring to a smart contract without receiver data', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
const txHash = await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
erc721Receiver.address,
|
||||
amount,
|
||||
@@ -298,13 +311,14 @@ describe('Asset Transfer Proxies', () => {
|
||||
erc721MakerTokenId,
|
||||
receiverData,
|
||||
);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
const txHash = await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
erc721Receiver.address,
|
||||
amount,
|
||||
@@ -333,6 +347,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
erc721MakerTokenId,
|
||||
receiverData,
|
||||
);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
@@ -340,7 +355,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
const amount = new BigNumber(1);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
erc20Proxy.address, // the ERC20 proxy does not have an ERC721 receiver
|
||||
amount,
|
||||
@@ -352,6 +367,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should throw if transferring 0 amount of a token', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
@@ -359,7 +375,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
const amount = new BigNumber(0);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -371,6 +387,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should throw if transferring > 1 amount of a token', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Verify pre-condition
|
||||
const ownerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(ownerMakerAsset).to.be.bignumber.equal(makerAddress);
|
||||
@@ -378,7 +395,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
const amount = new BigNumber(500);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -390,6 +407,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should throw if allowances are too low', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Remove transfer approval for makerAddress.
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, false, {
|
||||
@@ -400,20 +418,27 @@ describe('Asset Transfer Proxies', () => {
|
||||
// Perform a transfer; expect this to fail.
|
||||
const amount = new BigNumber(1);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(encodedAssetData, makerAddress, takerAddress, amount, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{
|
||||
from: notAuthorized,
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if requesting address is not authorized', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(erc721Token.address, erc721MakerTokenId);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(1);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -430,8 +455,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
|
||||
const numTransfers = 2;
|
||||
const assetData = [
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA).slice(0, -2),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB).slice(0, -2),
|
||||
];
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
@@ -462,8 +487,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
|
||||
const numTransfers = 2;
|
||||
const assetData = [
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdA).slice(0, -2),
|
||||
assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerTokenIdB).slice(0, -2),
|
||||
];
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
@@ -484,3 +509,4 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
// tslint:disable:max-file-line-count
|
||||
|
||||
@@ -276,12 +276,14 @@ describe('AssetProxyDispatcher', () => {
|
||||
);
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(10);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
AssetProxyId.ERC20,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -302,11 +304,13 @@ describe('AssetProxyDispatcher', () => {
|
||||
it('should throw if dispatching to unregistered proxy', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(10);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
|
||||
encodedAssetData,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
AssetProxyId.ERC20,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
|
||||
@@ -781,20 +781,49 @@ describe('Exchange wrappers', () => {
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should throw when a signedOrder does not use the same takerAssetAddress', async () => {
|
||||
it('should not fill a signedOrder that does not use the same takerAssetAddress', async () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
|
||||
const filledSignedOrders = signedOrders.slice(0, -1);
|
||||
_.forEach(filledSignedOrders, signedOrder => {
|
||||
erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
|
||||
defaultMakerAssetAddress
|
||||
].minus(signedOrder.makerAssetAmount);
|
||||
erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
|
||||
defaultTakerAssetAddress
|
||||
].add(signedOrder.takerAssetAmount);
|
||||
erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
|
||||
signedOrder.makerFee,
|
||||
);
|
||||
erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
|
||||
defaultMakerAssetAddress
|
||||
].add(signedOrder.makerAssetAmount);
|
||||
erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
|
||||
defaultTakerAssetAddress
|
||||
].minus(signedOrder.takerAssetAmount);
|
||||
erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
|
||||
signedOrder.takerFee,
|
||||
);
|
||||
erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
|
||||
zrxToken.address
|
||||
].add(signedOrder.makerFee.add(signedOrder.takerFee));
|
||||
});
|
||||
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
|
||||
// delegatecall and swallow errors.
|
||||
gas: 600000,
|
||||
});
|
||||
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
|
||||
}),
|
||||
);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -894,6 +923,10 @@ describe('Exchange wrappers', () => {
|
||||
);
|
||||
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
|
||||
// delegatecall and swallow errors.
|
||||
gas: 600000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -926,8 +959,8 @@ describe('Exchange wrappers', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should fill all signedOrders if cannot fill entire takerAssetFillAmount', async () => {
|
||||
const takerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
|
||||
it('should fill all signedOrders if cannot fill entire makerAssetFillAmount', async () => {
|
||||
const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
|
||||
_.forEach(signedOrders, signedOrder => {
|
||||
erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
|
||||
defaultMakerAssetAddress
|
||||
@@ -951,8 +984,8 @@ describe('Exchange wrappers', () => {
|
||||
zrxToken.address
|
||||
].add(signedOrder.makerFee.add(signedOrder.takerFee));
|
||||
});
|
||||
await exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmount,
|
||||
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
|
||||
// delegatecall and swallow errors.
|
||||
@@ -963,20 +996,50 @@ describe('Exchange wrappers', () => {
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
|
||||
it('should throw when a signedOrder does not use the same makerAssetAddress', async () => {
|
||||
it('should not fill a signedOrder that does not use the same makerAssetAddress', async () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
|
||||
}),
|
||||
);
|
||||
const makerAssetFillAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18);
|
||||
const filledSignedOrders = signedOrders.slice(0, -1);
|
||||
_.forEach(filledSignedOrders, signedOrder => {
|
||||
erc20Balances[makerAddress][defaultMakerAssetAddress] = erc20Balances[makerAddress][
|
||||
defaultMakerAssetAddress
|
||||
].minus(signedOrder.makerAssetAmount);
|
||||
erc20Balances[makerAddress][defaultTakerAssetAddress] = erc20Balances[makerAddress][
|
||||
defaultTakerAssetAddress
|
||||
].add(signedOrder.takerAssetAmount);
|
||||
erc20Balances[makerAddress][zrxToken.address] = erc20Balances[makerAddress][zrxToken.address].minus(
|
||||
signedOrder.makerFee,
|
||||
);
|
||||
erc20Balances[takerAddress][defaultMakerAssetAddress] = erc20Balances[takerAddress][
|
||||
defaultMakerAssetAddress
|
||||
].add(signedOrder.makerAssetAmount);
|
||||
erc20Balances[takerAddress][defaultTakerAssetAddress] = erc20Balances[takerAddress][
|
||||
defaultTakerAssetAddress
|
||||
].minus(signedOrder.takerAssetAmount);
|
||||
erc20Balances[takerAddress][zrxToken.address] = erc20Balances[takerAddress][zrxToken.address].minus(
|
||||
signedOrder.takerFee,
|
||||
);
|
||||
erc20Balances[feeRecipientAddress][zrxToken.address] = erc20Balances[feeRecipientAddress][
|
||||
zrxToken.address
|
||||
].add(signedOrder.makerFee.add(signedOrder.takerFee));
|
||||
});
|
||||
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
|
||||
// delegatecall and swallow errors.
|
||||
gas: 600000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user