Merge branch 'v2-prototype' into bug/contracts/eip712-191-prefix
This commit is contained in:
@@ -63,3 +63,12 @@ yarn lint
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
### Run Tests Against Geth
|
||||
|
||||
Follow the instructions in the README for the devnet package to start the
|
||||
devnet.
|
||||
|
||||
```bash
|
||||
TEST_PROVIDER=geth yarn test
|
||||
```
|
||||
|
@@ -21,6 +21,7 @@
|
||||
"contracts": [
|
||||
"AssetProxyOwner",
|
||||
"DummyERC20Token",
|
||||
"DummyERC721Receiver",
|
||||
"DummyERC721Token",
|
||||
"ERC20Proxy",
|
||||
"ERC721Proxy",
|
||||
@@ -28,8 +29,10 @@
|
||||
"MixinAuthorizable",
|
||||
"MultiSigWallet",
|
||||
"MultiSigWalletWithTimeLock",
|
||||
"TestAssetDataDecoders",
|
||||
"TestAssetProxyDispatcher",
|
||||
"TestLibBytes",
|
||||
"TestLibMem",
|
||||
"TestLibs",
|
||||
"TestSignatureValidator",
|
||||
"TokenRegistry",
|
||||
|
@@ -11,25 +11,29 @@
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"prebuild": "run-s clean compile copy_artifacts generate_contract_wrappers",
|
||||
"watch_without_deps": "yarn pre_build && tsc -w",
|
||||
"build": "yarn pre_build && tsc",
|
||||
"pre_build": "run-s compile copy_artifacts generate_contract_wrappers",
|
||||
"copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/2.0.0/**/*' ./lib/src/artifacts;",
|
||||
"build": "tsc",
|
||||
"test": "run-s build run_mocha",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"clean": "shx rm -rf lib src/contract_wrappers/generated",
|
||||
"clean": "shx rm -rf lib src/generated_contract_wrappers",
|
||||
"generate_contract_wrappers":
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
|
||||
"lint": "tslint --project .",
|
||||
"abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/generated_contract_wrappers --backend ethers",
|
||||
"lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/*",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetProxyDispatcher|TestLibBytes|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
"abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|TestAssetDataDecoders|TestAssetProxyDispatcher|TestLibBytes|TestLibMem|TestLibs|TestSignatureValidator|TokenRegistry|Whitelist|WETH9|ZRXToken).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -60,7 +64,6 @@
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^4.0.1",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.11.1",
|
||||
"shx": "^0.2.2",
|
||||
"solc": "^0.4.24",
|
||||
"tslint": "5.8.0",
|
||||
|
@@ -34,36 +34,51 @@ contract ERC20Proxy is
|
||||
uint8 constant PROXY_ID = 1;
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
uint256 length = assetMetadata.length;
|
||||
|
||||
require(
|
||||
length == 21,
|
||||
LENGTH_21_REQUIRED
|
||||
);
|
||||
// TODO: Is this too inflexible in the future?
|
||||
require(
|
||||
uint8(assetMetadata[length - 1]) == PROXY_ID,
|
||||
ASSET_PROXY_ID_MISMATCH
|
||||
);
|
||||
|
||||
// Decode metadata.
|
||||
address token = readAddress(assetMetadata, 0);
|
||||
// Decode asset data.
|
||||
address token = readAddress(assetData, 0);
|
||||
|
||||
// Transfer tokens.
|
||||
bool success = IERC20Token(token).transferFrom(from, to, amount);
|
||||
// We do a raw call so we can check the success separate
|
||||
// from the return data.
|
||||
bool success = token.call(abi.encodeWithSelector(
|
||||
IERC20Token(token).transferFrom.selector,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
));
|
||||
require(
|
||||
success,
|
||||
TRANSFER_FAILED
|
||||
);
|
||||
|
||||
// Check return data.
|
||||
// If there is no return data, we assume the token incorrectly
|
||||
// does not return a bool. In this case we expect it to revert
|
||||
// on failure, which was handled above.
|
||||
// If the token does return data, we require that it is a single
|
||||
// value that evaluates to true.
|
||||
assembly {
|
||||
if returndatasize {
|
||||
success := 0
|
||||
if eq(returndatasize, 32) {
|
||||
// First 64 bytes of memory are reserved scratch space
|
||||
returndatacopy(0, 0, 32)
|
||||
success := mload(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
require(
|
||||
success,
|
||||
TRANSFER_FAILED
|
||||
|
@@ -34,47 +34,38 @@ contract ERC721Proxy is
|
||||
uint8 constant PROXY_ID = 2;
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Data must be intended for this proxy.
|
||||
uint256 length = assetMetadata.length;
|
||||
|
||||
require(
|
||||
length == 53,
|
||||
LENGTH_53_REQUIRED
|
||||
);
|
||||
|
||||
// TODO: Is this too inflexible in the future?
|
||||
require(
|
||||
uint8(assetMetadata[length - 1]) == 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);
|
||||
|
||||
// Decode metadata
|
||||
address token = readAddress(assetMetadata, 0);
|
||||
uint256 tokenId = readUint256(assetMetadata, 20);
|
||||
|
||||
// Transfer token.
|
||||
// Either succeeds or throws.
|
||||
// @TODO: Call safeTransferFrom if there is additional
|
||||
// data stored in `assetMetadata`.
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
// Transfer token. Saves gas by calling safeTransferFrom only
|
||||
// when there is receiverData present. Either succeeds or throws.
|
||||
if (receiverData.length > 0) {
|
||||
ERC721Token(token).safeTransferFrom(from, to, tokenId, receiverData);
|
||||
} else {
|
||||
ERC721Token(token).transferFrom(from, to, tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Gets the proxy id associated with the proxy address.
|
||||
@@ -86,4 +77,34 @@ contract ERC721Proxy is
|
||||
{
|
||||
return PROXY_ID;
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function decodeERC721AssetData(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
// Decode asset data.
|
||||
token = readAddress(assetData, 0);
|
||||
tokenId = readUint256(assetData, 20);
|
||||
if (assetData.length > 52) {
|
||||
receiverData = readBytes(assetData, 52);
|
||||
}
|
||||
|
||||
return (
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -28,12 +28,12 @@ contract MixinAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -42,7 +42,7 @@ contract MixinAssetProxy is
|
||||
onlyAuthorized
|
||||
{
|
||||
transferFromInternal(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
@@ -50,12 +50,12 @@ contract MixinAssetProxy is
|
||||
}
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param assetData Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetMetadata,
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
@@ -63,9 +63,9 @@ contract MixinAssetProxy is
|
||||
public
|
||||
onlyAuthorized
|
||||
{
|
||||
for (uint256 i = 0; i < assetMetadata.length; i++) {
|
||||
for (uint256 i = 0; i < assetData.length; i++) {
|
||||
transferFromInternal(
|
||||
assetMetadata[i],
|
||||
assetData[i],
|
||||
from[i],
|
||||
to[i],
|
||||
amounts[i]
|
||||
|
@@ -26,12 +26,12 @@ contract IAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Transfers assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFrom(
|
||||
bytes assetMetadata,
|
||||
bytes assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -39,12 +39,12 @@ contract IAssetProxy is
|
||||
external;
|
||||
|
||||
/// @dev Makes multiple transfers of assets. Either succeeds or throws.
|
||||
/// @param assetMetadata Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param assetData Array of byte arrays encoded for the respective asset proxy.
|
||||
/// @param from Array of addresses to transfer assets from.
|
||||
/// @param to Array of addresses to transfer assets to.
|
||||
/// @param amounts Array of amounts of assets to transfer.
|
||||
function batchTransferFrom(
|
||||
bytes[] memory assetMetadata,
|
||||
bytes[] memory assetData,
|
||||
address[] memory from,
|
||||
address[] memory to,
|
||||
uint256[] memory amounts
|
||||
|
@@ -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_53_REQUIRED = "LENGTH_53_REQUIRED"; // Byte array must have a length of 53.
|
||||
string constant TRANSFER_FAILED = "TRANSFER_FAILED"; // Transfer failed.
|
||||
}
|
||||
|
@@ -26,12 +26,12 @@ contract MAssetProxy is
|
||||
{
|
||||
|
||||
/// @dev Internal version of `transferFrom`.
|
||||
/// @param assetMetadata Encoded byte array.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
function transferFromInternal(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
|
@@ -40,11 +40,11 @@ contract Exchange is
|
||||
string constant public VERSION = "2.0.1-alpha";
|
||||
|
||||
// Mixins are instantiated in the order they are inherited
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
MixinExchangeCore()
|
||||
MixinMatchOrders()
|
||||
MixinSettlement(_zrxProxyData)
|
||||
MixinSettlement(_zrxAssetData)
|
||||
MixinSignatureValidator()
|
||||
MixinTransactions()
|
||||
MixinAssetProxyDispatcher()
|
||||
|
@@ -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
|
||||
{
|
||||
@@ -80,12 +82,14 @@ contract MixinAssetProxyDispatcher is
|
||||
}
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @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 assetMetadata,
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
@@ -94,18 +98,10 @@ contract MixinAssetProxyDispatcher is
|
||||
{
|
||||
// Do nothing if no amount should be transferred.
|
||||
if (amount > 0) {
|
||||
|
||||
// Lookup asset proxy
|
||||
uint256 length = assetMetadata.length;
|
||||
require(
|
||||
length > 0,
|
||||
LENGTH_GREATER_THAN_0_REQUIRED
|
||||
);
|
||||
uint8 assetProxyId = uint8(assetMetadata[length - 1]);
|
||||
// Lookup assetProxy
|
||||
IAssetProxy assetProxy = assetProxies[assetProxyId];
|
||||
|
||||
// transferFrom will either succeed or throw.
|
||||
assetProxy.transferFrom(assetMetadata, from, to, amount);
|
||||
assetProxy.transferFrom(assetData, from, to, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ contract MixinExchangeCore is
|
||||
|
||||
////// Core exchange functions //////
|
||||
|
||||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value.
|
||||
/// @dev Cancels all orders created by sender with a salt less than or equal to the specified salt value.
|
||||
/// @param salt Orders created with a salt less or equal to this value will be cancelled.
|
||||
function cancelOrdersUpTo(uint256 salt)
|
||||
external
|
||||
@@ -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,33 +29,26 @@ import "./mixins/MSettlement.sol";
|
||||
import "./mixins/MAssetProxyDispatcher.sol";
|
||||
|
||||
contract MixinSettlement is
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibExchangeErrors,
|
||||
MMatchOrders,
|
||||
MSettlement,
|
||||
MAssetProxyDispatcher
|
||||
{
|
||||
// ZRX metadata used for fee transfers.
|
||||
// ZRX address encoded as a byte array.
|
||||
// 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;
|
||||
uint8 constant ZRX_PROXY_ID = 1;
|
||||
|
||||
/// @dev Gets the ZRX metadata used for fee transfers.
|
||||
function zrxProxyData()
|
||||
external
|
||||
view
|
||||
returns (bytes memory)
|
||||
{
|
||||
return ZRX_PROXY_DATA;
|
||||
}
|
||||
|
||||
/// TODO: _zrxProxyData should be a constant in production.
|
||||
/// TODO: _zrxAssetData should be a constant in production.
|
||||
/// @dev Constructor sets the metadata that will be used for paying ZRX fees.
|
||||
/// @param _zrxProxyData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxProxyData)
|
||||
/// @param _zrxAssetData Byte array containing ERC20 proxy id concatenated with address of ZRX.
|
||||
constructor (bytes memory _zrxAssetData)
|
||||
public
|
||||
{
|
||||
ZRX_PROXY_DATA = _zrxProxyData;
|
||||
ZRX_ASSET_DATA = _zrxAssetData;
|
||||
}
|
||||
|
||||
/// @dev Settles an order by transferring assets between counterparties.
|
||||
@@ -68,26 +62,33 @@ contract MixinSettlement is
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 makerAssetProxyId = uint8(popLastByte(order.makerAssetData));
|
||||
uint8 takerAssetProxyId = uint8(popLastByte(order.takerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
dispatchTransferFrom(
|
||||
order.makerAssetData,
|
||||
makerAssetProxyId,
|
||||
order.makerAddress,
|
||||
takerAddress,
|
||||
fillResults.makerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
order.takerAssetData,
|
||||
takerAssetProxyId,
|
||||
takerAddress,
|
||||
order.makerAddress,
|
||||
fillResults.takerAssetFilledAmount
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
order.feeRecipientAddress,
|
||||
fillResults.takerFeePaid
|
||||
@@ -107,21 +108,27 @@ contract MixinSettlement is
|
||||
)
|
||||
internal
|
||||
{
|
||||
uint8 leftMakerAssetProxyId = uint8(popLastByte(leftOrder.makerAssetData));
|
||||
uint8 rightMakerAssetProxyId = uint8(popLastByte(rightOrder.makerAssetData));
|
||||
bytes memory zrxAssetData = ZRX_ASSET_DATA;
|
||||
// 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 +136,15 @@ contract MixinSettlement is
|
||||
|
||||
// Maker fees
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
leftOrder.makerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.makerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
rightOrder.makerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.makerFeePaid
|
||||
@@ -144,7 +153,8 @@ contract MixinSettlement is
|
||||
// Taker fees
|
||||
if (leftOrder.feeRecipientAddress == rightOrder.feeRecipientAddress) {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
safeAdd(
|
||||
@@ -154,13 +164,15 @@ contract MixinSettlement is
|
||||
);
|
||||
} else {
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
leftOrder.feeRecipientAddress,
|
||||
matchedFillResults.left.takerFeePaid
|
||||
);
|
||||
dispatchTransferFrom(
|
||||
ZRX_PROXY_DATA,
|
||||
zrxAssetData,
|
||||
ZRX_PROXY_ID,
|
||||
takerAddress,
|
||||
rightOrder.feeRecipientAddress,
|
||||
matchedFillResults.right.takerFeePaid
|
||||
|
@@ -93,7 +93,7 @@ contract MixinSignatureValidator is
|
||||
);
|
||||
|
||||
// Pop last byte off of signature byte array.
|
||||
SignatureType signatureType = SignatureType(uint8(popByte(signature)));
|
||||
SignatureType signatureType = SignatureType(uint8(popLastByte(signature)));
|
||||
|
||||
// Variables are not scoped in Solidity.
|
||||
uint8 v;
|
||||
@@ -183,7 +183,7 @@ contract MixinSignatureValidator is
|
||||
// | 0x14 + x | 1 | Signature type is always "\x06" |
|
||||
} else if (signatureType == SignatureType.Validator) {
|
||||
// Pop last 20 bytes off of signature byte array.
|
||||
address validator = popAddress(signature);
|
||||
address validator = popLast20Bytes(signature);
|
||||
// Ensure signer has approved validator.
|
||||
if (!allowedValidators[signer][validator]) {
|
||||
return false;
|
||||
|
@@ -19,7 +19,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";
|
||||
@@ -27,7 +26,6 @@ import "./libs/LibExchangeErrors.sol";
|
||||
import "./mixins/MExchangeCore.sol";
|
||||
|
||||
contract MixinWrapperFunctions is
|
||||
LibBytes,
|
||||
LibMath,
|
||||
LibFillResults,
|
||||
LibExchangeErrors,
|
||||
@@ -40,7 +38,8 @@ contract MixinWrapperFunctions is
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
@@ -65,7 +64,8 @@ contract MixinWrapperFunctions is
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults)
|
||||
{
|
||||
@@ -91,12 +91,12 @@ contract MixinWrapperFunctions is
|
||||
// | | 0x0E0 | | 8. takerFeeAmount |
|
||||
// | | 0x100 | | 9. expirationTimeSeconds |
|
||||
// | | 0x120 | | 10. salt |
|
||||
// | | 0x140 | | 11. Offset to makerAssetProxyMetadata (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetProxyMetadata (*) |
|
||||
// | | 0x180 | 32 | makerAssetProxyMetadata Length |
|
||||
// | | 0x1A0 | ** | makerAssetProxyMetadata Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetProxyMetadata Length |
|
||||
// | | 0x1E0 | ** | takerAssetProxyMetadata Contents |
|
||||
// | | 0x140 | | 11. Offset to makerAssetData (*) |
|
||||
// | | 0x160 | | 12. Offset to takerAssetData (*) |
|
||||
// | | 0x180 | 32 | makerAssetData Length |
|
||||
// | | 0x1A0 | ** | makerAssetData Contents |
|
||||
// | | 0x1C0 | 32 | takerAssetData Length |
|
||||
// | | 0x1E0 | ** | takerAssetData Contents |
|
||||
// | | 0x200 | 32 | signature Length |
|
||||
// | | 0x220 | ** | signature Contents |
|
||||
|
||||
@@ -163,43 +163,45 @@ contract MixinWrapperFunctions is
|
||||
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
|
||||
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
|
||||
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetProxyMetadata
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetProxyMetadata
|
||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
|
||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
|
||||
dataAreaEnd := add(dataAreaEnd, 0x180)
|
||||
sourceOffset := add(sourceOffset, 0x180)
|
||||
|
||||
// Write offset to <order.makerAssetProxyMetadata>
|
||||
// Write offset to <order.makerAssetData>
|
||||
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.makerAssetProxyMetadata>
|
||||
// Calculate length of <order.makerAssetData>
|
||||
sourceOffset := mload(add(order, 0x140)) // makerAssetData
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.makerAssetProxyMetadata>
|
||||
// Write length of <order.makerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.makerAssetProxyMetadata>
|
||||
// Write contents of <order.makerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
}
|
||||
|
||||
// Write offset to <order.takerAssetProxyMetadata>
|
||||
// Write offset to <order.takerAssetData>
|
||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||
|
||||
// Calculate length of <order.takerAssetProxyMetadata>
|
||||
// Calculate length of <order.takerAssetData>
|
||||
sourceOffset := mload(add(order, 0x160)) // takerAssetData
|
||||
arrayLenBytes := mload(sourceOffset)
|
||||
sourceOffset := add(sourceOffset, 0x20)
|
||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||
|
||||
// Write length of <order.takerAssetProxyMetadata>
|
||||
// Write length of <order.takerAssetData>
|
||||
mstore(dataAreaEnd, arrayLenBytes)
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
|
||||
// Write contents of <order.takerAssetProxyMetadata>
|
||||
// Write contents of <order.takerAssetData>
|
||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||
mstore(dataAreaEnd, mload(sourceOffset))
|
||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||
@@ -264,7 +266,8 @@ contract MixinWrapperFunctions is
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
@@ -283,7 +286,8 @@ contract MixinWrapperFunctions is
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
@@ -303,7 +307,8 @@ contract MixinWrapperFunctions is
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
{
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
@@ -323,18 +328,18 @@ contract MixinWrapperFunctions is
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
|
||||
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 use the takerAssetData from the first order in all later orders.
|
||||
orders[i].takerAssetData = takerAssetData;
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
@@ -346,6 +351,14 @@ contract MixinWrapperFunctions is
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// HACK: the proxyId is "popped" from the byte array before a fill is settled
|
||||
// by subtracting from the length of the array. Since the popped byte is
|
||||
// still in memory, we can "unpop" it by incrementing the length of the byte array.
|
||||
assembly {
|
||||
let len := mload(takerAssetData)
|
||||
mstore(takerAssetData, add(len, 1))
|
||||
}
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
@@ -366,18 +379,18 @@ contract MixinWrapperFunctions is
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory takerAssetData = orders[0].takerAssetData;
|
||||
|
||||
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 use the takerAssetData from the first order in all later orders.
|
||||
orders[i].takerAssetData = takerAssetData;
|
||||
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount);
|
||||
@@ -408,18 +421,18 @@ contract MixinWrapperFunctions is
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
|
||||
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.
|
||||
orders[i].makerAssetData = makerAssetData;
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
@@ -439,6 +452,14 @@ contract MixinWrapperFunctions is
|
||||
signatures[i]
|
||||
);
|
||||
|
||||
// HACK: the proxyId is "popped" from the byte array before a fill is settled
|
||||
// by subtracting from the length of the array. Since the popped byte is
|
||||
// still in memory, we can "unpop" it by incrementing the length of the byte array.
|
||||
assembly {
|
||||
let len := mload(makerAssetData)
|
||||
mstore(makerAssetData, add(len, 1))
|
||||
}
|
||||
|
||||
// Update amounts filled and fees paid by maker and taker
|
||||
addFillResults(totalFillResults, singleFillResults);
|
||||
|
||||
@@ -459,18 +480,18 @@ contract MixinWrapperFunctions is
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (FillResults memory totalFillResults)
|
||||
{
|
||||
bytes memory makerAssetData = orders[0].makerAssetData;
|
||||
|
||||
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.
|
||||
orders[i].makerAssetData = makerAssetData;
|
||||
|
||||
// Calculate the remaining amount of makerAsset to buy
|
||||
uint256 remainingMakerAssetFillAmount = safeSub(makerAssetFillAmount, totalFillResults.makerAssetFilledAmount);
|
||||
|
@@ -28,7 +28,8 @@ contract IAssetProxyDispatcher {
|
||||
function registerAssetProxy(
|
||||
uint8 assetProxyId,
|
||||
address newAssetProxy,
|
||||
address oldAssetProxy)
|
||||
address oldAssetProxy
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Gets an asset proxy.
|
||||
|
@@ -28,6 +28,7 @@ contract ITransactions {
|
||||
uint256 salt,
|
||||
address signer,
|
||||
bytes data,
|
||||
bytes signature)
|
||||
bytes signature
|
||||
)
|
||||
external;
|
||||
}
|
||||
|
@@ -33,7 +33,8 @@ contract IWrapperFunctions is
|
||||
function fillOrKillOrder(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
@@ -46,7 +47,8 @@ contract IWrapperFunctions is
|
||||
function fillOrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature)
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
@@ -57,7 +59,8 @@ contract IWrapperFunctions is
|
||||
function batchFillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrKill.
|
||||
@@ -67,7 +70,8 @@ contract IWrapperFunctions is
|
||||
function batchFillOrKillOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Fills an order with specified parameters and ECDSA signature.
|
||||
@@ -78,7 +82,8 @@ contract IWrapperFunctions is
|
||||
function batchFillOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public;
|
||||
|
||||
/// @dev Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker.
|
||||
@@ -89,7 +94,8 @@ contract IWrapperFunctions is
|
||||
function marketSellOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -102,7 +108,8 @@ contract IWrapperFunctions is
|
||||
function marketSellOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -114,7 +121,8 @@ contract IWrapperFunctions is
|
||||
function marketBuyOrders(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
@@ -127,7 +135,8 @@ contract IWrapperFunctions is
|
||||
function marketBuyOrdersNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetFillAmount,
|
||||
bytes[] memory signatures)
|
||||
bytes[] memory signatures
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.FillResults memory totalFillResults);
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -33,12 +33,14 @@ contract MAssetProxyDispatcher is
|
||||
);
|
||||
|
||||
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
|
||||
/// @param assetMetadata Byte array encoded for the respective asset proxy.
|
||||
/// @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 assetMetadata,
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
|
@@ -31,7 +31,8 @@ contract DummyERC20Token is Mintable, Ownable {
|
||||
string _name,
|
||||
string _symbol,
|
||||
uint256 _decimals,
|
||||
uint256 _totalSupply)
|
||||
uint256 _totalSupply
|
||||
)
|
||||
public
|
||||
{
|
||||
name = _name;
|
||||
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Smart Contract Solutions, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../../tokens/ERC721Token/IERC721Receiver.sol";
|
||||
|
||||
contract DummyERC721Receiver is
|
||||
IERC721Receiver
|
||||
{
|
||||
|
||||
event TokenReceived(
|
||||
address from,
|
||||
uint256 tokenId,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/**
|
||||
* @notice Handle the receipt of an NFT
|
||||
* @dev The ERC721 smart contract calls this function on the recipient
|
||||
* after a `safetransfer`. This function MAY throw to revert and reject the
|
||||
* transfer. This function MUST use 50,000 gas or less. Return of other
|
||||
* than the magic value MUST result in the transaction being reverted.
|
||||
* Note: the contract address is always the message sender.
|
||||
* @param _from The sending address
|
||||
* @param _tokenId The NFT identifier which is being transfered
|
||||
* @param _data Additional data with no specified format
|
||||
* @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
|
||||
*/
|
||||
function onERC721Received(
|
||||
address _from,
|
||||
uint256 _tokenId,
|
||||
bytes _data
|
||||
)
|
||||
public
|
||||
returns (bytes4)
|
||||
{
|
||||
emit TokenReceived(_from, _tokenId, _data);
|
||||
return ERC721_RECEIVED;
|
||||
}
|
||||
}
|
@@ -34,7 +34,8 @@ contract DummyERC721Token is
|
||||
*/
|
||||
constructor (
|
||||
string name,
|
||||
string symbol)
|
||||
string symbol
|
||||
)
|
||||
public
|
||||
ERC721Token(name, symbol)
|
||||
{}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../../protocol/AssetProxy/ERC20Proxy.sol";
|
||||
import "../../protocol/AssetProxy/ERC721Proxy.sol";
|
||||
|
||||
contract TestAssetDataDecoders is
|
||||
ERC721Proxy
|
||||
{
|
||||
/// @dev Decodes ERC721 Asset data.
|
||||
/// @param assetData Encoded byte array.
|
||||
/// @return proxyId Intended ERC721 proxy id.
|
||||
/// @return token ERC721 token address.
|
||||
/// @return tokenId ERC721 token id.
|
||||
/// @return receiverData Additional data with no specific format, which
|
||||
/// is passed to the receiving contract's onERC721Received.
|
||||
function publicDecodeERC721Data(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
address token,
|
||||
uint256 tokenId,
|
||||
bytes memory receiverData
|
||||
)
|
||||
{
|
||||
(
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
) = decodeERC721AssetData(assetData);
|
||||
|
||||
return (
|
||||
token,
|
||||
tokenId,
|
||||
receiverData
|
||||
);
|
||||
}
|
||||
}
|
@@ -23,12 +23,13 @@ import "../../protocol/Exchange/MixinAssetProxyDispatcher.sol";
|
||||
|
||||
contract TestAssetProxyDispatcher is MixinAssetProxyDispatcher {
|
||||
function publicDispatchTransferFrom(
|
||||
bytes memory assetMetadata,
|
||||
bytes memory assetData,
|
||||
uint8 assetProxyId,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount)
|
||||
public
|
||||
{
|
||||
dispatchTransferFrom(assetMetadata, from, to, amount);
|
||||
dispatchTransferFrom(assetData, assetProxyId, from, to, amount);
|
||||
}
|
||||
}
|
||||
|
@@ -28,24 +28,24 @@ contract TestLibBytes is
|
||||
/// @dev Pops the last byte off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
/// @return The byte that was popped off.
|
||||
function publicPopByte(bytes memory b)
|
||||
function publicPopLastByte(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory, bytes1 result)
|
||||
{
|
||||
result = popByte(b);
|
||||
result = popLastByte(b);
|
||||
return (b, result);
|
||||
}
|
||||
|
||||
/// @dev Pops the last 20 bytes off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
/// @return The 20 byte address that was popped off.
|
||||
function publicPopAddress(bytes memory b)
|
||||
function publicPopLast20Bytes(bytes memory b)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory, address result)
|
||||
{
|
||||
result = popAddress(b);
|
||||
result = popLast20Bytes(b);
|
||||
return (b, result);
|
||||
}
|
||||
|
||||
@@ -62,13 +62,29 @@ contract TestLibBytes 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 publicDeepCopyBytes(
|
||||
bytes memory dest,
|
||||
bytes memory source
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
deepCopyBytes(dest, source);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/// @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.
|
||||
/// @return address from byte array.
|
||||
function publicReadAddress(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (address result)
|
||||
@@ -84,7 +100,8 @@ contract TestLibBytes is
|
||||
function publicWriteAddress(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
address input)
|
||||
address input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -99,7 +116,8 @@ contract TestLibBytes is
|
||||
/// @return bytes32 value from byte array.
|
||||
function publicReadBytes32(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes32 result)
|
||||
@@ -115,7 +133,8 @@ contract TestLibBytes is
|
||||
function publicWriteBytes32(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes32 input)
|
||||
bytes32 input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -130,7 +149,8 @@ contract TestLibBytes is
|
||||
/// @return uint256 value from byte array.
|
||||
function publicReadUint256(
|
||||
bytes memory b,
|
||||
uint256 index)
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (uint256 result)
|
||||
@@ -146,7 +166,8 @@ contract TestLibBytes is
|
||||
function publicWriteUint256(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
uint256 input)
|
||||
uint256 input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
@@ -166,4 +187,38 @@ contract TestLibBytes is
|
||||
result = readFirst4(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Reads nested bytes from a specific position.
|
||||
/// @param b Byte array containing nested bytes.
|
||||
/// @param index Index of nested bytes.
|
||||
/// @return result Nested bytes.
|
||||
function publicReadBytes(
|
||||
bytes memory b,
|
||||
uint256 index
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory result)
|
||||
{
|
||||
result = readBytes(b, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Inserts bytes at a specific position in a byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
/// @param input bytes to insert.
|
||||
/// @return b Updated input byte array
|
||||
function publicWriteBytes(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes memory input
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
writeBytes(b, index, input);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
import "../../utils/LibMem/LibMem.sol";
|
||||
|
||||
contract TestLibMem is
|
||||
LibMem
|
||||
{
|
||||
|
||||
/// @dev Copies a block of memory from one location to another.
|
||||
/// @param mem Memory contents we want to apply memCopy to
|
||||
/// @param dest Destination offset into <mem>.
|
||||
/// @param source Source offset into <mem>.
|
||||
/// @param length Length of bytes to copy from <source> to <dest>
|
||||
/// @return mem Memory contents after calling memCopy.
|
||||
function testMemcpy(
|
||||
bytes mem,
|
||||
uint256 dest,
|
||||
uint256 source,
|
||||
uint256 length
|
||||
)
|
||||
public // not external, we need input in memory
|
||||
pure
|
||||
returns (bytes)
|
||||
{
|
||||
// Sanity check. Overflows are not checked.
|
||||
require(source + length <= mem.length);
|
||||
require(dest + length <= mem.length);
|
||||
|
||||
// Get pointer to memory contents
|
||||
uint256 offset = getMemAddress(mem) + 32;
|
||||
|
||||
// Execute memCopy adjusted for memory array location
|
||||
memCopy(offset + dest, offset + source, length);
|
||||
|
||||
// Return modified memory contents
|
||||
return mem;
|
||||
}
|
||||
}
|
@@ -18,31 +18,36 @@
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract LibBytes {
|
||||
import "../LibMem/LibMem.sol";
|
||||
|
||||
contract LibBytes is
|
||||
LibMem
|
||||
{
|
||||
|
||||
// Revert reasons
|
||||
string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
|
||||
string constant GTE_4_LENGTH_REQUIRED = "Length must be greater than or equal to 4.";
|
||||
string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
|
||||
string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
|
||||
string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
|
||||
string constant GREATER_THAN_ZERO_LENGTH_REQUIRED = "GREATER_THAN_ZERO_LENGTH_REQUIRED";
|
||||
string constant GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED = "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED";
|
||||
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.
|
||||
/// @return The byte that was popped off.
|
||||
function popByte(bytes memory b)
|
||||
function popLastByte(bytes memory b)
|
||||
internal
|
||||
pure
|
||||
returns (bytes1 result)
|
||||
{
|
||||
require(
|
||||
b.length > 0,
|
||||
GT_ZERO_LENGTH_REQUIRED
|
||||
GREATER_THAN_ZERO_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Store last byte.
|
||||
result = b[b.length - 1];
|
||||
|
||||
|
||||
assembly {
|
||||
// Decrement length of byte array.
|
||||
let newLen := sub(mload(b), 1)
|
||||
@@ -54,14 +59,14 @@ contract LibBytes {
|
||||
/// @dev Pops the last 20 bytes off of a byte array by modifying its length.
|
||||
/// @param b Byte array that will be modified.
|
||||
/// @return The 20 byte address that was popped off.
|
||||
function popAddress(bytes memory b)
|
||||
function popLast20Bytes(bytes memory b)
|
||||
internal
|
||||
pure
|
||||
returns (address result)
|
||||
{
|
||||
require(
|
||||
b.length >= 20,
|
||||
GTE_20_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Store last 20 bytes.
|
||||
@@ -75,41 +80,6 @@ contract LibBytes {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Tests equality of two byte arrays.
|
||||
/// @param lhs First byte array to compare.
|
||||
/// @param rhs Second byte array to compare.
|
||||
/// @return True if arrays are the same. False otherwise.
|
||||
function areBytesEqual(
|
||||
bytes memory lhs,
|
||||
bytes memory rhs
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bool equal)
|
||||
{
|
||||
assembly {
|
||||
// Get the number of words occupied by <lhs>
|
||||
let lenFullWords := div(add(mload(lhs), 0x1F), 0x20)
|
||||
|
||||
// Add 1 to the number of words, to account for the length field
|
||||
lenFullWords := add(lenFullWords, 0x1)
|
||||
|
||||
// Test equality word-by-word.
|
||||
// Terminates early if there is a mismatch.
|
||||
for {let i := 0} lt(i, lenFullWords) {i := add(i, 1)} {
|
||||
let lhsWord := mload(add(lhs, mul(i, 0x20)))
|
||||
let rhsWord := mload(add(rhs, mul(i, 0x20)))
|
||||
equal := eq(lhsWord, rhsWord)
|
||||
if eq(equal, 0) {
|
||||
// Break
|
||||
i := lenFullWords
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
/// @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.
|
||||
@@ -124,8 +94,8 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 20, // 20 is length of address
|
||||
GTE_20_LENGTH_REQUIRED
|
||||
);
|
||||
GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Add offset to index:
|
||||
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
|
||||
@@ -156,8 +126,8 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 20, // 20 is length of address
|
||||
GTE_20_LENGTH_REQUIRED
|
||||
);
|
||||
GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Add offset to index:
|
||||
// 1. Arrays are prefixed by 32-byte length parameter (add 32 to index)
|
||||
@@ -195,7 +165,7 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 32,
|
||||
GTE_32_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
@@ -222,7 +192,7 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= index + 32,
|
||||
GTE_32_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
@@ -274,11 +244,130 @@ contract LibBytes {
|
||||
{
|
||||
require(
|
||||
b.length >= 4,
|
||||
GTE_4_LENGTH_REQUIRED
|
||||
GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED
|
||||
);
|
||||
assembly {
|
||||
result := mload(add(b, 32))
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Reads nested bytes from a specific position.
|
||||
/// @param b Byte array containing nested bytes.
|
||||
/// @param index Index of nested bytes.
|
||||
/// @return result Nested bytes.
|
||||
function readBytes(
|
||||
bytes memory b,
|
||||
uint256 index
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory result)
|
||||
{
|
||||
// Read length of nested bytes
|
||||
uint256 nestedBytesLength = readUint256(b, index);
|
||||
index += 32;
|
||||
|
||||
// Assert length of <b> is valid, given
|
||||
// length of nested bytes
|
||||
require(
|
||||
b.length >= index + nestedBytesLength,
|
||||
GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Allocate memory and copy value to result
|
||||
result = new bytes(nestedBytesLength);
|
||||
memCopy(
|
||||
getMemAddress(result) + 32, // +32 skips array length
|
||||
getMemAddress(b) + index + 32,
|
||||
nestedBytesLength
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @dev Inserts bytes at a specific position in a byte array.
|
||||
/// @param b Byte array to insert <input> into.
|
||||
/// @param index Index in byte array of <input>.
|
||||
/// @param input bytes to insert.
|
||||
function writeBytes(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
bytes memory input
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
// Assert length of <b> is valid, given
|
||||
// length of input
|
||||
require(
|
||||
b.length >= index + 32 /* 32 bytes to store length */ + input.length,
|
||||
GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED
|
||||
);
|
||||
|
||||
// Copy <input> into <b>
|
||||
memCopy(
|
||||
getMemAddress(b) + 32 + index, // +32 to skip length of <b>
|
||||
getMemAddress(input), // includes length of <input>
|
||||
input.length + 32 // +32 bytes to store <input> length
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Tests equality of two byte arrays.
|
||||
/// @param lhs First byte array to compare.
|
||||
/// @param rhs Second byte array to compare.
|
||||
/// @return True if arrays are the same. False otherwise.
|
||||
function areBytesEqual(
|
||||
bytes memory lhs,
|
||||
bytes memory rhs
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bool equal)
|
||||
{
|
||||
assembly {
|
||||
// Get the number of words occupied by <lhs>
|
||||
let lenFullWords := div(add(mload(lhs), 0x1F), 0x20)
|
||||
|
||||
// Add 1 to the number of words, to account for the length field
|
||||
lenFullWords := add(lenFullWords, 0x1)
|
||||
|
||||
// Test equality word-by-word.
|
||||
// Terminates early if there is a mismatch.
|
||||
for {let i := 0} lt(i, lenFullWords) {i := add(i, 1)} {
|
||||
let lhsWord := mload(add(lhs, mul(i, 0x20)))
|
||||
let rhsWord := mload(add(rhs, mul(i, 0x20)))
|
||||
equal := eq(lhsWord, rhsWord)
|
||||
if eq(equal, 0) {
|
||||
// Break
|
||||
i := lenFullWords
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
140
packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol
Normal file
140
packages/contracts/src/contracts/current/utils/LibMem/LibMem.sol
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.24;
|
||||
|
||||
contract LibMem
|
||||
{
|
||||
|
||||
/// @dev Gets the memory address for a byte array.
|
||||
/// @param input Byte array to lookup.
|
||||
/// @return memoryAddress Memory address of byte array.
|
||||
function getMemAddress(bytes memory input)
|
||||
internal
|
||||
pure
|
||||
returns (uint256 memoryAddress)
|
||||
{
|
||||
assembly {
|
||||
memoryAddress := input
|
||||
}
|
||||
return memoryAddress;
|
||||
}
|
||||
|
||||
/// @dev Copies `length` bytes from memory location `source` to `dest`.
|
||||
/// @param dest memory address to copy bytes to.
|
||||
/// @param source memory address to copy bytes from.
|
||||
/// @param length number of bytes to copy.
|
||||
function memCopy(
|
||||
uint256 dest,
|
||||
uint256 source,
|
||||
uint256 length
|
||||
)
|
||||
internal
|
||||
pure
|
||||
{
|
||||
if (length < 32) {
|
||||
// Handle a partial word by reading destination and masking
|
||||
// off the bits we are interested in.
|
||||
// This correctly handles overlap, zero lengths and source == dest
|
||||
assembly {
|
||||
let mask := sub(exp(256, sub(32, length)), 1)
|
||||
let s := and(mload(source), not(mask))
|
||||
let d := and(mload(dest), mask)
|
||||
mstore(dest, or(s, d))
|
||||
}
|
||||
} else {
|
||||
// Skip the O(length) loop when source == dest.
|
||||
if (source == dest) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For large copies we copy whole words at a time. The final
|
||||
// word is aligned to the end of the range (instead of after the
|
||||
// previous) to handle partial words. So a copy will look like this:
|
||||
//
|
||||
// ####
|
||||
// ####
|
||||
// ####
|
||||
// ####
|
||||
//
|
||||
// We handle overlap in the source and destination range by
|
||||
// changing the copying direction. This prevents us from
|
||||
// overwriting parts of source that we still need to copy.
|
||||
//
|
||||
// This correctly handles source == dest
|
||||
//
|
||||
if (source > dest) {
|
||||
assembly {
|
||||
// Record the total number of full words to copy
|
||||
let nWords := div(length, 32)
|
||||
|
||||
// We subtract 32 from `sEnd` and `dEnd` because it
|
||||
// is easier to compare with in the loop, and these
|
||||
// are also the addresses we need for copying the
|
||||
// last bytes.
|
||||
length := sub(length, 32)
|
||||
let sEnd := add(source, length)
|
||||
let dEnd := add(dest, length)
|
||||
|
||||
// Remember the last 32 bytes of source
|
||||
// This needs to be done here and not after the loop
|
||||
// because we may have overwritten the last bytes in
|
||||
// source already due to overlap.
|
||||
let last := mload(sEnd)
|
||||
|
||||
// Copy whole words front to back
|
||||
for {let i := 0} lt(i, nWords) {i := add(i, 1)} {
|
||||
mstore(dest, mload(source))
|
||||
source := add(source, 32)
|
||||
dest := add(dest, 32)
|
||||
}
|
||||
|
||||
// Write the last 32 bytes
|
||||
mstore(dEnd, last)
|
||||
}
|
||||
} else {
|
||||
assembly {
|
||||
// Record the total number of full words to copy
|
||||
let nWords := div(length, 32)
|
||||
|
||||
// We subtract 32 from `sEnd` and `dEnd` because those
|
||||
// are the starting points when copying a word at the end.
|
||||
length := sub(length, 32)
|
||||
let sEnd := add(source, length)
|
||||
let dEnd := add(dest, length)
|
||||
|
||||
// Remember the first 32 bytes of source
|
||||
// This needs to be done here and not after the loop
|
||||
// because we may have overwritten the first bytes in
|
||||
// source already due to overlap.
|
||||
let first := mload(source)
|
||||
|
||||
// Copy whole words back to front
|
||||
for {let i := 0} lt(i, nWords) {i := add(i, 1)} {
|
||||
mstore(dEnd, mload(sEnd))
|
||||
sEnd := sub(sEnd, 32)
|
||||
dEnd := sub(dEnd, 32)
|
||||
}
|
||||
|
||||
// Write the first 32 bytes
|
||||
mstore(dest, first)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ import { ContractArtifact } from '@0xproject/sol-compiler';
|
||||
|
||||
import * as AssetProxyOwner from '../artifacts/AssetProxyOwner.json';
|
||||
import * as DummyERC20Token from '../artifacts/DummyERC20Token.json';
|
||||
import * as DummyERC721Receiver from '../artifacts/DummyERC721Receiver.json';
|
||||
import * as DummyERC721Token from '../artifacts/DummyERC721Token.json';
|
||||
import * as ERC20Proxy from '../artifacts/ERC20Proxy.json';
|
||||
import * as ERC721Proxy from '../artifacts/ERC721Proxy.json';
|
||||
@@ -9,8 +10,10 @@ import * as Exchange from '../artifacts/Exchange.json';
|
||||
import * as MixinAuthorizable from '../artifacts/MixinAuthorizable.json';
|
||||
import * as MultiSigWallet from '../artifacts/MultiSigWallet.json';
|
||||
import * as MultiSigWalletWithTimeLock from '../artifacts/MultiSigWalletWithTimeLock.json';
|
||||
import * as TestAssetDataDecoders from '../artifacts/TestAssetDataDecoders.json';
|
||||
import * as TestAssetProxyDispatcher from '../artifacts/TestAssetProxyDispatcher.json';
|
||||
import * as TestLibBytes from '../artifacts/TestLibBytes.json';
|
||||
import * as TestLibMem from '../artifacts/TestLibMem.json';
|
||||
import * as TestLibs from '../artifacts/TestLibs.json';
|
||||
import * as TestSignatureValidator from '../artifacts/TestSignatureValidator.json';
|
||||
import * as TokenRegistry from '../artifacts/TokenRegistry.json';
|
||||
@@ -21,6 +24,7 @@ import * as ZRX from '../artifacts/ZRXToken.json';
|
||||
export const artifacts = {
|
||||
AssetProxyOwner: (AssetProxyOwner as any) as ContractArtifact,
|
||||
DummyERC20Token: (DummyERC20Token as any) as ContractArtifact,
|
||||
DummyERC721Receiver: (DummyERC721Receiver as any) as ContractArtifact,
|
||||
DummyERC721Token: (DummyERC721Token as any) as ContractArtifact,
|
||||
ERC20Proxy: (ERC20Proxy as any) as ContractArtifact,
|
||||
ERC721Proxy: (ERC721Proxy as any) as ContractArtifact,
|
||||
@@ -30,7 +34,9 @@ export const artifacts = {
|
||||
MultiSigWallet: (MultiSigWallet as any) as ContractArtifact,
|
||||
MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
|
||||
TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact,
|
||||
TestAssetDataDecoders: (TestAssetDataDecoders as any) as ContractArtifact,
|
||||
TestLibBytes: (TestLibBytes as any) as ContractArtifact,
|
||||
TestLibMem: (TestLibMem as any) as ContractArtifact,
|
||||
TestLibs: (TestLibs as any) as ContractArtifact,
|
||||
TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact,
|
||||
TokenRegistry: (TokenRegistry as any) as ContractArtifact,
|
||||
|
63
packages/contracts/src/utils/assertions.ts
Normal file
63
packages/contracts/src/utils/assertions.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './constants';
|
||||
|
||||
const expect = chai.expect;
|
||||
|
||||
function _expectEitherErrorAsync<T>(p: Promise<T>, error1: string, error2: string): PromiseLike<void> {
|
||||
return expect(p)
|
||||
.to.be.rejected()
|
||||
.then(e => {
|
||||
expect(e).to.satisfy(
|
||||
(err: Error) => _.includes(err.message, error1) || _.includes(err.message, error2),
|
||||
`expected promise to reject with error message that includes "${error1}" or "${error2}", but got: ` +
|
||||
`"${e.message}"\n`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects if the given Promise does not reject with an error indicating
|
||||
* insufficient funds.
|
||||
* @param p the Promise which is expected to reject
|
||||
* @returns a new Promise which will reject if the conditions are not met and
|
||||
* otherwise resolve with no value.
|
||||
*/
|
||||
export function expectInsufficientFundsAsync<T>(p: Promise<T>): PromiseLike<void> {
|
||||
return _expectEitherErrorAsync(p, 'insufficient funds', "sender doesn't have enough funds");
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects if the given Promise does not reject with a "revert" error or the
|
||||
* given otherError.
|
||||
* @param p the Promise which is expected to reject
|
||||
* @param otherError the other error which is accepted as a valid reject error.
|
||||
* @returns a new Promise which will reject if the conditions are not met and
|
||||
* otherwise resolve with no value.
|
||||
*/
|
||||
export function expectRevertOrOtherErrorAsync<T>(p: Promise<T>, otherError: string): PromiseLike<void> {
|
||||
return _expectEitherErrorAsync(p, constants.REVERT, otherError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects if the given Promise does not reject with a "revert" or "always
|
||||
* failing transaction" error.
|
||||
* @param p the Promise which is expected to reject
|
||||
* @returns a new Promise which will reject if the conditions are not met and
|
||||
* otherwise resolve with no value.
|
||||
*/
|
||||
export function expectRevertOrAlwaysFailingTransactionAsync<T>(p: Promise<T>): PromiseLike<void> {
|
||||
return expectRevertOrOtherErrorAsync(p, 'always failing transaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects if the given Promise does not reject with a "revert" or "Contract
|
||||
* call failed" error.
|
||||
* @param p the Promise which is expected to reject
|
||||
* @returns a new Promise which will reject if the conditions are not met and
|
||||
* otherwise resolve with no value.
|
||||
*/
|
||||
export function expectRevertOrContractCallFailedAsync<T>(p: Promise<T>): PromiseLike<void> {
|
||||
return expectRevertOrOtherErrorAsync<T>(p, 'Contract call failed');
|
||||
}
|
@@ -19,8 +19,19 @@ const TESTRPC_PRIVATE_KEYS_STRINGS = [
|
||||
export const constants = {
|
||||
INVALID_OPCODE: 'invalid opcode',
|
||||
REVERT: 'revert',
|
||||
LIB_BYTES_GREATER_THAN_ZERO_LENGTH_REQUIRED: 'GREATER_THAN_ZERO_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED',
|
||||
LIB_BYTES_GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED: 'GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED',
|
||||
ERC20_INSUFFICIENT_BALANCE: 'Insufficient balance to complete transfer.',
|
||||
ERC20_INSUFFICIENT_ALLOWANCE: 'Insufficient allowance to complete transfer.',
|
||||
TESTRPC_NETWORK_ID: 50,
|
||||
AWAIT_TRANSACTION_MINED_MS: 100,
|
||||
// Note(albrow): In practice V8 and most other engines limit the minimum
|
||||
// interval for setInterval to 10ms. We still set it to 0 here in order to
|
||||
// ensure we always use the minimum interval.
|
||||
AWAIT_TRANSACTION_MINED_MS: 0,
|
||||
MAX_ETHERTOKEN_WITHDRAW_GAS: 43000,
|
||||
MAX_TOKEN_TRANSFERFROM_GAS: 80000,
|
||||
MAX_TOKEN_APPROVE_GAS: 60000,
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { CoverageSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov';
|
||||
import * as fs from 'fs';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
let coverageSubprovider: CoverageSubprovider;
|
||||
@@ -15,7 +14,8 @@ export const coverage = {
|
||||
_getCoverageSubprovider(): CoverageSubprovider {
|
||||
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
|
||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
|
||||
const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress);
|
||||
const isVerbose = true;
|
||||
const subprovider = new CoverageSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
|
||||
return subprovider;
|
||||
},
|
||||
};
|
||||
|
@@ -3,8 +3,8 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { DummyERC20TokenContract } from '../generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../generated_contract_wrappers/e_r_c20_proxy';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { constants } from './constants';
|
||||
|
@@ -4,8 +4,8 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC721ProxyContract } from '../contract_wrappers/generated/e_r_c721_proxy';
|
||||
import { DummyERC721TokenContract } from '../generated_contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC721ProxyContract } from '../generated_contract_wrappers/e_r_c721_proxy';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { constants } from './constants';
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { AssetProxyId, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { LogEntry, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ExchangeContract } from '../contract_wrappers/generated/exchange';
|
||||
import { ExchangeContract } from '../generated_contract_wrappers/exchange';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { formatters } from './formatters';
|
||||
@@ -60,14 +60,14 @@ export class ExchangeWrapper {
|
||||
public async fillOrderNoThrowAsync(
|
||||
signedOrder: SignedOrder,
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const txHash = await this._exchange.fillOrderNoThrow.sendTransactionAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
{ from },
|
||||
{ from, gas: opts.gas },
|
||||
);
|
||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
return tx;
|
||||
@@ -105,14 +105,14 @@ export class ExchangeWrapper {
|
||||
public async batchFillOrdersNoThrowAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
|
||||
const txHash = await this._exchange.batchFillOrdersNoThrow.sendTransactionAsync(
|
||||
params.orders,
|
||||
params.takerAssetFillAmounts,
|
||||
params.signatures,
|
||||
{ from },
|
||||
{ from, gas: opts.gas },
|
||||
);
|
||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
return tx;
|
||||
@@ -135,14 +135,14 @@ export class ExchangeWrapper {
|
||||
public async marketSellOrdersNoThrowAsync(
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount: BigNumber },
|
||||
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
|
||||
const txHash = await this._exchange.marketSellOrdersNoThrow.sendTransactionAsync(
|
||||
params.orders,
|
||||
params.takerAssetFillAmount,
|
||||
params.signatures,
|
||||
{ from },
|
||||
{ from, gas: opts.gas },
|
||||
);
|
||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
return tx;
|
||||
@@ -165,14 +165,14 @@ 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(
|
||||
params.orders,
|
||||
params.makerAssetFillAmount,
|
||||
params.signatures,
|
||||
{ from },
|
||||
{ from, gas: opts.gas },
|
||||
);
|
||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
return tx;
|
||||
|
@@ -2,6 +2,7 @@ import { SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { orderUtils } from './order_utils';
|
||||
import { BatchCancelOrders, BatchFillOrders, MarketBuyOrders, MarketSellOrders } from './types';
|
||||
|
||||
@@ -28,8 +29,11 @@ export const formatters = {
|
||||
signatures: [],
|
||||
takerAssetFillAmount,
|
||||
};
|
||||
_.forEach(signedOrders, signedOrder => {
|
||||
_.forEach(signedOrders, (signedOrder, i) => {
|
||||
const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
if (i !== 0) {
|
||||
orderWithoutExchangeAddress.takerAssetData = constants.NULL_BYTES;
|
||||
}
|
||||
marketSellOrders.orders.push(orderWithoutExchangeAddress);
|
||||
marketSellOrders.signatures.push(signedOrder.signature);
|
||||
});
|
||||
@@ -41,8 +45,11 @@ export const formatters = {
|
||||
signatures: [],
|
||||
makerAssetFillAmount,
|
||||
};
|
||||
_.forEach(signedOrders, signedOrder => {
|
||||
_.forEach(signedOrders, (signedOrder, i) => {
|
||||
const orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
if (i !== 0) {
|
||||
orderWithoutExchangeAddress.makerAssetData = constants.NULL_BYTES;
|
||||
}
|
||||
marketBuyOrders.orders.push(orderWithoutExchangeAddress);
|
||||
marketBuyOrders.signatures.push(signedOrder.signature);
|
||||
});
|
||||
|
31
packages/contracts/src/utils/increase_time.ts
Normal file
31
packages/contracts/src/utils/increase_time.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { web3Wrapper } from './web3_wrapper';
|
||||
|
||||
let firstAccount: string | undefined;
|
||||
|
||||
/**
|
||||
* Increases time by the given number of seconds and then mines a block so that
|
||||
* the current block timestamp has the offset applied.
|
||||
* @param seconds the number of seconds by which to incrase the time offset.
|
||||
* @returns a new Promise which will resolve with the new total time offset or
|
||||
* reject if the time could not be increased.
|
||||
*/
|
||||
export async function increaseTimeAndMineBlockAsync(seconds: number): Promise<number> {
|
||||
if (_.isUndefined(firstAccount)) {
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
firstAccount = accounts[0];
|
||||
}
|
||||
|
||||
const offset = await web3Wrapper.increaseTimeAsync(seconds);
|
||||
// Note: we need to send a transaction after increasing time so
|
||||
// that a block is actually mined. The contract looks at the
|
||||
// last mined block for the timestamp.
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await web3Wrapper.sendTransactionAsync({ from: firstAccount, to: firstAccount, value: 0 }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
return offset;
|
||||
}
|
@@ -39,6 +39,7 @@ export class LogDecoder {
|
||||
}
|
||||
public decodeLogOrThrow<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||
const logWithDecodedArgsOrLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
if (_.isUndefined((logWithDecodedArgsOrLog as LogWithDecodedArgs<ArgsType>).args)) {
|
||||
throw new Error(`Unable to decode log: ${JSON.stringify(log)}`);
|
||||
}
|
||||
|
@@ -1,38 +1,21 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, crypto, orderHashUtils } from '@0xproject/order-utils';
|
||||
import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../contract_wrappers/generated/e_r_c721_proxy';
|
||||
import {
|
||||
CancelContractEventArgs,
|
||||
ExchangeContract,
|
||||
FillContractEventArgs,
|
||||
} from '../contract_wrappers/generated/exchange';
|
||||
import { chaiSetup } from '../utils/chai_setup';
|
||||
import { constants } from '../utils/constants';
|
||||
import { ERC20Wrapper } from '../utils/erc20_wrapper';
|
||||
import { ERC721Wrapper } from '../utils/erc721_wrapper';
|
||||
import { ExchangeWrapper } from '../utils/exchange_wrapper';
|
||||
import { OrderFactory } from '../utils/order_factory';
|
||||
import {
|
||||
ContractName,
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
TransferAmountsByMatchOrders as TransferAmounts,
|
||||
} from '../utils/types';
|
||||
import { provider, web3Wrapper } from '../utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
export class MatchOrderTester {
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
@@ -112,11 +95,6 @@ export class MatchOrderTester {
|
||||
initialTakerAssetFilledAmountLeft?: BigNumber,
|
||||
initialTakerAssetFilledAmountRight?: BigNumber,
|
||||
): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> {
|
||||
// Test setup & verify preconditions
|
||||
const makerAddressLeft = signedOrderLeft.makerAddress;
|
||||
const makerAddressRight = signedOrderRight.makerAddress;
|
||||
const feeRecipientAddressLeft = signedOrderLeft.feeRecipientAddress;
|
||||
const feeRecipientAddressRight = signedOrderRight.feeRecipientAddress;
|
||||
// Verify Left order preconditions
|
||||
const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync(
|
||||
orderHashUtils.getOrderHashHex(signedOrderLeft),
|
||||
@@ -259,11 +237,11 @@ export class MatchOrderTester {
|
||||
const expectedNewERC20BalancesByOwner = _.cloneDeep(erc20BalancesByOwner);
|
||||
const expectedNewERC721TokenIdsByOwner = _.cloneDeep(erc721TokenIdsByOwner);
|
||||
// Left Maker Asset (Right Taker Asset)
|
||||
const makerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.makerAssetData);
|
||||
const makerAssetProxyIdLeft = assetProxyUtils.decodeAssetDataId(signedOrderLeft.makerAssetData);
|
||||
if (makerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
// Decode asset data
|
||||
const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc20ProxyData.tokenAddress;
|
||||
const erc20AssetData = assetProxyUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc20AssetData.tokenAddress;
|
||||
const takerAssetAddressRight = makerAssetAddressLeft;
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
@@ -281,9 +259,9 @@ export class MatchOrderTester {
|
||||
][makerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByTaker);
|
||||
} else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
// Decode asset data
|
||||
const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc721ProxyData.tokenAddress;
|
||||
const makerAssetIdLeft = erc721ProxyData.tokenId;
|
||||
const erc721AssetData = assetProxyUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData);
|
||||
const makerAssetAddressLeft = erc721AssetData.tokenAddress;
|
||||
const makerAssetIdLeft = erc721AssetData.tokenId;
|
||||
const takerAssetAddressRight = makerAssetAddressLeft;
|
||||
const takerAssetIdRight = makerAssetIdLeft;
|
||||
// Left Maker
|
||||
@@ -294,11 +272,11 @@ export class MatchOrderTester {
|
||||
}
|
||||
// Left Taker Asset (Right Maker Asset)
|
||||
// Note: This exchange is only between the order makers: the Taker does not receive any of the left taker asset.
|
||||
const takerAssetProxyIdLeft = assetProxyUtils.decodeProxyDataId(signedOrderLeft.takerAssetData);
|
||||
const takerAssetProxyIdLeft = assetProxyUtils.decodeAssetDataId(signedOrderLeft.takerAssetData);
|
||||
if (takerAssetProxyIdLeft === AssetProxyId.ERC20) {
|
||||
// Decode asset data
|
||||
const erc20ProxyData = assetProxyUtils.decodeERC20ProxyData(signedOrderLeft.takerAssetData);
|
||||
const takerAssetAddressLeft = erc20ProxyData.tokenAddress;
|
||||
const erc20AssetData = assetProxyUtils.decodeERC20AssetData(signedOrderLeft.takerAssetData);
|
||||
const takerAssetAddressLeft = erc20AssetData.tokenAddress;
|
||||
const makerAssetAddressRight = takerAssetAddressLeft;
|
||||
// Left Maker
|
||||
expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[
|
||||
@@ -312,9 +290,9 @@ export class MatchOrderTester {
|
||||
);
|
||||
} else if (takerAssetProxyIdLeft === AssetProxyId.ERC721) {
|
||||
// Decode asset data
|
||||
const erc721ProxyData = assetProxyUtils.decodeERC721ProxyData(signedOrderRight.makerAssetData);
|
||||
const makerAssetAddressRight = erc721ProxyData.tokenAddress;
|
||||
const makerAssetIdRight = erc721ProxyData.tokenId;
|
||||
const erc721AssetData = assetProxyUtils.decodeERC721AssetData(signedOrderRight.makerAssetData);
|
||||
const makerAssetAddressRight = erc721AssetData.tokenAddress;
|
||||
const makerAssetIdRight = erc721AssetData.tokenId;
|
||||
const takerAssetAddressLeft = makerAssetAddressRight;
|
||||
const takerAssetIdLeft = makerAssetIdRight;
|
||||
// Right Maker
|
||||
|
@@ -3,10 +3,9 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AssetProxyOwnerContract } from '../contract_wrappers/generated/asset_proxy_owner';
|
||||
import { MultiSigWalletContract } from '../contract_wrappers/generated/multi_sig_wallet';
|
||||
import { AssetProxyOwnerContract } from '../generated_contract_wrappers/asset_proxy_owner';
|
||||
import { MultiSigWalletContract } from '../generated_contract_wrappers/multi_sig_wallet';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { LogDecoder } from './log_decoder';
|
||||
|
||||
export class MultiSigWrapper {
|
||||
@@ -45,6 +44,7 @@ export class MultiSigWrapper {
|
||||
txId: BigNumber,
|
||||
from: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const txHash = await (this
|
||||
._multiSig as AssetProxyOwnerContract).executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from });
|
||||
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { generatePseudoRandomSalt, orderHashUtils } from '@0xproject/order-utils';
|
||||
import { Order, SignatureType, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { signingUtils } from './signing_utils';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import { constants } from './constants';
|
||||
import { CancelOrder, MatchOrder } from './types';
|
||||
|
||||
export const orderUtils = {
|
||||
@@ -44,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;
|
||||
},
|
||||
};
|
||||
|
27
packages/contracts/src/utils/profiler.ts
Normal file
27
packages/contracts/src/utils/profiler.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
let profilerSubprovider: ProfilerSubprovider;
|
||||
|
||||
export const profiler = {
|
||||
start(): void {
|
||||
profiler.getProfilerSubproviderSingleton().start();
|
||||
},
|
||||
stop(): void {
|
||||
profiler.getProfilerSubproviderSingleton().stop();
|
||||
},
|
||||
getProfilerSubproviderSingleton(): ProfilerSubprovider {
|
||||
if (_.isUndefined(profilerSubprovider)) {
|
||||
profilerSubprovider = profiler._getProfilerSubprovider();
|
||||
}
|
||||
return profilerSubprovider;
|
||||
},
|
||||
_getProfilerSubprovider(): ProfilerSubprovider {
|
||||
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
|
||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
|
||||
const isVerbose = true;
|
||||
const subprovider = new ProfilerSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
|
||||
return subprovider;
|
||||
},
|
||||
};
|
21
packages/contracts/src/utils/revert_trace.ts
Normal file
21
packages/contracts/src/utils/revert_trace.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { devConstants } from '@0xproject/dev-utils';
|
||||
import { RevertTraceSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
let revertTraceSubprovider: RevertTraceSubprovider;
|
||||
|
||||
export const revertTrace = {
|
||||
getRevertTraceSubproviderSingleton(): RevertTraceSubprovider {
|
||||
if (_.isUndefined(revertTraceSubprovider)) {
|
||||
revertTraceSubprovider = revertTrace._getRevertTraceSubprovider();
|
||||
}
|
||||
return revertTraceSubprovider;
|
||||
},
|
||||
_getRevertTraceSubprovider(): RevertTraceSubprovider {
|
||||
const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS;
|
||||
const solCompilerArtifactAdapter = new SolCompilerArtifactAdapter();
|
||||
const isVerbose = true;
|
||||
const subprovider = new RevertTraceSubprovider(solCompilerArtifactAdapter, defaultFromAddress, isVerbose);
|
||||
return subprovider;
|
||||
},
|
||||
};
|
@@ -1,7 +1,7 @@
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider } from 'ethereum-types';
|
||||
|
||||
import { TokenRegistryContract } from '../contract_wrappers/generated/token_registry';
|
||||
import { TokenRegistryContract } from '../generated_contract_wrappers/token_registry';
|
||||
|
||||
import { Token } from './types';
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Order, OrderWithoutExchangeAddress } from '@0xproject/types';
|
||||
import { OrderWithoutExchangeAddress } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { AbiDefinition, ContractAbi } from 'ethereum-types';
|
||||
import { AbiDefinition } from 'ethereum-types';
|
||||
|
||||
export interface ERC20BalancesByOwner {
|
||||
[ownerAddress: string]: {
|
||||
@@ -90,11 +90,14 @@ export enum ContractName {
|
||||
AccountLevels = 'AccountLevels',
|
||||
EtherDelta = 'EtherDelta',
|
||||
Arbitrage = 'Arbitrage',
|
||||
TestAssetDataDecoders = 'TestAssetDataDecoders',
|
||||
TestAssetProxyDispatcher = 'TestAssetProxyDispatcher',
|
||||
TestLibMem = 'TestLibMem',
|
||||
TestLibs = 'TestLibs',
|
||||
TestSignatureValidator = 'TestSignatureValidator',
|
||||
ERC20Proxy = 'ERC20Proxy',
|
||||
ERC721Proxy = 'ERC721Proxy',
|
||||
DummyERC721Receiver = 'DummyERC721Receiver',
|
||||
DummyERC721Token = 'DummyERC721Token',
|
||||
TestLibBytes = 'TestLibBytes',
|
||||
Authorizable = 'Authorizable',
|
||||
|
@@ -1,19 +1,82 @@
|
||||
import { devConstants, env, EnvVars, web3Factory } from '@0xproject/dev-utils';
|
||||
import { prependSubprovider } from '@0xproject/subproviders';
|
||||
import { logUtils } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { Provider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { coverage } from './coverage';
|
||||
import { profiler } from './profiler';
|
||||
import { revertTrace } from './revert_trace';
|
||||
|
||||
export const txDefaults = {
|
||||
enum ProviderType {
|
||||
Ganache = 'ganache',
|
||||
Geth = 'geth',
|
||||
}
|
||||
|
||||
let testProvider: ProviderType;
|
||||
switch (process.env.TEST_PROVIDER) {
|
||||
case undefined:
|
||||
testProvider = ProviderType.Ganache;
|
||||
break;
|
||||
case 'ganache':
|
||||
testProvider = ProviderType.Ganache;
|
||||
break;
|
||||
case 'geth':
|
||||
testProvider = ProviderType.Geth;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown TEST_PROVIDER: ${process.env.TEST_PROVIDER}`);
|
||||
}
|
||||
|
||||
const ganacheTxDefaults = {
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
gas: devConstants.GAS_LIMIT,
|
||||
};
|
||||
const providerConfigs = { shouldUseInProcessGanache: true };
|
||||
const gethTxDefaults = {
|
||||
from: devConstants.TESTRPC_FIRST_ADDRESS,
|
||||
};
|
||||
export const txDefaults = testProvider === ProviderType.Ganache ? ganacheTxDefaults : gethTxDefaults;
|
||||
|
||||
const gethConfigs = {
|
||||
shouldUseInProcessGanache: false,
|
||||
rpcUrl: 'http://localhost:8501',
|
||||
shouldUseFakeGasEstimate: false,
|
||||
};
|
||||
const ganacheConfigs = {
|
||||
shouldUseInProcessGanache: true,
|
||||
};
|
||||
const providerConfigs = testProvider === ProviderType.Ganache ? ganacheConfigs : gethConfigs;
|
||||
|
||||
export const provider = web3Factory.getRpcProvider(providerConfigs);
|
||||
const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
|
||||
const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler);
|
||||
const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace);
|
||||
const enabledSubproviderCount = _.filter([isCoverageEnabled, isProfilerEnabled, isRevertTraceEnabled], _.identity)
|
||||
.length;
|
||||
if (enabledSubproviderCount > 1) {
|
||||
throw new Error(`Only one of coverage, profiler, or revert trace subproviders can be enabled at a time`);
|
||||
}
|
||||
if (isCoverageEnabled) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
prependSubprovider(provider, coverageSubprovider);
|
||||
}
|
||||
if (isProfilerEnabled) {
|
||||
if (testProvider === ProviderType.Ganache) {
|
||||
logUtils.warn(
|
||||
"Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
logUtils.log(
|
||||
"By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
|
||||
);
|
||||
profilerSubprovider.stop();
|
||||
prependSubprovider(provider, profilerSubprovider);
|
||||
}
|
||||
if (isRevertTraceEnabled) {
|
||||
const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton();
|
||||
prependSubprovider(provider, revertTraceSubprovider);
|
||||
}
|
||||
|
||||
export const web3Wrapper = new Web3Wrapper(provider);
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { MixinAuthorizableContract } from '../../src/contract_wrappers/generated/mixin_authorizable';
|
||||
import { MixinAuthorizableContract } from '../../src/generated_contract_wrappers/mixin_authorizable';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
@@ -44,9 +43,9 @@ describe('Authorizable', () => {
|
||||
});
|
||||
describe('addAuthorizedAddress', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
it('should allow owner to add an authorized address', async () => {
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
@@ -61,9 +60,9 @@ describe('Authorizable', () => {
|
||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,11 +72,11 @@ describe('Authorizable', () => {
|
||||
await authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||
from: notOwner,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow owner to remove an authorized address', async () => {
|
||||
@@ -96,11 +95,11 @@ describe('Authorizable', () => {
|
||||
});
|
||||
|
||||
it('should throw if owner attempts to remove an address that is not authorized', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
|
||||
from: owner,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
86
packages/contracts/test/asset_proxy/decoder.ts
Normal file
86
packages/contracts/test/asset_proxy/decoder.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import { TestAssetDataDecodersContract } from '../../src/generated_contract_wrappers/test_asset_data_decoders';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('TestAssetDataDecoders', () => {
|
||||
let testAssetProxyDecoder: TestAssetDataDecodersContract;
|
||||
let testAddress: string;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
// Setup accounts & addresses
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
testAddress = accounts[0];
|
||||
// Deploy TestLibMem
|
||||
testAssetProxyDecoder = await TestAssetDataDecodersContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestAssetDataDecoders,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('Asset Data Decoders', () => {
|
||||
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 decodedTokenAddress: string;
|
||||
let decodedTokenId: BigNumber;
|
||||
let decodedData: string;
|
||||
[
|
||||
decodedTokenAddress,
|
||||
decodedTokenId,
|
||||
decodedData,
|
||||
] = 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);
|
||||
});
|
||||
|
||||
it('should correctly decode ERC721 asset data with receiver data', async () => {
|
||||
const tokenId = generatePseudoRandomSalt();
|
||||
const receiverDataFirst32Bytes = ethUtil.bufferToHex(
|
||||
assetProxyUtils.encodeUint256(generatePseudoRandomSalt()),
|
||||
);
|
||||
const receiverDataExtraBytes = 'FFFF';
|
||||
// We add extra bytes to generate a value that doesn't fit perfectly into one word
|
||||
const receiverData = receiverDataFirst32Bytes + receiverDataExtraBytes;
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(testAddress, tokenId, receiverData);
|
||||
const expectedDecodedAssetData = assetProxyUtils.decodeERC721AssetData(encodedAssetData);
|
||||
let decodedTokenAddress: string;
|
||||
let decodedTokenId: BigNumber;
|
||||
let decodedReceiverData: string;
|
||||
[
|
||||
decodedTokenAddress,
|
||||
decodedTokenId,
|
||||
decodedReceiverData,
|
||||
] = await testAssetProxyDecoder.publicDecodeERC721Data.callAsync(encodedAssetData);
|
||||
expect(decodedTokenAddress).to.be.equal(expectedDecodedAssetData.tokenAddress);
|
||||
expect(decodedTokenId).to.be.bignumber.equal(expectedDecodedAssetData.tokenId);
|
||||
expect(decodedReceiverData).to.be.equal(expectedDecodedAssetData.receiverData);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,25 +1,33 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId } from '@0xproject/types';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import {
|
||||
DummyERC721ReceiverContract,
|
||||
TokenReceivedContractEventArgs,
|
||||
} from '../../src/generated_contract_wrappers/dummy_e_r_c721_receiver';
|
||||
import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||
import { provider, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
import { LogDecoder } from '../../src/utils/log_decoder';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Asset Transfer Proxies', () => {
|
||||
let owner: string;
|
||||
let notAuthorized: string;
|
||||
@@ -29,6 +37,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let erc721Receiver: DummyERC721ReceiverContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
let erc721Proxy: ERC721ProxyContract;
|
||||
|
||||
@@ -70,6 +79,11 @@ describe('Asset Transfer Proxies', () => {
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
erc721Receiver = await DummyERC721ReceiverContract.deployFrom0xArtifactAsync(
|
||||
artifacts.DummyERC721Receiver,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -80,14 +94,15 @@ describe('Asset Transfer Proxies', () => {
|
||||
describe('Transfer Proxy - ERC20', () => {
|
||||
describe('transferFrom', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// 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(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -106,14 +121,15 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should do nothing if transferring 0 amount of a token', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// 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(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -132,8 +148,8 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if allowances are too low', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// Construct ERC20 asset data
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
// Create allowance less than transfer amount. Set allowance on proxy.
|
||||
const allowance = new BigNumber(0);
|
||||
const transferAmount = new BigNumber(10);
|
||||
@@ -144,25 +160,26 @@ describe('Asset Transfer Proxies', () => {
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
// Perform a transfer; expect this to fail.
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetData,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
transferAmount,
|
||||
{ from: notAuthorized },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if requesting address is not authorized', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
// 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 expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -170,7 +187,7 @@ describe('Asset Transfer Proxies', () => {
|
||||
from: notAuthorized,
|
||||
},
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -178,16 +195,17 @@ describe('Asset Transfer Proxies', () => {
|
||||
it('should succesfully make multiple token transfers', async () => {
|
||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
const amount = new BigNumber(10);
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = _.times(numTransfers, () => encodedProxyMetadata);
|
||||
const assetData = _.times(numTransfers, () => encodedAssetDataWithoutProxyId);
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => amount);
|
||||
|
||||
const txHash = await erc20Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
@@ -209,23 +227,20 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
|
||||
it('should throw if not called by an authorized address', async () => {
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
const encodedAssetData = assetProxyUtils.encodeERC20AssetData(zrxToken.address);
|
||||
const encodedAssetDataWithoutProxyId = encodedAssetData.slice(0, -2);
|
||||
const amount = new BigNumber(10);
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = _.times(numTransfers, () => encodedProxyMetadata);
|
||||
const assetData = _.times(numTransfers, () => encodedAssetDataWithoutProxyId);
|
||||
const fromAddresses = _.times(numTransfers, () => makerAddress);
|
||||
const toAddresses = _.times(numTransfers, () => takerAddress);
|
||||
const amounts = _.times(numTransfers, () => amount);
|
||||
|
||||
return expect(
|
||||
erc20Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
{ from: notAuthorized },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -238,20 +253,17 @@ describe('Asset Transfer Proxies', () => {
|
||||
describe('Transfer Proxy - ERC721', () => {
|
||||
describe('transferFrom', () => {
|
||||
it('should successfully transfer tokens', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// 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 erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(1);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -264,58 +276,138 @@ describe('Asset Transfer Proxies', () => {
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
});
|
||||
|
||||
it('should throw if transferring 0 amount of a token', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
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 erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(0);
|
||||
return expect(
|
||||
const amount = new BigNumber(1);
|
||||
const txHash = await erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
erc721Receiver.address,
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
||||
// Parse transaction logs
|
||||
const logDecoder = new LogDecoder(web3Wrapper, erc721Receiver.address);
|
||||
const tx = await logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
// Verify that no log was emitted by erc721 receiver
|
||||
expect(tx.logs.length).to.be.equal(0);
|
||||
// Verify transfer was successful
|
||||
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(erc721Receiver.address);
|
||||
});
|
||||
|
||||
it('should call onERC721Received when transferring to a smart contract with receiver data', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const receiverData = ethUtil.bufferToHex(assetProxyUtils.encodeUint256(generatePseudoRandomSalt()));
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(
|
||||
erc721Token.address,
|
||||
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(
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
erc721Receiver.address,
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS);
|
||||
// Parse transaction logs
|
||||
const logDecoder = new LogDecoder(web3Wrapper, erc721Receiver.address);
|
||||
const tx = await logDecoder.getTxWithDecodedLogsAsync(txHash);
|
||||
// Validate log emitted by erc721 receiver
|
||||
expect(tx.logs.length).to.be.equal(1);
|
||||
const tokenReceivedLog = tx.logs[0] as LogWithDecodedArgs<TokenReceivedContractEventArgs>;
|
||||
expect(tokenReceivedLog.args.from).to.be.equal(makerAddress);
|
||||
expect(tokenReceivedLog.args.tokenId).to.be.bignumber.equal(erc721MakerTokenId);
|
||||
expect(tokenReceivedLog.args.data).to.be.equal(receiverData);
|
||||
// Verify transfer was successful
|
||||
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(erc721MakerTokenId);
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(erc721Receiver.address);
|
||||
});
|
||||
|
||||
it('should throw if there is receiver data but contract does not have onERC721Received', async () => {
|
||||
// Construct ERC721 asset data
|
||||
const receiverData = ethUtil.bufferToHex(assetProxyUtils.encodeUint256(generatePseudoRandomSalt()));
|
||||
const encodedAssetData = assetProxyUtils.encodeERC721AssetData(
|
||||
erc721Token.address,
|
||||
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);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
erc20Proxy.address, // the ERC20 proxy does not have an ERC721 receiver
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
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);
|
||||
// Perform a transfer from makerAddress to takerAddress
|
||||
const amount = new BigNumber(0);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if transferring > 1 amount of a token', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// 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 erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
const amount = new BigNumber(500);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{ from: exchangeAddress },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if allowances are too low', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// 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, {
|
||||
@@ -325,9 +417,9 @@ describe('Asset Transfer Proxies', () => {
|
||||
);
|
||||
// Perform a transfer; expect this to fail.
|
||||
const amount = new BigNumber(1);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc20Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -335,26 +427,24 @@ describe('Asset Transfer Proxies', () => {
|
||||
from: notAuthorized,
|
||||
},
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if requesting address is not authorized', async () => {
|
||||
// Construct metadata for ERC721 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC721ProxyData(
|
||||
erc721Token.address,
|
||||
erc721MakerTokenId,
|
||||
);
|
||||
// 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 expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.transferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{ from: notAuthorized },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -364,16 +454,16 @@ describe('Asset Transfer Proxies', () => {
|
||||
const [makerTokenIdA, makerTokenIdB] = erc721TokensById[makerAddress][erc721Token.address];
|
||||
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = [
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdB),
|
||||
const assetData = [
|
||||
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);
|
||||
const amounts = _.times(numTransfers, () => new BigNumber(1));
|
||||
|
||||
const txHash = await erc721Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
assetData,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
@@ -396,23 +486,19 @@ describe('Asset Transfer Proxies', () => {
|
||||
const [makerTokenIdA, makerTokenIdB] = erc721TokensById[makerAddress][erc721Token.address];
|
||||
|
||||
const numTransfers = 2;
|
||||
const assetMetadata = [
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdA),
|
||||
assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerTokenIdB),
|
||||
const assetData = [
|
||||
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);
|
||||
const amounts = _.times(numTransfers, () => new BigNumber(1));
|
||||
|
||||
return expect(
|
||||
erc721Proxy.batchTransferFrom.sendTransactionAsync(
|
||||
assetMetadata,
|
||||
fromAddresses,
|
||||
toAddresses,
|
||||
amounts,
|
||||
{ from: notAuthorized },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
erc721Proxy.batchTransferFrom.sendTransactionAsync(assetData, fromAddresses, toAddresses, amounts, {
|
||||
from: notAuthorized,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -422,3 +508,5 @@ describe('Asset Transfer Proxies', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
// tslint:disable:max-file-line-count
|
||||
|
@@ -2,9 +2,7 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {
|
||||
AssetProxyOwnerContract,
|
||||
@@ -12,18 +10,23 @@ import {
|
||||
ExecutionContractEventArgs,
|
||||
ExecutionFailureContractEventArgs,
|
||||
SubmissionContractEventArgs,
|
||||
} from '../src/contract_wrappers/generated/asset_proxy_owner';
|
||||
import { MixinAuthorizableContract } from '../src/contract_wrappers/generated/mixin_authorizable';
|
||||
} from '../src/generated_contract_wrappers/asset_proxy_owner';
|
||||
import { MixinAuthorizableContract } from '../src/generated_contract_wrappers/mixin_authorizable';
|
||||
import { artifacts } from '../src/utils/artifacts';
|
||||
import {
|
||||
expectRevertOrAlwaysFailingTransactionAsync,
|
||||
expectRevertOrContractCallFailedAsync,
|
||||
} from '../src/utils/assertions';
|
||||
import { chaiSetup } from '../src/utils/chai_setup';
|
||||
import { constants } from '../src/utils/constants';
|
||||
import { increaseTimeAndMineBlockAsync } from '../src/utils/increase_time';
|
||||
import { MultiSigWrapper } from '../src/utils/multi_sig_wrapper';
|
||||
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('AssetProxyOwner', () => {
|
||||
let owners: string[];
|
||||
let authorized: string;
|
||||
@@ -101,7 +104,7 @@ describe('AssetProxyOwner', () => {
|
||||
});
|
||||
it('should throw if a null address is included in assetProxyContracts', async () => {
|
||||
const assetProxyContractAddresses = [erc20Proxy.address, constants.NULL_ADDRESS];
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
AssetProxyOwnerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.AssetProxyOwner,
|
||||
provider,
|
||||
@@ -111,7 +114,7 @@ describe('AssetProxyOwner', () => {
|
||||
REQUIRED_APPROVALS,
|
||||
SECONDS_TIME_LOCKED,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -120,9 +123,9 @@ describe('AssetProxyOwner', () => {
|
||||
const notRemoveAuthorizedAddressData = erc20Proxy.addAuthorizedAddress.getABIEncodedTransactionData(
|
||||
owners[0],
|
||||
);
|
||||
return expect(
|
||||
return expectRevertOrContractCallFailedAsync(
|
||||
multiSig.isFunctionRemoveAuthorizedAddress.callAsync(notRemoveAuthorizedAddressData),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true if data is for removeAuthorizedAddress', async () => {
|
||||
@@ -139,9 +142,9 @@ describe('AssetProxyOwner', () => {
|
||||
describe('registerAssetProxy', () => {
|
||||
it('should throw if not called by multisig', async () => {
|
||||
const isRegistered = true;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, isRegistered, { from: owners[0] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should register an address if called by multisig after timelock', async () => {
|
||||
@@ -156,11 +159,12 @@ describe('AssetProxyOwner', () => {
|
||||
registerAssetProxyData,
|
||||
owners[0],
|
||||
);
|
||||
|
||||
const log = submitTxRes.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
|
||||
const txId = log.args.transactionId;
|
||||
|
||||
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
|
||||
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
|
||||
const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
|
||||
const registerLog = executeTxRes.logs[0] as LogWithDecodedArgs<AssetProxyRegistrationContractEventArgs>;
|
||||
@@ -187,7 +191,7 @@ describe('AssetProxyOwner', () => {
|
||||
const txId = log.args.transactionId;
|
||||
|
||||
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
|
||||
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
|
||||
const executeTxRes = await multiSigWrapper.executeTransactionAsync(txId, owners[0]);
|
||||
const failureLog = executeTxRes.logs[0] as LogWithDecodedArgs<ExecutionFailureContractEventArgs>;
|
||||
@@ -239,7 +243,7 @@ describe('AssetProxyOwner', () => {
|
||||
|
||||
await multiSigWrapper.confirmTransactionAsync(erc20AddAuthorizedAddressTxId, owners[1]);
|
||||
await multiSigWrapper.confirmTransactionAsync(erc721AddAuthorizedAddressTxId, owners[1]);
|
||||
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
await multiSigWrapper.executeTransactionAsync(registerAssetProxyTxId, owners[0]);
|
||||
await multiSigWrapper.executeTransactionAsync(erc20AddAuthorizedAddressTxId, owners[0]);
|
||||
await multiSigWrapper.executeTransactionAsync(erc721AddAuthorizedAddressTxId, owners[0]);
|
||||
@@ -257,9 +261,9 @@ describe('AssetProxyOwner', () => {
|
||||
const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
|
||||
const txId = log.args.transactionId;
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if tx destination is not registered', async () => {
|
||||
@@ -276,9 +280,9 @@ describe('AssetProxyOwner', () => {
|
||||
|
||||
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if tx data is not for removeAuthorizedAddress', async () => {
|
||||
@@ -296,9 +300,9 @@ describe('AssetProxyOwner', () => {
|
||||
|
||||
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should execute removeAuthorizedAddress for registered address if fully confirmed', async () => {
|
||||
@@ -349,9 +353,10 @@ describe('AssetProxyOwner', () => {
|
||||
const isExecuted = tx[3];
|
||||
expect(isExecuted).to.equal(true);
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.executeRemoveAuthorizedAddress.sendTransactionAsync(txId, { from: owners[1] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BigNumber, promisify } from '@0xproject/utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { WETH9Contract } from '../src/contract_wrappers/generated/weth9';
|
||||
import { WETH9Contract } from '../src/generated_contract_wrappers/weth9';
|
||||
import { artifacts } from '../src/utils/artifacts';
|
||||
import { expectInsufficientFundsAsync, expectRevertOrAlwaysFailingTransactionAsync } from '../src/utils/assertions';
|
||||
import { chaiSetup } from '../src/utils/chai_setup';
|
||||
import { constants } from '../src/utils/constants';
|
||||
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
|
||||
@@ -45,9 +46,7 @@ describe('EtherToken', () => {
|
||||
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
|
||||
const ethToDeposit = initEthBalance.plus(1);
|
||||
|
||||
return expect(etherToken.deposit.sendTransactionAsync({ value: ethToDeposit })).to.be.rejectedWith(
|
||||
"ender doesn't have enough funds to send tx.",
|
||||
);
|
||||
return expectInsufficientFundsAsync(etherToken.deposit.sendTransactionAsync({ value: ethToDeposit }));
|
||||
});
|
||||
|
||||
it('should convert deposited Ether to wrapped Ether tokens', async () => {
|
||||
@@ -76,8 +75,8 @@ describe('EtherToken', () => {
|
||||
const initEthTokenBalance = await etherToken.balanceOf.callAsync(account);
|
||||
const ethTokensToWithdraw = initEthTokenBalance.plus(1);
|
||||
|
||||
return expect(etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
etherToken.withdraw.sendTransactionAsync(ethTokensToWithdraw),
|
||||
);
|
||||
});
|
||||
|
||||
|
@@ -8,16 +8,17 @@ import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import 'make-promises-safe';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy';
|
||||
import {
|
||||
CancelContractEventArgs,
|
||||
ExchangeContract,
|
||||
FillContractEventArgs,
|
||||
} from '../../src/contract_wrappers/generated/exchange';
|
||||
} from '../../src/generated_contract_wrappers/exchange';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
@@ -30,7 +31,7 @@ import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper'
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('Exchange core', () => {
|
||||
let makerAddress: string;
|
||||
let owner: string;
|
||||
@@ -86,7 +87,7 @@ describe('Exchange core', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
zrxToken.address,
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -113,8 +114,8 @@ describe('Exchange core', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
@@ -414,8 +415,8 @@ describe('Exchange core', () => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
|
||||
});
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -431,8 +432,8 @@ describe('Exchange core', () => {
|
||||
const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
|
||||
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
|
||||
signedOrder.signature = invalidSigHex;
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -441,8 +442,8 @@ describe('Exchange core', () => {
|
||||
makerAssetAmount: new BigNumber(0),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -451,19 +452,19 @@ describe('Exchange core', () => {
|
||||
takerAssetAmount: new BigNumber(0),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if takerAssetFillAmount is 0', async () => {
|
||||
signedOrder = orderFactory.newSignedOrder();
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
|
||||
takerAssetFillAmount: new BigNumber(0),
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if maker erc20Balances are too low to fill order', async () => {
|
||||
@@ -471,8 +472,8 @@ describe('Exchange core', () => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -480,9 +481,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100000), 18),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -493,11 +493,8 @@ describe('Exchange core', () => {
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
// HACK: `rejectWith` returns a "promise-like" type, but not an actual "Promise", so TSLint
|
||||
// complains, even though we do need to `await` it. So we disable the TSLint error below.
|
||||
// tslint:disable-next-line:await-promise
|
||||
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -508,11 +505,8 @@ describe('Exchange core', () => {
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
// HACK: `rejectWith` returns a "promise-like" type, but not an actual "Promise", so TSLint
|
||||
// complains, even though we do need to `await` it. So we disable the TSLint error below.
|
||||
// tslint:disable-next-line:await-promise
|
||||
await expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -520,16 +514,16 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
|
||||
});
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if no value is filled', async () => {
|
||||
signedOrder = orderFactory.newSignedOrder();
|
||||
await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress);
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -541,8 +535,8 @@ describe('Exchange core', () => {
|
||||
});
|
||||
|
||||
it('should throw if not sent by maker', async () => {
|
||||
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -551,8 +545,8 @@ describe('Exchange core', () => {
|
||||
makerAssetAmount: new BigNumber(0),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -561,22 +555,21 @@ describe('Exchange core', () => {
|
||||
takerAssetAmount: new BigNumber(0),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to cancel a full order', async () => {
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
|
||||
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should log 1 event with correct arguments', async () => {
|
||||
const divisor = 2;
|
||||
const res = await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
|
||||
expect(res.logs).to.have.length(1);
|
||||
|
||||
@@ -592,8 +585,8 @@ describe('Exchange core', () => {
|
||||
|
||||
it('should throw if already cancelled', async () => {
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress);
|
||||
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -601,8 +594,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
|
||||
});
|
||||
return expect(exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrderAsync(signedOrder, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -618,11 +611,11 @@ describe('Exchange core', () => {
|
||||
});
|
||||
|
||||
const fillTakerAssetAmount2 = new BigNumber(1);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, {
|
||||
takerAssetFillAmount: fillTakerAssetAmount2,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -631,16 +624,16 @@ describe('Exchange core', () => {
|
||||
const makerEpoch = new BigNumber(1);
|
||||
await exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress);
|
||||
const lesserMakerEpoch = new BigNumber(0);
|
||||
return expect(exchangeWrapper.cancelOrdersUpToAsync(lesserMakerEpoch, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrdersUpToAsync(lesserMakerEpoch, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail to set makerEpoch equal to existing makerEpoch', async () => {
|
||||
const makerEpoch = new BigNumber(1);
|
||||
await exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress);
|
||||
return expect(exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.cancelOrdersUpToAsync(makerEpoch, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -674,7 +667,12 @@ describe('Exchange core', () => {
|
||||
salt: new BigNumber(3),
|
||||
}),
|
||||
];
|
||||
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress);
|
||||
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
// 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: 490000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
const fillMakerAssetAmount = signedOrders[2].makerAssetAmount.add(signedOrders[3].makerAssetAmount);
|
||||
@@ -713,8 +711,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -723,6 +721,7 @@ describe('Exchange core', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
const res = await exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
||||
// Verify post-conditions
|
||||
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -738,8 +737,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -748,9 +747,9 @@ describe('Exchange core', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw when taker does not own the token with id takerAssetId', async () => {
|
||||
@@ -760,8 +759,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -770,9 +769,9 @@ describe('Exchange core', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.not.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw when makerAssetAmount is greater than 1', async () => {
|
||||
@@ -782,8 +781,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(2),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -792,9 +791,9 @@ describe('Exchange core', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw when takerAssetAmount is greater than 1', async () => {
|
||||
@@ -804,8 +803,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(500),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -814,9 +813,9 @@ describe('Exchange core', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw on partial fill', async () => {
|
||||
@@ -826,8 +825,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(0),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -836,9 +835,9 @@ describe('Exchange core', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, takerAddress, { takerAssetFillAmount }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should successfully fill order when makerAsset is ERC721 and takerAsset is ERC20', async () => {
|
||||
@@ -847,8 +846,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -887,8 +886,8 @@ describe('Exchange core', () => {
|
||||
signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerTakerAsset = await erc721Token.ownerOf.callAsync(takerAssetId);
|
||||
@@ -921,4 +920,6 @@ describe('Exchange core', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
}); // tslint:disable-line:max-file-line-count
|
||||
});
|
||||
// tslint:disable:max-file-line-count
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
|
@@ -3,13 +3,13 @@ import { assetProxyUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import { TestAssetProxyDispatcherContract } from '../../src/contract_wrappers/generated/test_asset_proxy_dispatcher';
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy';
|
||||
import { TestAssetProxyDispatcherContract } from '../../src/generated_contract_wrappers/test_asset_proxy_dispatcher';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
@@ -23,7 +23,6 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
describe('AssetProxyDispatcher', () => {
|
||||
let owner: string;
|
||||
let notOwner: string;
|
||||
let notAuthorized: string;
|
||||
let makerAddress: string;
|
||||
let takerAddress: string;
|
||||
|
||||
@@ -45,7 +44,6 @@ describe('AssetProxyDispatcher', () => {
|
||||
// Setup accounts & addresses
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const usedAddresses = ([owner, notOwner, makerAddress, takerAddress] = accounts);
|
||||
notAuthorized = notOwner;
|
||||
|
||||
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||
erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
|
||||
@@ -177,14 +175,14 @@ describe('AssetProxyDispatcher', () => {
|
||||
const proxyAddress = await assetProxyDispatcher.getAssetProxy.callAsync(AssetProxyId.ERC20);
|
||||
expect(proxyAddress).to.be.equal(erc20Proxy.address);
|
||||
// The following transaction will throw because the currentAddress is no longer constants.NULL_ADDRESS
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(
|
||||
AssetProxyId.ERC20,
|
||||
erc20Proxy.address,
|
||||
constants.NULL_ADDRESS,
|
||||
{ from: owner },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to reset proxy address to NULL', async () => {
|
||||
@@ -218,26 +216,26 @@ describe('AssetProxyDispatcher', () => {
|
||||
|
||||
it('should throw if requesting address is not owner', async () => {
|
||||
const prevProxyAddress = constants.NULL_ADDRESS;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(
|
||||
AssetProxyId.ERC20,
|
||||
erc20Proxy.address,
|
||||
prevProxyAddress,
|
||||
{ from: notOwner },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if attempting to register a proxy to the incorrect id', async () => {
|
||||
const prevProxyAddress = constants.NULL_ADDRESS;
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(
|
||||
AssetProxyId.ERC721,
|
||||
erc20Proxy.address,
|
||||
prevProxyAddress,
|
||||
{ from: owner },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -277,13 +275,15 @@ describe('AssetProxyDispatcher', () => {
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
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(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
AssetProxyId.ERC20,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
@@ -303,19 +303,20 @@ describe('AssetProxyDispatcher', () => {
|
||||
|
||||
it('should throw if dispatching to unregistered proxy', async () => {
|
||||
// Construct metadata for ERC20 proxy
|
||||
const encodedProxyMetadata = assetProxyUtils.encodeERC20ProxyData(zrxToken.address);
|
||||
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);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
assetProxyDispatcher.publicDispatchTransferFrom.sendTransactionAsync(
|
||||
encodedProxyMetadata,
|
||||
encodedAssetDataWithoutProxyId,
|
||||
AssetProxyId.ERC20,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
amount,
|
||||
{ from: owner },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,9 +3,8 @@ import { assetProxyUtils, EIP712Utils, orderHashUtils } from '@0xproject/order-u
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import { TestLibsContract } from '../../src/contract_wrappers/generated/test_libs';
|
||||
import { TestLibsContract } from '../../src/generated_contract_wrappers/test_libs';
|
||||
import { addressUtils } from '../../src/utils/address_utils';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
@@ -39,8 +38,8 @@ describe('Exchange libs', () => {
|
||||
exchangeAddress: libs.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
|
@@ -1,23 +1,18 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, crypto } from '@0xproject/order-utils';
|
||||
import { AssetProxyId, SignedOrder } from '@0xproject/types';
|
||||
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import {
|
||||
CancelContractEventArgs,
|
||||
ExchangeContract,
|
||||
FillContractEventArgs,
|
||||
} from '../../src/contract_wrappers/generated/exchange';
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy';
|
||||
import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
@@ -25,13 +20,7 @@ import { ERC721Wrapper } from '../../src/utils/erc721_wrapper';
|
||||
import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||
import { MatchOrderTester } from '../../src/utils/match_order_tester';
|
||||
import { OrderFactory } from '../../src/utils/order_factory';
|
||||
import {
|
||||
ContractName,
|
||||
ERC20BalancesByOwner,
|
||||
ERC721TokenIdsByOwner,
|
||||
OrderInfo,
|
||||
OrderStatus,
|
||||
} from '../../src/utils/types';
|
||||
import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, OrderStatus } from '../../src/utils/types';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
@@ -64,7 +53,6 @@ describe('matchOrders', () => {
|
||||
|
||||
let erc721LeftMakerAssetIds: BigNumber[];
|
||||
let erc721RightMakerAssetIds: BigNumber[];
|
||||
let erc721TakerAssetIds: BigNumber[];
|
||||
|
||||
let defaultERC20MakerAssetAddress: string;
|
||||
let defaultERC20TakerAssetAddress: string;
|
||||
@@ -103,13 +91,12 @@ describe('matchOrders', () => {
|
||||
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
||||
erc721LeftMakerAssetIds = erc721Balances[makerAddressLeft][erc721Token.address];
|
||||
erc721RightMakerAssetIds = erc721Balances[makerAddressRight][erc721Token.address];
|
||||
erc721TakerAssetIds = erc721Balances[takerAddress][erc721Token.address];
|
||||
// Depoy exchange
|
||||
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
zrxToken.address,
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -135,8 +122,8 @@ describe('matchOrders', () => {
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
exchangeAddress: exchange.address,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
};
|
||||
const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
|
||||
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParams);
|
||||
@@ -161,16 +148,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -195,16 +180,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -240,16 +223,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -274,16 +255,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -308,16 +287,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -347,8 +324,8 @@ describe('matchOrders', () => {
|
||||
// branch in the contract twice for this test.
|
||||
const signedOrderRight2 = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -377,8 +354,6 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
@@ -386,8 +361,8 @@ describe('matchOrders', () => {
|
||||
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -417,8 +392,6 @@ describe('matchOrders', () => {
|
||||
// branch in the contract twice for this test.
|
||||
const signedOrderLeft2 = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
@@ -450,16 +423,14 @@ describe('matchOrders', () => {
|
||||
const feeRecipientAddress = feeRecipientAddressLeft;
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress,
|
||||
@@ -478,16 +449,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -507,16 +476,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -536,16 +503,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -565,16 +530,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -594,16 +557,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: makerAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: makerAddressRight,
|
||||
@@ -622,16 +583,14 @@ describe('matchOrders', () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -639,25 +598,23 @@ describe('matchOrders', () => {
|
||||
// Cancel left order
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress);
|
||||
// Match orders
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('Should throw if right order is not fillable', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -665,31 +622,29 @@ describe('matchOrders', () => {
|
||||
// Cancel right order
|
||||
await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress);
|
||||
// Match orders
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if there is not a positive spread', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
@@ -697,29 +652,27 @@ describe('matchOrders', () => {
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if the left maker asset is not equal to the right taker asset ', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
@@ -727,29 +680,29 @@ describe('matchOrders', () => {
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if the right maker asset is not equal to the left taker asset', async () => {
|
||||
// Create orders to match
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
});
|
||||
// Match orders
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
matchOrderTester.matchOrdersAndVerifyBalancesAsync(
|
||||
signedOrderLeft,
|
||||
signedOrderRight,
|
||||
@@ -757,7 +710,7 @@ describe('matchOrders', () => {
|
||||
erc20BalancesByOwner,
|
||||
erc721TokenIdsByOwner,
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should transfer correct amounts when left order maker asset is an ERC721 token', async () => {
|
||||
@@ -765,16 +718,16 @@ describe('matchOrders', () => {
|
||||
const erc721TokenToTransfer = erc721LeftMakerAssetIds[0];
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
@@ -800,16 +753,16 @@ describe('matchOrders', () => {
|
||||
const erc721TokenToTransfer = erc721RightMakerAssetIds[0];
|
||||
const signedOrderLeft = orderFactoryLeft.newSignedOrder({
|
||||
makerAddress: makerAddressLeft,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
feeRecipientAddress: feeRecipientAddressLeft,
|
||||
});
|
||||
const signedOrderRight = orderFactoryRight.newSignedOrder({
|
||||
makerAddress: makerAddressRight,
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultERC20MakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress),
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
|
||||
feeRecipientAddress: feeRecipientAddressRight,
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, orderHashUtils } from '@0xproject/order-utils';
|
||||
import { SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
import { TestSignatureValidatorContract } from '../../src/contract_wrappers/generated/test_signature_validator';
|
||||
import { TestSignatureValidatorContract } from '../../src/generated_contract_wrappers/test_signature_validator';
|
||||
import { addressUtils } from '../../src/utils/address_utils';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
@@ -43,8 +42,8 @@ describe('MixinSignatureValidator', () => {
|
||||
exchangeAddress: signatureValidator.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(addressUtils.generatePseudoRandomAddress()),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
|
@@ -1,16 +1,15 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { AssetProxyId, Order, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types';
|
||||
import { AssetProxyId, OrderWithoutExchangeAddress, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
||||
import { WhitelistContract } from '../../src/contract_wrappers/generated/whitelist';
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
|
||||
import { WhitelistContract } from '../../src/generated_contract_wrappers/whitelist';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
@@ -18,7 +17,7 @@ import { ExchangeWrapper } from '../../src/utils/exchange_wrapper';
|
||||
import { OrderFactory } from '../../src/utils/order_factory';
|
||||
import { orderUtils } from '../../src/utils/order_utils';
|
||||
import { TransactionFactory } from '../../src/utils/transaction_factory';
|
||||
import { ERC20BalancesByOwner, OrderStatus, SignedTransaction } from '../../src/utils/types';
|
||||
import { ERC20BalancesByOwner, SignedTransaction } from '../../src/utils/types';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
@@ -73,7 +72,7 @@ describe('Exchange transactions', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
zrxToken.address,
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -92,8 +91,8 @@ describe('Exchange transactions', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerTokenAddress),
|
||||
};
|
||||
makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
@@ -126,8 +125,8 @@ describe('Exchange transactions', () => {
|
||||
});
|
||||
|
||||
it('should throw if not called by specified sender', async () => {
|
||||
return expect(exchangeWrapper.executeTransactionAsync(signedTx, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.executeTransactionAsync(signedTx, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -168,8 +167,8 @@ describe('Exchange transactions', () => {
|
||||
|
||||
it('should throw if the a 0x transaction with the same transactionHash has already been executed', async () => {
|
||||
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
|
||||
return expect(exchangeWrapper.executeTransactionAsync(signedTx, senderAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.executeTransactionAsync(signedTx, senderAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -187,15 +186,15 @@ describe('Exchange transactions', () => {
|
||||
});
|
||||
|
||||
it('should throw if not called by specified sender', async () => {
|
||||
return expect(exchangeWrapper.executeTransactionAsync(signedTx, makerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.executeTransactionAsync(signedTx, makerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
it('should cancel the order when signed by maker and called by sender', async () => {
|
||||
await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress);
|
||||
return expect(exchangeWrapper.fillOrderAsync(signedOrder, senderAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrderAsync(signedOrder, senderAddress),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -217,6 +216,7 @@ describe('Exchange transactions', () => {
|
||||
await exchange.setSignatureValidatorApproval.sendTransactionAsync(whitelist.address, isApproved, {
|
||||
from: takerAddress,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
@@ -224,8 +224,8 @@ describe('Exchange transactions', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerTokenAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerTokenAddress),
|
||||
};
|
||||
whitelistOrderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
|
||||
});
|
||||
@@ -239,12 +239,13 @@ describe('Exchange transactions', () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
const salt = generatePseudoRandomSalt();
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
|
||||
orderWithoutExchangeAddress,
|
||||
takerAssetFillAmount,
|
||||
@@ -252,19 +253,20 @@ describe('Exchange transactions', () => {
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should revert if taker has not been whitelisted', async () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
const salt = generatePseudoRandomSalt();
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
whitelist.fillOrderIfWhitelisted.sendTransactionAsync(
|
||||
orderWithoutExchangeAddress,
|
||||
takerAssetFillAmount,
|
||||
@@ -272,17 +274,19 @@ describe('Exchange transactions', () => {
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should fill the order if maker and taker have been whitelisted', async () => {
|
||||
const isApproved = true;
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(makerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await whitelist.updateWhitelistStatus.sendTransactionAsync(takerAddress, isApproved, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
orderWithoutExchangeAddress = orderUtils.getOrderWithoutExchangeAddress(signedOrder);
|
||||
@@ -296,6 +300,7 @@ describe('Exchange transactions', () => {
|
||||
signedOrder.signature,
|
||||
{ from: takerAddress },
|
||||
),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId, SignedOrder } from '@0xproject/types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
@@ -6,15 +6,14 @@ import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/contract_wrappers/generated/e_r_c721_proxy';
|
||||
import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
||||
import { TokenRegistryContract } from '../../src/contract_wrappers/generated/token_registry';
|
||||
import { DummyERC20TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { DummyERC721TokenContract } from '../../src/generated_contract_wrappers/dummy_e_r_c721_token';
|
||||
import { ERC20ProxyContract } from '../../src/generated_contract_wrappers/e_r_c20_proxy';
|
||||
import { ERC721ProxyContract } from '../../src/generated_contract_wrappers/e_r_c721_proxy';
|
||||
import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { ERC20Wrapper } from '../../src/utils/erc20_wrapper';
|
||||
@@ -82,7 +81,7 @@ describe('Exchange wrappers', () => {
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
zrxToken.address,
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner);
|
||||
@@ -109,8 +108,8 @@ describe('Exchange wrappers', () => {
|
||||
exchangeAddress: exchange.address,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerAssetAddress),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
@@ -172,8 +171,8 @@ describe('Exchange wrappers', () => {
|
||||
expirationTimeSeconds: new BigNumber(Math.floor((Date.now() - 10000) / 1000)),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -184,8 +183,8 @@ describe('Exchange wrappers', () => {
|
||||
takerAssetFillAmount: signedOrder.takerAssetAmount.div(2),
|
||||
});
|
||||
|
||||
return expect(exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -197,12 +196,16 @@ describe('Exchange wrappers', () => {
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18),
|
||||
});
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2);
|
||||
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, 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: 250000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
|
||||
const makerAssetFilledAmount = takerAssetFillAmount
|
||||
.times(signedOrder.makerAssetAmount)
|
||||
.dividedToIntegerBy(signedOrder.takerAssetAmount);
|
||||
@@ -212,6 +215,7 @@ describe('Exchange wrappers', () => {
|
||||
const takerFee = signedOrder.takerFee
|
||||
.times(makerAssetFilledAmount)
|
||||
.dividedToIntegerBy(signedOrder.makerAssetAmount);
|
||||
|
||||
expect(newBalances[makerAddress][defaultMakerAssetAddress]).to.be.bignumber.equal(
|
||||
erc20Balances[makerAddress][defaultMakerAssetAddress].minus(makerAssetFilledAmount),
|
||||
);
|
||||
@@ -300,7 +304,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: makerZRXBalance,
|
||||
makerFee: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -312,7 +316,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(makerZRXAllowance),
|
||||
makerFee: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -324,7 +328,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: takerZRXBalance,
|
||||
takerFee: new BigNumber(1),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -336,7 +340,7 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
takerAssetAmount: new BigNumber(takerZRXAllowance),
|
||||
takerFee: new BigNumber(1),
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
});
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -350,8 +354,8 @@ describe('Exchange wrappers', () => {
|
||||
const signedOrder = orderFactory.newSignedOrder({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
makerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721ProxyData(erc721Token.address, takerAssetId),
|
||||
makerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerAssetData: assetProxyUtils.encodeERC721AssetData(erc721Token.address, takerAssetId),
|
||||
});
|
||||
// Verify pre-conditions
|
||||
const initialOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
@@ -360,7 +364,13 @@ describe('Exchange wrappers', () => {
|
||||
expect(initialOwnerTakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
// Call Exchange
|
||||
const takerAssetFillAmount = signedOrder.takerAssetAmount;
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress, { takerAssetFillAmount });
|
||||
await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, 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: 270000,
|
||||
});
|
||||
// Verify post-conditions
|
||||
const newOwnerMakerAsset = await erc721Token.ownerOf.callAsync(makerAssetId);
|
||||
expect(newOwnerMakerAsset).to.be.bignumber.equal(takerAddress);
|
||||
@@ -485,11 +495,11 @@ describe('Exchange wrappers', () => {
|
||||
|
||||
await exchangeWrapper.fillOrKillOrderAsync(signedOrders[0], takerAddress);
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.batchFillOrKillOrdersAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmounts,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -535,6 +545,10 @@ describe('Exchange wrappers', () => {
|
||||
|
||||
await exchangeWrapper.batchFillOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmounts,
|
||||
// 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();
|
||||
@@ -591,6 +605,10 @@ describe('Exchange wrappers', () => {
|
||||
const newOrders = [invalidOrder, ...validOrders];
|
||||
await exchangeWrapper.batchFillOrdersNoThrowAsync(newOrders, takerAddress, {
|
||||
takerAssetFillAmounts,
|
||||
// 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: 450000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -674,16 +692,16 @@ describe('Exchange wrappers', () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.marketSellOrdersAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -694,6 +712,10 @@ describe('Exchange wrappers', () => {
|
||||
);
|
||||
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: 6000000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
@@ -753,26 +775,59 @@ describe('Exchange wrappers', () => {
|
||||
});
|
||||
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,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
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({
|
||||
takerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
|
||||
return expect(
|
||||
exchangeWrapper.marketSellOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
takerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
|
||||
orderFactory.newSignedOrder({
|
||||
takerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
];
|
||||
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,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances).to.be.deep.equal(erc20Balances);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -852,16 +907,16 @@ describe('Exchange wrappers', () => {
|
||||
signedOrders = [
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
];
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
exchangeWrapper.marketBuyOrdersAsync(signedOrders, takerAddress, {
|
||||
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -872,6 +927,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();
|
||||
@@ -904,8 +963,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
|
||||
@@ -929,28 +988,62 @@ 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.
|
||||
gas: 600000,
|
||||
});
|
||||
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
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({
|
||||
makerAssetData: assetProxyUtils.encodeERC20ProxyData(zrxToken.address),
|
||||
}),
|
||||
orderFactory.newSignedOrder(),
|
||||
orderFactory.newSignedOrder({
|
||||
makerAssetData: assetProxyUtils.encodeERC20AssetData(zrxToken.address),
|
||||
}),
|
||||
];
|
||||
|
||||
return expect(
|
||||
exchangeWrapper.marketBuyOrdersNoThrowAsync(signedOrders, takerAddress, {
|
||||
makerAssetFillAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1000), 18),
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,10 +1,15 @@
|
||||
import { env, EnvVars } from '@0xproject/dev-utils';
|
||||
|
||||
import { coverage } from '../src/utils/coverage';
|
||||
import { profiler } from '../src/utils/profiler';
|
||||
|
||||
after('generate coverage report', async () => {
|
||||
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
await coverageSubprovider.writeCoverageAsync();
|
||||
}
|
||||
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
await profilerSubprovider.writeProfilerOutputAsync();
|
||||
}
|
||||
});
|
||||
|
@@ -1,15 +1,14 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { AssetProxyId } from '@0xproject/types';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { assetProxyUtils, generatePseudoRandomSalt } from '@0xproject/order-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import BN = require('bn.js');
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as Web3 from 'web3';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { TestLibBytesContract } from '../../src/contract_wrappers/generated/test_lib_bytes';
|
||||
import { TestLibBytesContract } from '../../src/generated_contract_wrappers/test_lib_bytes';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { expectRevertOrOtherErrorAsync } from '../../src/utils/assertions';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { constants } from '../../src/utils/constants';
|
||||
import { provider, txDefaults, web3Wrapper } from '../../src/utils/web3_wrapper';
|
||||
@@ -19,7 +18,6 @@ const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
describe('LibBytes', () => {
|
||||
let owner: string;
|
||||
let libBytes: TestLibBytesContract;
|
||||
const byteArrayShorterThan32Bytes = '0x012345';
|
||||
const byteArrayShorterThan20Bytes = byteArrayShorterThan32Bytes;
|
||||
@@ -30,8 +28,20 @@ describe('LibBytes', () => {
|
||||
const byteArrayLongerThan32BytesLastBytesSwapped =
|
||||
'0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abefcd';
|
||||
let testAddress: string;
|
||||
let testAddressB: string;
|
||||
const testBytes32 = '0x102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f01020';
|
||||
const testBytes32B = '0x534877abd8443578526845cdfef020047528759477fedef87346527659aced32';
|
||||
const testUint256 = new BigNumber(testBytes32, 16);
|
||||
const testUint256B = new BigNumber(testBytes32B, 16);
|
||||
let shortData: string;
|
||||
let shortTestBytes: string;
|
||||
let shortTestBytesAsBuffer: Buffer;
|
||||
let wordOfData: string;
|
||||
let wordOfTestBytes: string;
|
||||
let wordOfTestBytesAsBuffer: Buffer;
|
||||
let longData: string;
|
||||
let longTestBytes: string;
|
||||
let longTestBytesAsBuffer: Buffer;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -42,8 +52,8 @@ describe('LibBytes', () => {
|
||||
before(async () => {
|
||||
// Setup accounts & addresses
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
owner = accounts[0];
|
||||
testAddress = accounts[1];
|
||||
testAddressB = accounts[2];
|
||||
// Deploy LibBytes
|
||||
libBytes = await TestLibBytesContract.deployFrom0xArtifactAsync(artifacts.TestLibBytes, provider, txDefaults);
|
||||
// Verify lengths of test data
|
||||
@@ -53,6 +63,26 @@ describe('LibBytes', () => {
|
||||
expect(byteArrayLongerThan32BytesLength).to.be.greaterThan(32);
|
||||
const testBytes32Length = ethUtil.toBuffer(testBytes32).byteLength;
|
||||
expect(testBytes32Length).to.be.equal(32);
|
||||
// Create short test bytes
|
||||
shortData = '0xffffaa';
|
||||
const encodedShortData = ethUtil.toBuffer(shortData);
|
||||
const shortDataLength = new BigNumber(encodedShortData.byteLength);
|
||||
const encodedShortDataLength = assetProxyUtils.encodeUint256(shortDataLength);
|
||||
shortTestBytesAsBuffer = Buffer.concat([encodedShortDataLength, encodedShortData]);
|
||||
shortTestBytes = ethUtil.bufferToHex(shortTestBytesAsBuffer);
|
||||
// Create test bytes one word in length
|
||||
wordOfData = ethUtil.bufferToHex(assetProxyUtils.encodeUint256(generatePseudoRandomSalt()));
|
||||
const encodedWordOfData = ethUtil.toBuffer(wordOfData);
|
||||
const wordOfDataLength = new BigNumber(encodedWordOfData.byteLength);
|
||||
const encodedWordOfDataLength = assetProxyUtils.encodeUint256(wordOfDataLength);
|
||||
wordOfTestBytesAsBuffer = Buffer.concat([encodedWordOfDataLength, encodedWordOfData]);
|
||||
wordOfTestBytes = ethUtil.bufferToHex(wordOfTestBytesAsBuffer);
|
||||
// Create long test bytes (combines short test bytes with word of test bytes)
|
||||
longData = ethUtil.bufferToHex(Buffer.concat([encodedShortData, encodedWordOfData]));
|
||||
const longDataLength = new BigNumber(encodedShortData.byteLength + encodedWordOfData.byteLength);
|
||||
const encodedLongDataLength = assetProxyUtils.encodeUint256(longDataLength);
|
||||
longTestBytesAsBuffer = Buffer.concat([encodedLongDataLength, encodedShortData, encodedWordOfData]);
|
||||
longTestBytes = ethUtil.bufferToHex(longTestBytesAsBuffer);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@@ -61,13 +91,15 @@ describe('LibBytes', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe('popByte', () => {
|
||||
describe('popLastByte', () => {
|
||||
it('should revert if length is 0', async () => {
|
||||
return expect(libBytes.publicPopByte.callAsync(constants.NULL_BYTES)).to.be.rejectedWith(constants.REVERT);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicPopLastByte.callAsync(constants.NULL_BYTES),
|
||||
constants.LIB_BYTES_GREATER_THAN_ZERO_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should pop the last byte from the input and return it', async () => {
|
||||
const [newBytes, poppedByte] = await libBytes.publicPopByte.callAsync(byteArrayLongerThan32Bytes);
|
||||
const [newBytes, poppedByte] = await libBytes.publicPopLastByte.callAsync(byteArrayLongerThan32Bytes);
|
||||
const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -2);
|
||||
const expectedPoppedByte = `0x${byteArrayLongerThan32Bytes.slice(-2)}`;
|
||||
expect(newBytes).to.equal(expectedNewBytes);
|
||||
@@ -75,15 +107,15 @@ describe('LibBytes', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('popAddress', () => {
|
||||
describe('popLast20Bytes', () => {
|
||||
it('should revert if length is less than 20', async () => {
|
||||
return expect(libBytes.publicPopAddress.callAsync(byteArrayShorterThan20Bytes)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicPopLast20Bytes.callAsync(byteArrayShorterThan20Bytes),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should pop the last 20 bytes from the input and return it', async () => {
|
||||
const [newBytes, poppedAddress] = await libBytes.publicPopAddress.callAsync(byteArrayLongerThan32Bytes);
|
||||
const [newBytes, poppedAddress] = await libBytes.publicPopLast20Bytes.callAsync(byteArrayLongerThan32Bytes);
|
||||
const expectedNewBytes = byteArrayLongerThan32Bytes.slice(0, -40);
|
||||
const expectedPoppedAddress = `0x${byteArrayLongerThan32Bytes.slice(-40)}`;
|
||||
expect(newBytes).to.equal(expectedNewBytes);
|
||||
@@ -99,7 +131,6 @@ describe('LibBytes', () => {
|
||||
);
|
||||
return expect(areBytesEqual).to.be.true();
|
||||
});
|
||||
|
||||
it('should return true if byte arrays are equal (both arrays > 32 bytes)', async () => {
|
||||
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
|
||||
byteArrayLongerThan32Bytes,
|
||||
@@ -107,7 +138,6 @@ describe('LibBytes', () => {
|
||||
);
|
||||
return expect(areBytesEqual).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false if byte arrays are not equal (first array < 32 bytes, second array > 32 bytes)', async () => {
|
||||
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
|
||||
byteArrayShorterThan32Bytes,
|
||||
@@ -115,7 +145,6 @@ describe('LibBytes', () => {
|
||||
);
|
||||
return expect(areBytesEqual).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false if byte arrays are not equal (first array > 32 bytes, second array < 32 bytes)', async () => {
|
||||
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
|
||||
byteArrayLongerThan32Bytes,
|
||||
@@ -123,7 +152,6 @@ describe('LibBytes', () => {
|
||||
);
|
||||
return expect(areBytesEqual).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false if byte arrays are not equal (same length, but a byte in first word differs)', async () => {
|
||||
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
|
||||
byteArrayLongerThan32BytesFirstBytesSwapped,
|
||||
@@ -131,7 +159,6 @@ describe('LibBytes', () => {
|
||||
);
|
||||
return expect(areBytesEqual).to.be.false();
|
||||
});
|
||||
|
||||
it('should return false if byte arrays are not equal (same length, but a byte in last word differs)', async () => {
|
||||
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
|
||||
byteArrayLongerThan32BytesLastBytesSwapped,
|
||||
@@ -141,15 +168,50 @@ describe('LibBytes', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('deepCopyBytes', () => {
|
||||
it('should revert if dest is shorter than source', async () => {
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicDeepCopyBytes.callAsync(byteArrayShorterThan32Bytes, byteArrayLongerThan32Bytes),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should overwrite dest with source if source and dest have equal length', async () => {
|
||||
const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length - 2)}`;
|
||||
const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
|
||||
zeroedByteArrayLongerThan32Bytes,
|
||||
byteArrayLongerThan32Bytes,
|
||||
);
|
||||
return expect(zeroedBytesAfterCopy).to.be.equal(byteArrayLongerThan32Bytes);
|
||||
});
|
||||
it('should overwrite the leftmost len(source) bytes of dest if dest is larger than source', async () => {
|
||||
const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`;
|
||||
const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
|
||||
zeroedByteArrayLongerThan32Bytes,
|
||||
byteArrayLongerThan32Bytes,
|
||||
);
|
||||
const copiedBytes = zeroedBytesAfterCopy.slice(0, byteArrayLongerThan32Bytes.length);
|
||||
return expect(copiedBytes).to.be.equal(byteArrayLongerThan32Bytes);
|
||||
});
|
||||
it('should not overwrite the rightmost bytes of dest if dest is larger than source', async () => {
|
||||
const zeroedByteArrayLongerThan32Bytes = `0x${_.repeat('0', byteArrayLongerThan32Bytes.length * 2)}`;
|
||||
const zeroedBytesAfterCopy = await libBytes.publicDeepCopyBytes.callAsync(
|
||||
zeroedByteArrayLongerThan32Bytes,
|
||||
byteArrayLongerThan32Bytes,
|
||||
);
|
||||
const expectedNotCopiedBytes = zeroedByteArrayLongerThan32Bytes.slice(byteArrayLongerThan32Bytes.length);
|
||||
const notCopiedBytes = zeroedBytesAfterCopy.slice(byteArrayLongerThan32Bytes.length);
|
||||
return expect(notCopiedBytes).to.be.equal(expectedNotCopiedBytes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readAddress', () => {
|
||||
it('should successfully read address when the address takes up the whole array)', async () => {
|
||||
it('should successfully read address when the address takes up the whole array', async () => {
|
||||
const byteArray = ethUtil.addHexPrefix(testAddress);
|
||||
const testAddressOffset = new BigNumber(0);
|
||||
const address = await libBytes.publicReadAddress.callAsync(byteArray, testAddressOffset);
|
||||
return expect(address).to.be.equal(testAddress);
|
||||
});
|
||||
|
||||
it('should successfully read address when it is offset in the array)', async () => {
|
||||
it('should successfully read address when it is offset in the array', async () => {
|
||||
const addressByteArrayBuffer = ethUtil.toBuffer(testAddress);
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
|
||||
@@ -158,80 +220,145 @@ describe('LibBytes', () => {
|
||||
const address = await libBytes.publicReadAddress.callAsync(combinedByteArray, testAddressOffset);
|
||||
return expect(address).to.be.equal(testAddress);
|
||||
});
|
||||
|
||||
it('should fail if the byte array is too short to hold an address)', async () => {
|
||||
it('should fail if the byte array is too short to hold an address', async () => {
|
||||
const shortByteArray = '0xabcdef';
|
||||
const offset = new BigNumber(0);
|
||||
return expect(libBytes.publicReadAddress.callAsync(shortByteArray, offset)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadAddress.callAsync(shortByteArray, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold an address)', async () => {
|
||||
const byteArray = ethUtil.addHexPrefix(testAddress);
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
|
||||
const byteArray = testAddress;
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
|
||||
return expect(libBytes.publicReadAddress.callAsync(byteArray, badOffset)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadAddress.callAsync(byteArray, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/// @TODO Implement test cases for writeAddress. Test template below.
|
||||
/// Currently, the generated contract wrappers do not support this library's write methods.
|
||||
/*
|
||||
describe('writeAddress', () => {
|
||||
it('should successfully write address when the address takes up the whole array)', async () => {});
|
||||
it('should successfully write address when it is offset in the array)', async () => {});
|
||||
it('should fail if the byte array is too short to hold an address)', async () => {});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold an address)', async () => {});
|
||||
it('should successfully write address when the address takes up the whole array', async () => {
|
||||
const byteArray = testAddress;
|
||||
const testAddressOffset = new BigNumber(0);
|
||||
const newByteArray = await libBytes.publicWriteAddress.callAsync(
|
||||
byteArray,
|
||||
testAddressOffset,
|
||||
testAddressB,
|
||||
);
|
||||
return expect(newByteArray).to.be.equal(testAddressB);
|
||||
});
|
||||
it('should successfully write address when it is offset in the array', async () => {
|
||||
const addressByteArrayBuffer = ethUtil.toBuffer(testAddress);
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, addressByteArrayBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const newByteArray = await libBytes.publicWriteAddress.callAsync(
|
||||
combinedByteArray,
|
||||
testAddressOffset,
|
||||
testAddressB,
|
||||
);
|
||||
const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
|
||||
const addressFromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
|
||||
const addressFromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(addressFromOffsetBuffer));
|
||||
return expect(addressFromOffset).to.be.equal(testAddressB);
|
||||
});
|
||||
it('should fail if the byte array is too short to hold an address', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteAddress.callAsync(byteArrayShorterThan20Bytes, offset, testAddress),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold an address', async () => {
|
||||
const byteArray = byteArrayLongerThan32Bytes;
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteAddress.callAsync(byteArray, badOffset, testAddress),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
describe('readBytes32', () => {
|
||||
it('should successfully read bytes32 when the bytes32 takes up the whole array)', async () => {
|
||||
it('should successfully read bytes32 when the bytes32 takes up the whole array', async () => {
|
||||
const testBytes32Offset = new BigNumber(0);
|
||||
const bytes32 = await libBytes.publicReadBytes32.callAsync(testBytes32, testBytes32Offset);
|
||||
return expect(bytes32).to.be.equal(testBytes32);
|
||||
});
|
||||
|
||||
it('should successfully read bytes32 when it is offset in the array)', async () => {
|
||||
const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testAddressOffset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes32 = await libBytes.publicReadBytes32.callAsync(combinedByteArray, testAddressOffset);
|
||||
const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes32 = await libBytes.publicReadBytes32.callAsync(combinedByteArray, testBytes32Offset);
|
||||
return expect(bytes32).to.be.equal(testBytes32);
|
||||
});
|
||||
|
||||
it('should fail if the byte array is too short to hold a bytes32)', async () => {
|
||||
it('should fail if the byte array is too short to hold a bytes32', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expect(libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes32.callAsync(byteArrayShorterThan32Bytes, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32)', async () => {
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
|
||||
return expect(libBytes.publicReadBytes32.callAsync(testBytes32, badOffset)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes32.callAsync(testBytes32, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/// @TODO Implement test cases for writeBytes32. Test template below.
|
||||
/// Currently, the generated contract wrappers do not support this library's write methods.
|
||||
/*
|
||||
describe('writeBytes32', () => {
|
||||
it('should successfully write bytes32 when the address takes up the whole array)', async () => {});
|
||||
it('should successfully write bytes32 when it is offset in the array)', async () => {});
|
||||
it('should fail if the byte array is too short to hold a bytes32)', async () => {});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32)', async () => {});
|
||||
it('should successfully write bytes32 when the address takes up the whole array', async () => {
|
||||
const byteArray = testBytes32;
|
||||
const testBytes32Offset = new BigNumber(0);
|
||||
const newByteArray = await libBytes.publicWriteBytes32.callAsync(
|
||||
byteArray,
|
||||
testBytes32Offset,
|
||||
testBytes32B,
|
||||
);
|
||||
return expect(newByteArray).to.be.equal(testBytes32B);
|
||||
});
|
||||
it('should successfully write bytes32 when it is offset in the array', async () => {
|
||||
const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testBytes32Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const newByteArray = await libBytes.publicWriteBytes32.callAsync(
|
||||
combinedByteArray,
|
||||
testBytes32Offset,
|
||||
testBytes32B,
|
||||
);
|
||||
const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
|
||||
const bytes32FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
|
||||
const bytes32FromOffset = ethUtil.addHexPrefix(ethUtil.bufferToHex(bytes32FromOffsetBuffer));
|
||||
return expect(bytes32FromOffset).to.be.equal(testBytes32B);
|
||||
});
|
||||
it('should fail if the byte array is too short to hold a bytes32', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteBytes32.callAsync(byteArrayShorterThan32Bytes, offset, testBytes32),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a bytes32', async () => {
|
||||
const byteArray = byteArrayLongerThan32Bytes;
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteBytes32.callAsync(byteArray, badOffset, testBytes32),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
describe('readUint256', () => {
|
||||
it('should successfully read uint256 when the uint256 takes up the whole array)', async () => {
|
||||
it('should successfully read uint256 when the uint256 takes up the whole array', async () => {
|
||||
const formattedTestUint256 = new BN(testUint256.toString(10));
|
||||
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
|
||||
const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
|
||||
@@ -239,8 +366,7 @@ describe('LibBytes', () => {
|
||||
const uint256 = await libBytes.publicReadUint256.callAsync(byteArray, testUint256Offset);
|
||||
return expect(uint256).to.bignumber.equal(testUint256);
|
||||
});
|
||||
|
||||
it('should successfully read uint256 when it is offset in the array)', async () => {
|
||||
it('should successfully read uint256 when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const formattedTestUint256 = new BN(testUint256.toString(10));
|
||||
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
|
||||
@@ -250,41 +376,80 @@ describe('LibBytes', () => {
|
||||
const uint256 = await libBytes.publicReadUint256.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(uint256).to.bignumber.equal(testUint256);
|
||||
});
|
||||
|
||||
it('should fail if the byte array is too short to hold a uint256)', async () => {
|
||||
it('should fail if the byte array is too short to hold a uint256', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expect(libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadUint256.callAsync(byteArrayShorterThan32Bytes, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a uint256)', async () => {
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
|
||||
const formattedTestUint256 = new BN(testUint256.toString(10));
|
||||
const testUint256AsBuffer = ethUtil.toBuffer(formattedTestUint256);
|
||||
const byteArray = ethUtil.bufferToHex(testUint256AsBuffer);
|
||||
const badOffset = new BigNumber(testUint256AsBuffer.byteLength);
|
||||
return expect(libBytes.publicReadUint256.callAsync(byteArray, badOffset)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadUint256.callAsync(byteArray, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/// @TODO Implement test cases for writeUint256. Test template below.
|
||||
/// Currently, the generated contract wrappers do not support this library's write methods.
|
||||
/*
|
||||
describe('writeUint256', () => {
|
||||
it('should successfully write uint256 when the address takes up the whole array)', async () => {});
|
||||
it('should successfully write uint256 when it is offset in the array)', async () => {});
|
||||
it('should fail if the byte array is too short to hold a uint256)', async () => {});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a uint256)', async () => {});
|
||||
it('should successfully write uint256 when the address takes up the whole array', async () => {
|
||||
const byteArray = testBytes32;
|
||||
const testUint256Offset = new BigNumber(0);
|
||||
const newByteArray = await libBytes.publicWriteUint256.callAsync(
|
||||
byteArray,
|
||||
testUint256Offset,
|
||||
testUint256B,
|
||||
);
|
||||
const newByteArrayAsUint256 = new BigNumber(newByteArray, 16);
|
||||
return expect(newByteArrayAsUint256).to.be.bignumber.equal(testUint256B);
|
||||
});
|
||||
it('should successfully write uint256 when it is offset in the array', async () => {
|
||||
const bytes32ByteArrayBuffer = ethUtil.toBuffer(testBytes32);
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, bytes32ByteArrayBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const newByteArray = await libBytes.publicWriteUint256.callAsync(
|
||||
combinedByteArray,
|
||||
testUint256Offset,
|
||||
testUint256B,
|
||||
);
|
||||
const newByteArrayBuffer = ethUtil.toBuffer(newByteArray);
|
||||
const uint256FromOffsetBuffer = newByteArrayBuffer.slice(prefixByteArrayBuffer.byteLength);
|
||||
const uint256FromOffset = new BigNumber(
|
||||
ethUtil.addHexPrefix(ethUtil.bufferToHex(uint256FromOffsetBuffer)),
|
||||
16,
|
||||
);
|
||||
return expect(uint256FromOffset).to.be.bignumber.equal(testUint256B);
|
||||
});
|
||||
it('should fail if the byte array is too short to hold a uint256', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteUint256.callAsync(byteArrayShorterThan32Bytes, offset, testUint256),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold a uint256', async () => {
|
||||
const byteArray = byteArrayLongerThan32Bytes;
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArray).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteUint256.callAsync(byteArray, badOffset, testUint256),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
describe('readFirst4', () => {
|
||||
// AssertionError: expected promise to be rejected with an error including 'revert' but it was fulfilled with '0x08c379a0'
|
||||
it('should revert if byte array has a length < 4', async () => {
|
||||
const byteArrayLessThan4Bytes = '0x010101';
|
||||
return expect(libBytes.publicReadFirst4.callAsync(byteArrayLessThan4Bytes)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadFirst4.callAsync(byteArrayLessThan4Bytes),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should return the first 4 bytes of a byte array of arbitrary length', async () => {
|
||||
@@ -293,4 +458,164 @@ describe('LibBytes', () => {
|
||||
expect(first4Bytes).to.equal(expectedFirst4Bytes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readBytes', () => {
|
||||
it('should successfully read short, nested array of bytes when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(shortTestBytes, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(shortData);
|
||||
});
|
||||
it('should successfully read short, nested array of bytes when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, shortTestBytesAsBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(bytes).to.be.equal(shortData);
|
||||
});
|
||||
it('should successfully read a nested array of bytes - one word in length - when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(wordOfTestBytes, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(wordOfData);
|
||||
});
|
||||
it('should successfully read a nested array of bytes - one word in length - when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, wordOfTestBytesAsBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(bytes).to.be.equal(wordOfData);
|
||||
});
|
||||
it('should successfully read long, nested array of bytes when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(longTestBytes, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(longData);
|
||||
});
|
||||
it('should successfully read long, nested array of bytes when it is offset in the array', async () => {
|
||||
const prefixByteArrayBuffer = ethUtil.toBuffer('0xabcdef');
|
||||
const combinedByteArrayBuffer = Buffer.concat([prefixByteArrayBuffer, longTestBytesAsBuffer]);
|
||||
const combinedByteArray = ethUtil.bufferToHex(combinedByteArrayBuffer);
|
||||
const testUint256Offset = new BigNumber(prefixByteArrayBuffer.byteLength);
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(combinedByteArray, testUint256Offset);
|
||||
return expect(bytes).to.be.equal(longData);
|
||||
});
|
||||
it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
|
||||
// The length of the nested array is 32 bytes. By storing less than 32 bytes, a length cannot be read.
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(byteArrayShorterThan32Bytes, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if we store a nested byte array length, without a nested byte array', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(testBytes32, offset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array', async () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(byteArrayShorterThan32Bytes, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold the nested byte array', async () => {
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(testBytes32).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicReadBytes.callAsync(testBytes32, badOffset),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeBytes', () => {
|
||||
it('should successfully write short, nested array of bytes when it takes up the whole array)', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
|
||||
const bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, testBytesOffset, shortData);
|
||||
const bytesRead = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytesRead).to.be.equal(shortData);
|
||||
});
|
||||
it('should successfully write short, nested array of bytes when it is offset in the array', async () => {
|
||||
// Write a prefix to the array
|
||||
const prefixData = '0xabcdef';
|
||||
const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
|
||||
const prefixOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(
|
||||
new Buffer(prefixDataAsBuffer.byteLength + shortTestBytesAsBuffer.byteLength),
|
||||
);
|
||||
let bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, prefixOffset, prefixData);
|
||||
// Write data after prefix
|
||||
const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
|
||||
bytesWritten = await libBytes.publicWriteBytes.callAsync(bytesWritten, testBytesOffset, shortData);
|
||||
// Read data after prefix and validate
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(shortData);
|
||||
});
|
||||
it('should successfully write a nested array of bytes - one word in length - when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(wordOfTestBytesAsBuffer.byteLength));
|
||||
const bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, testBytesOffset, wordOfData);
|
||||
const bytesRead = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytesRead).to.be.equal(wordOfData);
|
||||
});
|
||||
it('should successfully write a nested array of bytes - one word in length - when it is offset in the array', async () => {
|
||||
// Write a prefix to the array
|
||||
const prefixData = '0xabcdef';
|
||||
const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
|
||||
const prefixOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(
|
||||
new Buffer(prefixDataAsBuffer.byteLength + wordOfTestBytesAsBuffer.byteLength),
|
||||
);
|
||||
let bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, prefixOffset, prefixData);
|
||||
// Write data after prefix
|
||||
const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
|
||||
bytesWritten = await libBytes.publicWriteBytes.callAsync(bytesWritten, testBytesOffset, wordOfData);
|
||||
// Read data after prefix and validate
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(wordOfData);
|
||||
});
|
||||
it('should successfully write a long, nested bytes when it takes up the whole array', async () => {
|
||||
const testBytesOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(longTestBytesAsBuffer.byteLength));
|
||||
const bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, testBytesOffset, longData);
|
||||
const bytesRead = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytesRead).to.be.equal(longData);
|
||||
});
|
||||
it('should successfully write long, nested array of bytes when it is offset in the array', async () => {
|
||||
// Write a prefix to the array
|
||||
const prefixData = '0xabcdef';
|
||||
const prefixDataAsBuffer = ethUtil.toBuffer(prefixData);
|
||||
const prefixOffset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(
|
||||
new Buffer(prefixDataAsBuffer.byteLength + longTestBytesAsBuffer.byteLength),
|
||||
);
|
||||
let bytesWritten = await libBytes.publicWriteBytes.callAsync(emptyByteArray, prefixOffset, prefixData);
|
||||
// Write data after prefix
|
||||
const testBytesOffset = new BigNumber(prefixDataAsBuffer.byteLength);
|
||||
bytesWritten = await libBytes.publicWriteBytes.callAsync(bytesWritten, testBytesOffset, longData);
|
||||
// Read data after prefix and validate
|
||||
const bytes = await libBytes.publicReadBytes.callAsync(bytesWritten, testBytesOffset);
|
||||
return expect(bytes).to.be.equal(longData);
|
||||
});
|
||||
it('should fail if the byte array is too short to hold the length of a nested byte array', async () => {
|
||||
const offset = new BigNumber(0);
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(1));
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteBytes.callAsync(emptyByteArray, offset, longData),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
it('should fail if the length between the offset and end of the byte array is too short to hold the length of a nested byte array)', async () => {
|
||||
const emptyByteArray = ethUtil.bufferToHex(new Buffer(shortTestBytesAsBuffer.byteLength));
|
||||
const badOffset = new BigNumber(ethUtil.toBuffer(shortTestBytesAsBuffer).byteLength);
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
libBytes.publicWriteBytes.callAsync(emptyByteArray, badOffset, shortData),
|
||||
constants.LIB_BYTES_GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable:max-file-line-count
|
||||
|
190
packages/contracts/test/libraries/lib_mem.ts
Normal file
190
packages/contracts/test/libraries/lib_mem.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { TestLibMemContract } from '../../src/generated_contract_wrappers/test_lib_mem';
|
||||
import { artifacts } from '../../src/utils/artifacts';
|
||||
import { chaiSetup } from '../../src/utils/chai_setup';
|
||||
import { provider, txDefaults } from '../../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
// BUG: Ideally we would use Buffer.from(memory).toString('hex')
|
||||
// https://github.com/Microsoft/TypeScript/issues/23155
|
||||
const toHex = (buf: Uint8Array): string => buf.reduce((a, v) => a + ('00' + v.toString(16)).slice(-2), '0x');
|
||||
|
||||
const fromHex = (str: string): Uint8Array => Uint8Array.from(Buffer.from(str.slice(2), 'hex'));
|
||||
|
||||
describe('LibMem', () => {
|
||||
let testLibMem: TestLibMemContract;
|
||||
|
||||
before(async () => {
|
||||
// Deploy TestLibMem
|
||||
testLibMem = await TestLibMemContract.deployFrom0xArtifactAsync(artifacts.TestLibMem, provider, txDefaults);
|
||||
});
|
||||
|
||||
describe('memCopy', () => {
|
||||
// Create memory 0x000102...FF
|
||||
const memSize = 256;
|
||||
const memory = new Uint8Array(memSize).map((_, i) => i);
|
||||
const memHex = toHex(memory);
|
||||
|
||||
// Reference implementation to test against
|
||||
const refMemcpy = (_mem: Uint8Array, dest: number, source: number, length: number): Uint8Array =>
|
||||
Uint8Array.from(memory).copyWithin(dest, source, source + length);
|
||||
|
||||
// Test vectors: destination, source, length, job description
|
||||
type Tests = Array<[number, number, number, string]>;
|
||||
|
||||
const test = (tests: Tests) =>
|
||||
tests.forEach(([dest, source, length, job]) =>
|
||||
it(job, async () => {
|
||||
const expected = refMemcpy(memory, dest, source, length);
|
||||
const resultStr = await testLibMem.testMemcpy.callAsync(
|
||||
memHex,
|
||||
new BigNumber(dest),
|
||||
new BigNumber(source),
|
||||
new BigNumber(length),
|
||||
);
|
||||
const result = fromHex(resultStr);
|
||||
expect(result).to.deep.equal(expected);
|
||||
}),
|
||||
);
|
||||
|
||||
test([[0, 0, 0, 'copies zero bytes with overlap']]);
|
||||
|
||||
describe('copies forward', () =>
|
||||
test([
|
||||
[128, 0, 0, 'zero bytes'],
|
||||
[128, 0, 1, 'one byte'],
|
||||
[128, 0, 11, 'eleven bytes'],
|
||||
[128, 0, 31, 'thirty-one bytes'],
|
||||
[128, 0, 32, 'one word'],
|
||||
[128, 0, 64, 'two words'],
|
||||
[128, 0, 96, 'three words'],
|
||||
[128, 0, 33, 'one word and one byte'],
|
||||
[128, 0, 72, 'two words and eight bytes'],
|
||||
[128, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward within one word', () =>
|
||||
test([
|
||||
[16, 0, 0, 'zero bytes'],
|
||||
[16, 0, 1, 'one byte'],
|
||||
[16, 0, 11, 'eleven bytes'],
|
||||
[16, 0, 16, 'sixteen bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 1, 'one byte'],
|
||||
[10, 0, 11, 'eleven bytes'],
|
||||
[30, 0, 31, 'thirty-one bytes'],
|
||||
[31, 0, 32, 'one word'],
|
||||
[32, 0, 33, 'one word and one byte'],
|
||||
[71, 0, 72, 'two words and eight bytes'],
|
||||
[99, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with thirty-one bytes overlap', () =>
|
||||
test([
|
||||
[0, 0, 31, 'thirty-one bytes'],
|
||||
[1, 0, 32, 'one word'],
|
||||
[2, 0, 33, 'one word and one byte'],
|
||||
[41, 0, 72, 'two words and eight bytes'],
|
||||
[69, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with one word overlap', () =>
|
||||
test([
|
||||
[0, 0, 32, 'one word'],
|
||||
[1, 0, 33, 'one word and one byte'],
|
||||
[41, 0, 72, 'two words and eight bytes'],
|
||||
[69, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with one word and one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 33, 'one word and one byte'],
|
||||
[40, 0, 72, 'two words and eight bytes'],
|
||||
[68, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward with two words overlap', () =>
|
||||
test([
|
||||
[0, 0, 64, 'two words'],
|
||||
[8, 0, 72, 'two words and eight bytes'],
|
||||
[36, 0, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward within one word and one byte overlap', () =>
|
||||
test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']]));
|
||||
|
||||
describe('copies backward', () =>
|
||||
test([
|
||||
[0, 128, 0, 'zero bytes'],
|
||||
[0, 128, 1, 'one byte'],
|
||||
[0, 128, 11, 'eleven bytes'],
|
||||
[0, 128, 31, 'thirty-one bytes'],
|
||||
[0, 128, 32, 'one word'],
|
||||
[0, 128, 64, 'two words'],
|
||||
[0, 128, 96, 'three words'],
|
||||
[0, 128, 33, 'one word and one byte'],
|
||||
[0, 128, 72, 'two words and eight bytes'],
|
||||
[0, 128, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward within one word', () =>
|
||||
test([
|
||||
[0, 16, 0, 'zero bytes'],
|
||||
[0, 16, 1, 'one byte'],
|
||||
[0, 16, 11, 'eleven bytes'],
|
||||
[0, 16, 16, 'sixteen bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 1, 'one byte'],
|
||||
[0, 10, 11, 'eleven bytes'],
|
||||
[0, 30, 31, 'thirty-one bytes'],
|
||||
[0, 31, 32, 'one word'],
|
||||
[0, 32, 33, 'one word and one byte'],
|
||||
[0, 71, 72, 'two words and eight bytes'],
|
||||
[0, 99, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with thirty-one bytes overlap', () =>
|
||||
test([
|
||||
[0, 0, 31, 'thirty-one bytes'],
|
||||
[0, 1, 32, 'one word'],
|
||||
[0, 2, 33, 'one word and one byte'],
|
||||
[0, 41, 72, 'two words and eight bytes'],
|
||||
[0, 69, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with one word overlap', () =>
|
||||
test([
|
||||
[0, 0, 32, 'one word'],
|
||||
[0, 1, 33, 'one word and one byte'],
|
||||
[0, 41, 72, 'two words and eight bytes'],
|
||||
[0, 69, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with one word and one byte overlap', () =>
|
||||
test([
|
||||
[0, 0, 33, 'one word and one byte'],
|
||||
[0, 40, 72, 'two words and eight bytes'],
|
||||
[0, 68, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies backward with two words overlap', () =>
|
||||
test([
|
||||
[0, 0, 64, 'two words'],
|
||||
[0, 8, 72, 'two words and eight bytes'],
|
||||
[0, 36, 100, 'three words and four bytes'],
|
||||
]));
|
||||
|
||||
describe('copies forward within one word and one byte overlap', () =>
|
||||
test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']]));
|
||||
});
|
||||
});
|
@@ -1,26 +1,25 @@
|
||||
import { BlockchainLifecycle, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {
|
||||
MultiSigWalletWithTimeLockContract,
|
||||
SubmissionContractEventArgs,
|
||||
} from '../src/contract_wrappers/generated/multi_sig_wallet_with_time_lock';
|
||||
} from '../src/generated_contract_wrappers/multi_sig_wallet_with_time_lock';
|
||||
import { artifacts } from '../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../src/utils/assertions';
|
||||
import { chaiSetup } from '../src/utils/chai_setup';
|
||||
import { constants } from '../src/utils/constants';
|
||||
import { increaseTimeAndMineBlockAsync } from '../src/utils/increase_time';
|
||||
import { MultiSigWrapper } from '../src/utils/multi_sig_wrapper';
|
||||
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
describe('MultiSigWalletWithTimeLock', () => {
|
||||
let owners: string[];
|
||||
const REQUIRED_APPROVALS = new BigNumber(2);
|
||||
@@ -69,9 +68,9 @@ describe('MultiSigWalletWithTimeLock', () => {
|
||||
});
|
||||
|
||||
it('should throw when not called by wallet', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw without enough confirmations', async () => {
|
||||
@@ -80,10 +79,9 @@ describe('MultiSigWalletWithTimeLock', () => {
|
||||
const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
|
||||
const log = res.logs[0] as LogWithDecodedArgs<SubmissionContractEventArgs>;
|
||||
const txId = log.args.transactionId;
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should set confirmation time with enough confirmations', async () => {
|
||||
@@ -148,14 +146,15 @@ describe('MultiSigWalletWithTimeLock', () => {
|
||||
txId = log.args.transactionId;
|
||||
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
|
||||
});
|
||||
|
||||
it('should throw if it has enough confirmations but is not past the time lock', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should execute if it has enough confirmations and is past the time lock', async () => {
|
||||
await web3Wrapper.increaseTimeAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
@@ -167,3 +166,4 @@ describe('MultiSigWalletWithTimeLock', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
|
@@ -1,14 +1,13 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber, NULL_BYTES } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
import * as _ from 'lodash';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { TokenRegistryContract } from '../src/contract_wrappers/generated/token_registry';
|
||||
import { TokenRegistryContract } from '../src/generated_contract_wrappers/token_registry';
|
||||
import { artifacts } from '../src/utils/artifacts';
|
||||
import { expectRevertOrAlwaysFailingTransactionAsync } from '../src/utils/assertions';
|
||||
import { chaiSetup } from '../src/utils/chai_setup';
|
||||
import { constants } from '../src/utils/constants';
|
||||
import { TokenRegWrapper } from '../src/utils/token_registry_wrapper';
|
||||
@@ -76,7 +75,7 @@ describe('TokenRegistry', () => {
|
||||
|
||||
describe('addToken', () => {
|
||||
it('should throw when not called by owner', async () => {
|
||||
return expect(tokenRegWrapper.addTokenAsync(token1, notOwner)).to.be.rejectedWith(constants.REVERT);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, notOwner));
|
||||
});
|
||||
|
||||
it('should add token metadata when called by owner', async () => {
|
||||
@@ -88,19 +87,19 @@ describe('TokenRegistry', () => {
|
||||
it('should throw if token already exists', async () => {
|
||||
await tokenRegWrapper.addTokenAsync(token1, owner);
|
||||
|
||||
return expect(tokenRegWrapper.addTokenAsync(token1, owner)).to.be.rejectedWith(constants.REVERT);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(token1, owner));
|
||||
});
|
||||
|
||||
it('should throw if token address is null', async () => {
|
||||
return expect(tokenRegWrapper.addTokenAsync(nullToken, owner)).to.be.rejectedWith(constants.REVERT);
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(tokenRegWrapper.addTokenAsync(nullToken, owner));
|
||||
});
|
||||
|
||||
it('should throw if name already exists', async () => {
|
||||
await tokenRegWrapper.addTokenAsync(token1, owner);
|
||||
const duplicateNameToken = _.assign({}, token2, { name: token1.name });
|
||||
|
||||
return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenRegWrapper.addTokenAsync(duplicateNameToken, owner),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -110,8 +109,8 @@ describe('TokenRegistry', () => {
|
||||
symbol: token1.symbol,
|
||||
});
|
||||
|
||||
return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -137,9 +136,9 @@ describe('TokenRegistry', () => {
|
||||
|
||||
describe('setTokenName', () => {
|
||||
it('should throw when not called by owner', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: notOwner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should change the token name when called by owner', async () => {
|
||||
@@ -163,25 +162,25 @@ describe('TokenRegistry', () => {
|
||||
it('should throw if the name already exists', async () => {
|
||||
await tokenRegWrapper.addTokenAsync(token2, owner);
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.setTokenName.sendTransactionAsync(token1.address, token2.name, { from: owner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if token does not exist', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.setTokenName.sendTransactionAsync(nullToken.address, token2.name, { from: owner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTokenSymbol', () => {
|
||||
it('should throw when not called by owner', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, {
|
||||
from: notOwner,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should change the token symbol when called by owner', async () => {
|
||||
@@ -203,28 +202,28 @@ describe('TokenRegistry', () => {
|
||||
it('should throw if the symbol already exists', async () => {
|
||||
await tokenRegWrapper.addTokenAsync(token2, owner);
|
||||
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.setTokenSymbol.sendTransactionAsync(token1.address, token2.symbol, {
|
||||
from: owner,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if token does not exist', async () => {
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.setTokenSymbol.sendTransactionAsync(nullToken.address, token2.symbol, {
|
||||
from: owner,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeToken', () => {
|
||||
it('should throw if not called by owner', async () => {
|
||||
const index = new BigNumber(0);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.removeToken.sendTransactionAsync(token1.address, index, { from: notOwner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should remove token metadata when called by owner', async () => {
|
||||
@@ -241,17 +240,17 @@ describe('TokenRegistry', () => {
|
||||
|
||||
it('should throw if token does not exist', async () => {
|
||||
const index = new BigNumber(0);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.removeToken.sendTransactionAsync(nullToken.address, index, { from: owner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if token at given index does not match address', async () => {
|
||||
await tokenRegWrapper.addTokenAsync(token2, owner);
|
||||
const incorrectIndex = new BigNumber(0);
|
||||
return expect(
|
||||
return expectRevertOrAlwaysFailingTransactionAsync(
|
||||
tokenReg.removeToken.sendTransactionAsync(token2.address, incorrectIndex, { from: owner }),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -8,12 +8,12 @@
|
||||
// import ethUtil = require('ethereumjs-util');
|
||||
// import * as Web3 from 'web3';
|
||||
|
||||
// import { AccountLevelsContract } from '../../src/contract_wrappers/generated/account_levels';
|
||||
// import { ArbitrageContract } from '../../src/contract_wrappers/generated/arbitrage';
|
||||
// import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token';
|
||||
// import { EtherDeltaContract } from '../../src/contract_wrappers/generated/ether_delta';
|
||||
// import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
|
||||
// import { TokenTransferProxyContract } from '../../src/contract_wrappers/generated/token_transfer_proxy';
|
||||
// import { AccountLevelsContract } from '../../src/generated_contract_wrappers/account_levels';
|
||||
// import { ArbitrageContract } from '../../src/generated_contract_wrappers/arbitrage';
|
||||
// import { DummyTokenContract } from '../../src/generated_contract_wrappers/dummy_token';
|
||||
// import { EtherDeltaContract } from '../../src/generated_contract_wrappers/ether_delta';
|
||||
// import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
|
||||
// import { TokenTransferProxyContract } from '../../src/generated_contract_wrappers/token_transfer_proxy';
|
||||
// import { artifacts } from '../../util/artifacts';
|
||||
// import { Balances } from '../../util/balances';
|
||||
// import { constants } from '../../util/constants';
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { DummyERC20TokenContract } from '../src/contract_wrappers/generated/dummy_e_r_c20_token';
|
||||
import { DummyERC20TokenContract } from '../src/generated_contract_wrappers/dummy_e_r_c20_token';
|
||||
import { artifacts } from '../src/utils/artifacts';
|
||||
import { expectRevertOrOtherErrorAsync } from '../src/utils/assertions';
|
||||
import { chaiSetup } from '../src/utils/chai_setup';
|
||||
import { constants } from '../src/utils/constants';
|
||||
import { provider, txDefaults, web3Wrapper } from '../src/utils/web3_wrapper';
|
||||
@@ -55,8 +54,9 @@ describe('UnlimitedAllowanceToken', () => {
|
||||
it('should throw if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await token.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
return expect(token.transfer.callAsync(spender, amountToTransfer, { from: owner })).to.be.rejectedWith(
|
||||
constants.REVERT,
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
token.transfer.callAsync(spender, amountToTransfer, { from: owner }),
|
||||
constants.ERC20_INSUFFICIENT_BALANCE,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -93,11 +93,12 @@ describe('UnlimitedAllowanceToken', () => {
|
||||
await token.approve.sendTransactionAsync(spender, amountToTransfer, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
return expect(
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
constants.ERC20_INSUFFICIENT_BALANCE,
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if spender has insufficient allowance', async () => {
|
||||
@@ -108,11 +109,12 @@ describe('UnlimitedAllowanceToken', () => {
|
||||
const isSpenderAllowanceInsufficient = spenderAllowance.cmp(amountToTransfer) < 0;
|
||||
expect(isSpenderAllowanceInsufficient).to.be.true();
|
||||
|
||||
return expect(
|
||||
return expectRevertOrOtherErrorAsync(
|
||||
token.transferFrom.callAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
}),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
constants.ERC20_INSUFFICIENT_ALLOWANCE,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true on a 0 value transfer', async () => {
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import 'make-promises-safe';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import { ZRXTokenContract } from '../src/contract_wrappers/generated/zrx_token';
|
||||
import { ZRXTokenContract } from '../src/generated_contract_wrappers/zrx_token';
|
||||
import { artifacts } from '../src/utils/artifacts';
|
||||
import { chaiSetup } from '../src/utils/chai_setup';
|
||||
import { constants } from '../src/utils/constants';
|
||||
@@ -79,7 +78,10 @@ describe('ZRXToken', () => {
|
||||
const receiver = spender;
|
||||
const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = new BigNumber(1);
|
||||
await zrxToken.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner });
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transfer.sendTransactionAsync(receiver, amountToTransfer, { from: owner }),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const finalOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const finalReceiverBalance = await zrxToken.balanceOf.callAsync(receiver);
|
||||
|
||||
@@ -101,10 +103,13 @@ describe('ZRXToken', () => {
|
||||
it('should return false if owner has insufficient balance', async () => {
|
||||
const ownerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = ownerBalance.plus(1);
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
const didReturnTrue = await zrxToken.transferFrom.callAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
});
|
||||
@@ -137,14 +142,20 @@ describe('ZRXToken', () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = MAX_UINT;
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
});
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance, {
|
||||
from: owner,
|
||||
gas: constants.MAX_TOKEN_APPROVE_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
|
||||
expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
|
||||
@@ -155,11 +166,17 @@ describe('ZRXToken', () => {
|
||||
const initSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
const initSpenderAllowance = initOwnerBalance;
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance);
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, initSpenderAllowance),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const newSpenderBalance = await zrxToken.balanceOf.callAsync(spender);
|
||||
@@ -171,11 +188,17 @@ describe('ZRXToken', () => {
|
||||
it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
|
||||
const initOwnerBalance = await zrxToken.balanceOf.callAsync(owner);
|
||||
const amountToTransfer = initOwnerBalance;
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer);
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
});
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.approve.sendTransactionAsync(spender, amountToTransfer),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await zrxToken.transferFrom.sendTransactionAsync(owner, spender, amountToTransfer, {
|
||||
from: spender,
|
||||
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
|
||||
}),
|
||||
constants.AWAIT_TRANSACTION_MINED_MS,
|
||||
);
|
||||
|
||||
const newSpenderAllowance = await zrxToken.allowance.callAsync(owner, spender);
|
||||
expect(newSpenderAllowance).to.be.bignumber.equal(0);
|
||||
|
Reference in New Issue
Block a user