Compare commits
44 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
6b0f3570b9 | ||
|
71de0d04f3 | ||
|
99debff5d2 | ||
|
3bac6fcb27 | ||
|
4b842b81a0 | ||
|
e2e4d048ab | ||
|
5574c368cd | ||
|
0d34f7b92e | ||
|
5be0632e01 | ||
|
79ea0bf9f4 | ||
|
b1929cb688 | ||
|
5ad98700e5 | ||
|
a54624b697 | ||
|
ca34c865af | ||
|
dde57b1eca | ||
|
264b06938e | ||
|
99edb303e2 | ||
|
104cc24dfc | ||
|
fcbcbac889 | ||
|
b86d19028c | ||
|
4f17a251d3 | ||
|
3d79fe2bf4 | ||
|
474399154f | ||
|
19f5153d0e | ||
|
ce11271866 | ||
|
86cf353296 | ||
|
36df5dc721 | ||
|
1e44a9c942 | ||
|
8685cf9036 | ||
|
2232870b09 | ||
|
b68acd101e | ||
|
173ba9b2b5 | ||
|
64ed1f87d3 | ||
|
1ca085ec4a | ||
|
e332b7535c | ||
|
79eb613b3e | ||
|
5a79ec28d1 | ||
|
97e65a02c0 | ||
|
e87c786b77 | ||
|
251d30d47f | ||
|
7a3f878c11 | ||
|
b8439598bc | ||
|
7fb0818923 | ||
|
a7c435adc4 |
@@ -193,10 +193,7 @@ jobs:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: 0xorg/ganache-cli:4.4.0-beta.1
|
||||
environment:
|
||||
VERSION: latest
|
||||
SNAPSHOT_NAME: 0x_ganache_snapshot-v3-beta
|
||||
- image: 0xorg/ganache-cli
|
||||
- image: 0xorg/mesh:0xV3
|
||||
environment:
|
||||
ETHEREUM_RPC_URL: 'http://localhost:8545'
|
||||
@@ -219,7 +216,7 @@ jobs:
|
||||
TAKER_FEE_UNIT_AMOUNT: 0
|
||||
MESH_ENDPOINT: 'ws://localhost:60557'
|
||||
command: |
|
||||
sh -c "waitForMesh () { sleep 5; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
|
||||
sh -c "waitForMesh () { sleep 30; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Implement `KyberBridge`. (#2352)
|
||||
|
75
contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
Normal file
75
contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IChai.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract ChaiBridge is
|
||||
IERC20Bridge,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Withdraws `amount` of `from` address's Dai from the Chai contract.
|
||||
/// Transfers `amount` of Dai to `to` address.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
/// @return success The magic bytes `0x37708e9b` if successful.
|
||||
function bridgeTransferFrom(
|
||||
address /* tokenAddress */,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata /* bridgeData */
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Ensure that only the `ERC20BridgeProxy` can call this function.
|
||||
require(
|
||||
msg.sender == _getERC20BridgeProxyAddress(),
|
||||
"ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
|
||||
);
|
||||
|
||||
// Withdraw `from` address's Dai.
|
||||
// NOTE: This contract must be approved to spend Chai on behalf of `from`.
|
||||
bytes memory drawCalldata = abi.encodeWithSelector(
|
||||
IChai(address(0)).draw.selector,
|
||||
from,
|
||||
amount
|
||||
);
|
||||
|
||||
(bool success,) = _getChaiAddress().call(drawCalldata);
|
||||
require(
|
||||
success,
|
||||
"ChaiBridge/DRAW_DAI_FAILED"
|
||||
);
|
||||
|
||||
// Transfer Dai to `to`
|
||||
// This will never fail if the `draw` call was successful
|
||||
IERC20Token(_getDaiAddress()).transfer(to, amount);
|
||||
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
}
|
@@ -55,7 +55,7 @@ contract Eth2DaiBridge is
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
IEth2Dai exchange = _getEth2DaiContract();
|
||||
IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress());
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
|
||||
|
||||
@@ -84,14 +84,4 @@ contract Eth2DaiBridge is
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the eth2dai contract.
|
||||
/// @return exchange The Eth2Dai exchange contract.
|
||||
function _getEth2DaiContract()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai exchange)
|
||||
{
|
||||
return IEth2Dai(_getEth2DaiAddress());
|
||||
}
|
||||
}
|
||||
|
@@ -77,8 +77,8 @@ contract KyberBridge is
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TradeState memory state;
|
||||
state.kyber = _getKyberContract();
|
||||
state.weth = _getWETHContract();
|
||||
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(state.fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||
@@ -143,24 +143,4 @@ contract KyberBridge is
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the `KyberNetworkProxy` contract.
|
||||
/// @return kyber The `IKyberNetworkProxy` contract.
|
||||
function _getKyberContract()
|
||||
internal
|
||||
view
|
||||
returns (IKyberNetworkProxy kyber)
|
||||
{
|
||||
return IKyberNetworkProxy(_getKyberNetworkProxyAddress());
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the WETH contract.
|
||||
/// @return weth The WETH contract.
|
||||
function _getWETHContract()
|
||||
internal
|
||||
view
|
||||
returns (IEtherToken weth)
|
||||
{
|
||||
return IEtherToken(_getWETHAddress());
|
||||
}
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ contract UniswapBridge is
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Get the weth contract.
|
||||
state.weth = getWethContract();
|
||||
state.weth = IEtherToken(_getWethAddress());
|
||||
|
||||
// Convert from WETH to a token.
|
||||
if (fromTokenAddress == address(state.weth)) {
|
||||
@@ -161,26 +161,6 @@ contract UniswapBridge is
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the weth contract.
|
||||
/// @return token The WETH contract.
|
||||
function getWethContract()
|
||||
public
|
||||
view
|
||||
returns (IEtherToken token)
|
||||
{
|
||||
return IEtherToken(_getWETHAddress());
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get the uniswap exchange factory contract.
|
||||
/// @return factory The exchange factory contract.
|
||||
function getUniswapExchangeFactoryContract()
|
||||
public
|
||||
view
|
||||
returns (IUniswapExchangeFactory factory)
|
||||
{
|
||||
return IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress());
|
||||
}
|
||||
|
||||
/// @dev Grants an unlimited allowance to the exchange for its token
|
||||
/// on behalf of this contract.
|
||||
/// @param exchange The Uniswap token exchange.
|
||||
@@ -207,11 +187,12 @@ contract UniswapBridge is
|
||||
{
|
||||
address exchangeTokenAddress = fromTokenAddress;
|
||||
// Whichever isn't WETH is the exchange token.
|
||||
if (fromTokenAddress == address(getWethContract())) {
|
||||
if (fromTokenAddress == _getWethAddress()) {
|
||||
exchangeTokenAddress = toTokenAddress;
|
||||
}
|
||||
exchange = IUniswapExchange(
|
||||
getUniswapExchangeFactoryContract().getExchange(exchangeTokenAddress)
|
||||
IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
|
||||
.getExchange(exchangeTokenAddress)
|
||||
);
|
||||
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
|
||||
return exchange;
|
||||
|
33
contracts/asset-proxy/contracts/src/interfaces/IChai.sol
Normal file
33
contracts/asset-proxy/contracts/src/interfaces/IChai.sol
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
// The actual Chai contract can be found here: https://github.com/dapphub/chai
|
||||
contract IChai {
|
||||
|
||||
/// @dev Withdraws Dai owned by `src`
|
||||
/// @param src Address that owns Dai.
|
||||
/// @param wad Amount of Dai to withdraw.
|
||||
function draw(
|
||||
address src,
|
||||
uint256 wad
|
||||
)
|
||||
external;
|
||||
}
|
80
contracts/asset-proxy/contracts/test/TestChaiBridge.sol
Normal file
80
contracts/asset-proxy/contracts/test/TestChaiBridge.sol
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/bridges/ChaiBridge.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/ERC20Token.sol";
|
||||
|
||||
|
||||
contract TestChaiDai is
|
||||
ERC20Token
|
||||
{
|
||||
address private constant ALWAYS_REVERT_ADDRESS = address(1);
|
||||
|
||||
function draw(
|
||||
address from,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
if (from == ALWAYS_REVERT_ADDRESS) {
|
||||
revert();
|
||||
}
|
||||
balances[msg.sender] += amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestChaiBridge is
|
||||
ChaiBridge
|
||||
{
|
||||
address public testChaiDai;
|
||||
address private constant ALWAYS_REVERT_ADDRESS = address(1);
|
||||
|
||||
constructor()
|
||||
public
|
||||
{
|
||||
testChaiDai = address(new TestChaiDai());
|
||||
}
|
||||
|
||||
function _getDaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return testChaiDai;
|
||||
}
|
||||
|
||||
function _getChaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return testChaiDai;
|
||||
}
|
||||
|
||||
function _getERC20BridgeProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
|
||||
}
|
||||
}
|
@@ -192,11 +192,11 @@ contract TestEth2DaiBridge is
|
||||
}
|
||||
|
||||
// @dev This contract will double as the Eth2Dai contract.
|
||||
function _getEth2DaiContract()
|
||||
function _getEth2DaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai)
|
||||
returns (address)
|
||||
{
|
||||
return IEth2Dai(address(this));
|
||||
return address(this);
|
||||
}
|
||||
}
|
||||
|
@@ -303,20 +303,20 @@ contract TestKyberBridge is
|
||||
}
|
||||
|
||||
// @dev overridden to point to this contract.
|
||||
function _getKyberContract()
|
||||
function _getKyberNetworkProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (IKyberNetworkProxy kyber)
|
||||
returns (address)
|
||||
{
|
||||
return IKyberNetworkProxy(address(this));
|
||||
return address(this);
|
||||
}
|
||||
|
||||
// @dev overridden to point to test WETH.
|
||||
function _getWETHContract()
|
||||
function _getWethAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEtherToken weth_)
|
||||
returns (address)
|
||||
{
|
||||
return weth;
|
||||
return address(weth);
|
||||
}
|
||||
}
|
||||
|
@@ -413,20 +413,20 @@ contract TestUniswapBridge is
|
||||
}
|
||||
|
||||
// @dev Use `wethToken`.
|
||||
function getWethContract()
|
||||
public
|
||||
function _getWethAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEtherToken)
|
||||
returns (address)
|
||||
{
|
||||
return IEtherToken(address(wethToken));
|
||||
return address(wethToken);
|
||||
}
|
||||
|
||||
// @dev This contract will double as the Uniswap contract.
|
||||
function getUniswapExchangeFactoryContract()
|
||||
public
|
||||
function _getUniswapExchangeFactoryAddress()
|
||||
internal
|
||||
view
|
||||
returns (IUniswapExchangeFactory)
|
||||
returns (address)
|
||||
{
|
||||
return IUniswapExchangeFactory(address(this));
|
||||
return address(this);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,8 +38,8 @@
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,KyberBridge,TestStaticCallTarget",
|
||||
"abis": "./test/generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,KyberBridge,ChaiBridge,TestStaticCallTarget",
|
||||
"abis": "./test/generated-artifacts/@(ChaiBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -52,15 +52,15 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -80,15 +80,15 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.0",
|
||||
"@0x/contracts-erc1155": "^2.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-erc721": "^3.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.1",
|
||||
"@0x/contracts-erc1155": "^2.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-erc721": "^3.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
|
||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
||||
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
|
||||
@@ -29,5 +30,6 @@ export const artifacts = {
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||
};
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/chai_bridge';
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../generated-wrappers/erc20_proxy';
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
|
||||
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
|
||||
import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json';
|
||||
@@ -14,6 +15,7 @@ import * as IAssetData from '../test/generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
|
||||
import * as IChai from '../test/generated-artifacts/IChai.json';
|
||||
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
|
||||
@@ -25,6 +27,7 @@ import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizabl
|
||||
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../test/generated-artifacts/Ownable.json';
|
||||
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
|
||||
import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json';
|
||||
import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json';
|
||||
@@ -41,6 +44,7 @@ export const artifacts = {
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
@@ -48,11 +52,13 @@ export const artifacts = {
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
||||
IUniswapExchange: IUniswapExchange as ContractArtifact,
|
||||
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
|
||||
TestChaiBridge: TestChaiBridge as ContractArtifact,
|
||||
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
|
||||
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
|
||||
TestKyberBridge: TestKyberBridge as ContractArtifact,
|
||||
|
60
contracts/asset-proxy/test/chai_bridge.ts
Normal file
60
contracts/asset-proxy/test/chai_bridge.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { ERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestChaiBridgeContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('ChaiBridge unit tests', env => {
|
||||
let chaiBridgeContract: TestChaiBridgeContract;
|
||||
let testDaiContract: ERC20TokenContract;
|
||||
let fromAddress: string;
|
||||
let toAddress: string;
|
||||
|
||||
const alwaysRevertAddress = '0x0000000000000000000000000000000000000001';
|
||||
const amount = new BigNumber(1);
|
||||
|
||||
before(async () => {
|
||||
[fromAddress, toAddress] = await env.getAccountAddressesAsync();
|
||||
chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestChaiBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync();
|
||||
testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults);
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
it('fails if not called by ERC20BridgeProxy', async () => {
|
||||
return expect(
|
||||
chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: alwaysRevertAddress }),
|
||||
).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy);
|
||||
});
|
||||
it('returns magic bytes upon success', async () => {
|
||||
const magicBytes = await chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.callAsync();
|
||||
expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => {
|
||||
const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync();
|
||||
await chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync();
|
||||
const endBalance = await testDaiContract.balanceOf(toAddress).callAsync();
|
||||
expect(endBalance).to.bignumber.eq(initialBalance.plus(amount));
|
||||
});
|
||||
it('fails if the `chai.draw` call fails', async () => {
|
||||
return expect(
|
||||
chaiBridgeContract
|
||||
.bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync(),
|
||||
).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed);
|
||||
});
|
||||
});
|
||||
});
|
@@ -3,15 +3,12 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRightPad,
|
||||
hexSlice,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, StringRevertError } from '@0x/utils';
|
||||
import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -21,7 +18,7 @@ import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const PROXY_ID = AssetProxyId.ERC20Bridge;
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID);
|
||||
const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID);
|
||||
let owner: string;
|
||||
let badCaller: string;
|
||||
let assetProxy: ERC20BridgeProxyContract;
|
||||
@@ -173,7 +170,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
|
||||
it('fails if asset data is truncated', async () => {
|
||||
const opts = createTransferFromOpts();
|
||||
const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1);
|
||||
const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1);
|
||||
const tx = assetProxy
|
||||
.transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount))
|
||||
.awaitTransactionSuccessAsync();
|
||||
@@ -197,7 +194,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: hexLeftPad('0x1'),
|
||||
returnData: hexUtils.leftPad('0x1'),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
@@ -210,7 +207,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||
const tx = transferFromAsync({
|
||||
assetData: createAssetData({
|
||||
bridgeData: createBridgeData({
|
||||
returnData: hexRightPad('0x1'),
|
||||
returnData: hexUtils.rightPad('0x1'),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
@@ -4,13 +4,11 @@ import {
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber, RawRevertError } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, RawRevertError } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -39,7 +37,9 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
@@ -71,7 +71,7 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
fillAmount: getRandomInteger(1, 100e18),
|
||||
fromTokenBalance: getRandomInteger(1, 100e18),
|
||||
toTokentransferRevertReason: '',
|
||||
toTokenTransferReturnData: hexLeftPad(1),
|
||||
toTokenTransferReturnData: hexUtils.leftPad(1),
|
||||
...opts,
|
||||
};
|
||||
}
|
||||
@@ -111,7 +111,7 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
_opts.toAddress,
|
||||
new BigNumber(_opts.amount),
|
||||
// ABI-encode the "from" token address as the bridge data.
|
||||
hexLeftPad(_opts.fromTokenAddress as string),
|
||||
hexUtils.leftPad(_opts.fromTokenAddress as string),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
@@ -179,13 +179,13 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||
});
|
||||
|
||||
it('fails if `toTokenAddress.transfer()` returns false', async () => {
|
||||
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) });
|
||||
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) });
|
||||
const tx = withdrawToAsync(opts);
|
||||
return expect(tx).to.revertWith(new RawRevertError(hexLeftPad(0)));
|
||||
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
|
||||
});
|
||||
|
||||
it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
|
||||
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) });
|
||||
await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,13 +3,11 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -33,7 +31,9 @@ blockchainTests.resets('KyberBridge unit tests', env => {
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
@@ -107,7 +107,7 @@ blockchainTests.resets('KyberBridge unit tests', env => {
|
||||
// Transfer amount.
|
||||
_opts.amount,
|
||||
// ABI-encode the input token address as the bridge data.
|
||||
hexLeftPad(_opts.fromTokenAddress),
|
||||
hexUtils.leftPad(_opts.fromTokenAddress),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
|
@@ -5,13 +5,11 @@ import {
|
||||
filterLogs,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
Numberish,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -46,7 +44,9 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
describe('isValidSignature()', () => {
|
||||
it('returns success bytes', async () => {
|
||||
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||
const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
|
||||
const result = await testContract
|
||||
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
|
||||
.callAsync();
|
||||
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||
});
|
||||
});
|
||||
@@ -126,7 +126,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
// The amount to transfer to "to"
|
||||
new BigNumber(_opts.amount),
|
||||
// ABI-encoded "from" token address.
|
||||
hexLeftPad(_opts.fromTokenAddress),
|
||||
hexUtils.leftPad(_opts.fromTokenAddress),
|
||||
);
|
||||
const result = await bridgeTransferFromFn.callAsync();
|
||||
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
|
||||
@@ -208,7 +208,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexLeftPad(randomAddress()),
|
||||
hexUtils.leftPad(randomAddress()),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
@@ -282,7 +282,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexLeftPad(wethTokenAddress),
|
||||
hexUtils.leftPad(wethTokenAddress),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
@@ -342,7 +342,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
|
||||
randomAddress(),
|
||||
randomAddress(),
|
||||
getRandomInteger(1, 1e18),
|
||||
hexLeftPad(randomAddress()),
|
||||
hexUtils.leftPad(randomAddress()),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/chai_bridge';
|
||||
export * from '../test/generated-wrappers/erc1155_proxy';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../test/generated-wrappers/erc20_proxy';
|
||||
@@ -12,6 +13,7 @@ export * from '../test/generated-wrappers/i_asset_data';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/i_authorizable';
|
||||
export * from '../test/generated-wrappers/i_chai';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
||||
@@ -23,6 +25,7 @@ export * from '../test/generated-wrappers/mixin_authorizable';
|
||||
export * from '../test/generated-wrappers/multi_asset_proxy';
|
||||
export * from '../test/generated-wrappers/ownable';
|
||||
export * from '../test/generated-wrappers/static_call_proxy';
|
||||
export * from '../test/generated-wrappers/test_chai_bridge';
|
||||
export * from '../test/generated-wrappers/test_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../test/generated-wrappers/test_kyber_bridge';
|
||||
|
@@ -3,6 +3,7 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
"generated-artifacts/ERC20Proxy.json",
|
||||
@@ -15,6 +16,7 @@
|
||||
"generated-artifacts/StaticCallProxy.json",
|
||||
"generated-artifacts/TestStaticCallTarget.json",
|
||||
"generated-artifacts/UniswapBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/ERC1155Proxy.json",
|
||||
"test/generated-artifacts/ERC20BridgeProxy.json",
|
||||
"test/generated-artifacts/ERC20Proxy.json",
|
||||
@@ -24,6 +26,7 @@
|
||||
"test/generated-artifacts/IAssetProxy.json",
|
||||
"test/generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/IAuthorizable.json",
|
||||
"test/generated-artifacts/IChai.json",
|
||||
"test/generated-artifacts/IERC20Bridge.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
@@ -35,6 +38,7 @@
|
||||
"test/generated-artifacts/MultiAssetProxy.json",
|
||||
"test/generated-artifacts/Ownable.json",
|
||||
"test/generated-artifacts/StaticCallProxy.json",
|
||||
"test/generated-artifacts/TestChaiBridge.json",
|
||||
"test/generated-artifacts/TestERC20Bridge.json",
|
||||
"test/generated-artifacts/TestEth2DaiBridge.json",
|
||||
"test/generated-artifacts/TestKyberBridge.json",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,19 +52,19 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-asset-proxy": "^3.0.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-exchange": "^3.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-asset-proxy": "^3.0.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-exchange": "^3.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -84,14 +84,14 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.0",
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/assert": "^3.0.1",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/contract-addresses": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/json-schemas": "^5.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/json-schemas": "^5.0.1",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"http-status-codes": "^1.3.2"
|
||||
},
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { hexConcat, signingUtils } from '@0x/contracts-test-utils';
|
||||
import { signingUtils } from '@0x/contracts-test-utils';
|
||||
import { SignatureType, SignedZeroExTransaction } from '@0x/types';
|
||||
import { hexUtils } from '@0x/utils';
|
||||
|
||||
import { hashUtils } from './hash_utils';
|
||||
import { SignedCoordinatorApproval } from './types';
|
||||
@@ -27,7 +28,7 @@ export class ApprovalFactory {
|
||||
const signedApproval = {
|
||||
txOrigin,
|
||||
transaction,
|
||||
signature: hexConcat(signatureBuff),
|
||||
signature: hexUtils.concat(signatureBuff),
|
||||
};
|
||||
return signedApproval;
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { hexConcat } from '@0x/contracts-test-utils';
|
||||
import { eip712Utils } from '@0x/order-utils';
|
||||
import { SignedZeroExTransaction } from '@0x/types';
|
||||
import { signTypedDataUtils } from '@0x/utils';
|
||||
import { hexUtils, signTypedDataUtils } from '@0x/utils';
|
||||
|
||||
export const hashUtils = {
|
||||
async getApprovalHashBufferAsync(
|
||||
@@ -22,7 +21,9 @@ export const hashUtils = {
|
||||
verifyingContract: string,
|
||||
txOrigin: string,
|
||||
): Promise<string> {
|
||||
const hashHex = hexConcat(await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin));
|
||||
const hashHex = hexUtils.concat(
|
||||
await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin),
|
||||
);
|
||||
return hashHex;
|
||||
},
|
||||
};
|
||||
|
@@ -4,15 +4,13 @@ import {
|
||||
constants,
|
||||
ExchangeFunctionName,
|
||||
expect,
|
||||
hexConcat,
|
||||
hexSlice,
|
||||
randomAddress,
|
||||
TransactionFactory,
|
||||
transactionHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { LibBytesRevertErrors } from '@0x/contracts-utils';
|
||||
import { SignatureType, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, CoordinatorRevertErrors } from '@0x/utils';
|
||||
import { BigNumber, CoordinatorRevertErrors, hexUtils } from '@0x/utils';
|
||||
|
||||
import { ApprovalFactory } from '../src/approval_factory';
|
||||
|
||||
@@ -89,8 +87,8 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
it('should revert with with the Illegal signature type', async () => {
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = hexConcat(
|
||||
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
|
||||
transaction.signature = hexUtils.concat(
|
||||
hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1),
|
||||
SignatureType.Illegal,
|
||||
);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
@@ -105,7 +103,7 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
it('should revert with with the Invalid signature type', async () => {
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = hexConcat(SignatureType.Invalid);
|
||||
transaction.signature = hexUtils.concat(SignatureType.Invalid);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith(
|
||||
new CoordinatorRevertErrors.SignatureError(
|
||||
@@ -118,8 +116,8 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
it('should revert with with a signature type that equals `NSignatureTypes`', async () => {
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = hexConcat(
|
||||
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
|
||||
transaction.signature = hexUtils.concat(
|
||||
hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1),
|
||||
SignatureType.NSignatureTypes,
|
||||
);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
@@ -134,8 +132,8 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
it("should revert with with a signature type that isn't supported", async () => {
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = hexConcat(
|
||||
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
|
||||
transaction.signature = hexUtils.concat(
|
||||
hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1),
|
||||
SignatureType.Wallet,
|
||||
);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
@@ -296,10 +294,10 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
|
||||
const signature = hexConcat(
|
||||
hexSlice(approval.signature, 0, 2),
|
||||
const signature = hexUtils.concat(
|
||||
hexUtils.slice(approval.signature, 0, 2),
|
||||
'0xFFFFFFFF',
|
||||
hexSlice(approval.signature, 6),
|
||||
hexUtils.slice(approval.signature, 6),
|
||||
);
|
||||
const tx = mixins
|
||||
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
|
||||
@@ -432,10 +430,10 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
|
||||
const signature = hexConcat(
|
||||
hexSlice(approval.signature, 0, 2),
|
||||
const signature = hexUtils.concat(
|
||||
hexUtils.slice(approval.signature, 0, 2),
|
||||
'0xFFFFFFFF',
|
||||
hexSlice(approval.signature, 6),
|
||||
hexUtils.slice(approval.signature, 6),
|
||||
);
|
||||
const tx = mixins
|
||||
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
|
||||
@@ -454,10 +452,10 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
|
||||
const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress);
|
||||
const approvalSignature2 = hexConcat(
|
||||
hexSlice(approval2.signature, 0, 2),
|
||||
const approvalSignature2 = hexUtils.concat(
|
||||
hexUtils.slice(approval2.signature, 0, 2),
|
||||
'0xFFFFFFFF',
|
||||
hexSlice(approval2.signature, 6),
|
||||
hexUtils.slice(approval2.signature, 6),
|
||||
);
|
||||
const tx = mixins
|
||||
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
|
||||
@@ -476,10 +474,10 @@ blockchainTests.resets('Mixins tests', env => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
|
||||
const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress);
|
||||
const approvalSignature2 = hexConcat(
|
||||
hexSlice(approval2.signature, 0, 2),
|
||||
const approvalSignature2 = hexUtils.concat(
|
||||
hexUtils.slice(approval2.signature, 0, 2),
|
||||
'0xFFFFFFFF',
|
||||
hexSlice(approval2.signature, 6),
|
||||
hexUtils.slice(approval2.signature, 6),
|
||||
);
|
||||
const tx = mixins
|
||||
.assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,10 +41,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/assert": "^3.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/assert": "^3.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@types/node": "*",
|
||||
@@ -59,7 +59,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0"
|
||||
"@0x/base-contract": "^6.0.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,14 +52,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -80,10 +80,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _December 2, 2019_
|
||||
|
||||
* Created package. (#2344)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,18 +50,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-asset-proxy": "^3.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-exchange": "^3.0.0",
|
||||
"@0x/contracts-exchange-libs": "^4.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-asset-proxy": "^3.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-exchange": "^3.0.1",
|
||||
"@0x/contracts-exchange-libs": "^4.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -79,10 +79,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -4,15 +4,10 @@ import {
|
||||
expect,
|
||||
getRandomInteger,
|
||||
getRandomPortion,
|
||||
hexConcat,
|
||||
hexHash,
|
||||
hexLeftPad,
|
||||
hexRandom,
|
||||
randomAddress,
|
||||
toHex,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { Order, OrderInfo } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
@@ -31,8 +26,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
|
||||
const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
|
||||
const ERC20_PROXY_ID = '0xf47261b0';
|
||||
const INVALID_ASSET_PROXY_ASSET_DATA = hexConcat('0xf47261b1', hexLeftPad(randomAddress()));
|
||||
const INVALID_ASSET_DATA = hexRandom(37);
|
||||
const INVALID_ASSET_PROXY_ASSET_DATA = hexUtils.concat('0xf47261b1', hexUtils.leftPad(randomAddress()));
|
||||
const INVALID_ASSET_DATA = hexUtils.random(37);
|
||||
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
|
||||
const BUY_SOURCES = ['Eth2Dai', 'Uniswap'];
|
||||
const EMPTY_ORDERS_ERROR = 'EMPTY_ORDERS';
|
||||
@@ -60,7 +55,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
|
||||
function getPackedHash(...args: string[]): string {
|
||||
return hexHash(hexConcat(...args.map(a => toHex(a))));
|
||||
return hexUtils.hash(hexUtils.concat(...args.map(a => hexUtils.toHex(a))));
|
||||
}
|
||||
|
||||
function getUniswapExchangeSalt(tokenAddress: string): string {
|
||||
@@ -198,7 +193,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
}
|
||||
|
||||
function getDeterministicOrderInfo(order: Order): OrderInfo {
|
||||
const hash = getPackedHash(toHex(order.salt, 32));
|
||||
const hash = getPackedHash(hexUtils.leftPad(order.salt, 32));
|
||||
return {
|
||||
orderHash: hash,
|
||||
orderStatus: new BigNumber(hash).mod(255).toNumber(),
|
||||
@@ -207,7 +202,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
}
|
||||
|
||||
function getERC20AssetData(tokenAddress: string): string {
|
||||
return hexConcat(ERC20_PROXY_ID, hexLeftPad(tokenAddress));
|
||||
return hexUtils.concat(ERC20_PROXY_ID, hexUtils.leftPad(tokenAddress));
|
||||
}
|
||||
|
||||
function getSampleAmounts(tokenAddress: string, count?: number): BigNumber[] {
|
||||
@@ -234,7 +229,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: getERC20AssetData(takerToken),
|
||||
makerFeeAssetData: getERC20AssetData(randomAddress()),
|
||||
takerFeeAssetData: getERC20AssetData(randomAddress()),
|
||||
salt: new BigNumber(hexRandom()),
|
||||
salt: new BigNumber(hexUtils.random()),
|
||||
expirationTimeSeconds: getRandomInteger(0, 2 ** 32),
|
||||
};
|
||||
}
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,18 +51,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -82,7 +82,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0"
|
||||
"@0x/base-contract": "^6.0.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -3,11 +3,10 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { RawRevertError, StringRevertError } from '@0x/utils';
|
||||
import { hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
|
||||
|
||||
import { TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from './wrappers';
|
||||
|
||||
@@ -17,11 +16,11 @@ blockchainTests('LibERC20Token', env => {
|
||||
let testContract: TestLibERC20TokenContract;
|
||||
const REVERT_STRING = 'WHOOPSIE';
|
||||
const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
|
||||
const ENCODED_TRUE = hexLeftPad(1);
|
||||
const ENCODED_FALSE = hexLeftPad(0);
|
||||
const ENCODED_TWO = hexLeftPad(2);
|
||||
const ENCODED_SHORT_TRUE = hexLeftPad(2, 31);
|
||||
const ENCODED_LONG_TRUE = hexLeftPad(2, 33);
|
||||
const ENCODED_TRUE = hexUtils.leftPad(1);
|
||||
const ENCODED_FALSE = hexUtils.leftPad(0);
|
||||
const ENCODED_TWO = hexUtils.leftPad(2);
|
||||
const ENCODED_SHORT_TRUE = hexUtils.leftPad(2, 31);
|
||||
const ENCODED_LONG_TRUE = hexUtils.leftPad(2, 33);
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
@@ -301,14 +300,14 @@ blockchainTests('LibERC20Token', env => {
|
||||
|
||||
describe('decimals()', () => {
|
||||
const DEFAULT_DECIMALS = 18;
|
||||
const ENCODED_ZERO = hexLeftPad(0);
|
||||
const ENCODED_SHORT_ZERO = hexLeftPad(0, 31);
|
||||
const ENCODED_LONG_ZERO = hexLeftPad(0, 33);
|
||||
const ENCODED_ZERO = hexUtils.leftPad(0);
|
||||
const ENCODED_SHORT_ZERO = hexUtils.leftPad(0, 31);
|
||||
const ENCODED_LONG_ZERO = hexUtils.leftPad(0, 33);
|
||||
const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
|
||||
|
||||
it('returns the number of decimals defined by the token', async () => {
|
||||
const decimals = randomDecimals();
|
||||
const encodedDecimals = hexLeftPad(decimals);
|
||||
const encodedDecimals = hexUtils.leftPad(decimals);
|
||||
const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
|
||||
return expect(result).to.bignumber.eq(decimals);
|
||||
});
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,18 +52,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -84,7 +84,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0"
|
||||
"@0x/base-contract": "^6.0.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.0 - _December 2, 2019_
|
||||
|
||||
* Added buy support for ERC20Bridge (#2356)
|
||||
|
@@ -109,6 +109,7 @@ contract MixinExchangeWrapper is
|
||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||
.safeSub(singleFillResults.takerFeePaid);
|
||||
|
||||
// WETH fee
|
||||
} else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.takerAssetData)) {
|
||||
|
||||
@@ -132,6 +133,7 @@ contract MixinExchangeWrapper is
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
|
||||
// Unsupported fee
|
||||
} else {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
|
||||
@@ -146,7 +148,7 @@ contract MixinExchangeWrapper is
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return totalWethSpentAmount Total amount of WETH spent on the given orders.
|
||||
/// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders.
|
||||
function _marketSellWeth(
|
||||
function _marketSellNoThrow(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 wethSellAmount,
|
||||
bytes[] memory signatures
|
||||
@@ -256,6 +258,7 @@ contract MixinExchangeWrapper is
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
|
||||
// Percentage fee
|
||||
} else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.makerAssetData)) {
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
@@ -278,6 +281,7 @@ contract MixinExchangeWrapper is
|
||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||
.safeSub(singleFillResults.takerFeePaid);
|
||||
|
||||
// Unsupported fee
|
||||
} else {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
|
||||
@@ -295,7 +299,7 @@ contract MixinExchangeWrapper is
|
||||
/// @param signatures Proofs that orders have been signed by makers.
|
||||
/// @return totalWethSpentAmount Total amount of WETH spent on the given orders.
|
||||
/// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders.
|
||||
function _marketBuyExactAmountWithWeth(
|
||||
function _marketBuyFillOrKill(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures
|
||||
|
@@ -63,53 +63,42 @@ contract MixinForwarderCore is
|
||||
/// as possible, accounting for order and forwarder fees.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
|
||||
/// @param feeRecipient Address that will receive ETH when orders are filled.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
|
||||
function marketSellOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory signatures,
|
||||
uint256 feePercentage,
|
||||
address payable feeRecipient
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount,
|
||||
uint256 ethFeePaid
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// Convert ETH to WETH.
|
||||
_convertEthToWeth();
|
||||
|
||||
// Calculate amount of WETH that won't be spent on the forwarder fee.
|
||||
uint256 wethSellAmount = LibMath.getPartialAmountFloor(
|
||||
PERCENTAGE_DENOMINATOR,
|
||||
feePercentage.safeAdd(PERCENTAGE_DENOMINATOR),
|
||||
msg.value
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
|
||||
// Spends up to wethSellAmount to fill orders, transfers purchased assets to msg.sender,
|
||||
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
|
||||
// and pays WETH order fees.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketSellWeth(
|
||||
) = _marketSellNoThrow(
|
||||
orders,
|
||||
wethSellAmount,
|
||||
wethRemaining,
|
||||
signatures
|
||||
);
|
||||
|
||||
// Transfer feePercentage of total ETH spent on orders to feeRecipient.
|
||||
// Refund remaining ETH to msg.sender.
|
||||
ethFeePaid = _transferEthFeeAndRefund(
|
||||
wethSpentAmount,
|
||||
feePercentage,
|
||||
feeRecipient
|
||||
);
|
||||
_transferEthRefund(wethRemaining, wethSpentAmount);
|
||||
}
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
@@ -119,45 +108,41 @@ contract MixinForwarderCore is
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
|
||||
/// @param feeRecipient Address that will receive ETH when orders are filled.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
|
||||
function marketBuyOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256 feePercentage,
|
||||
address payable feeRecipient
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount,
|
||||
uint256 ethFeePaid
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// Convert ETH to WETH.
|
||||
_convertEthToWeth();
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
|
||||
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketBuyExactAmountWithWeth(
|
||||
) = _marketBuyFillOrKill(
|
||||
orders,
|
||||
makerAssetBuyAmount,
|
||||
signatures
|
||||
);
|
||||
|
||||
// Transfer feePercentage of total ETH spent on orders to feeRecipient.
|
||||
// Refund remaining ETH to msg.sender.
|
||||
ethFeePaid = _transferEthFeeAndRefund(
|
||||
wethSpentAmount,
|
||||
feePercentage,
|
||||
feeRecipient
|
||||
);
|
||||
_transferEthRefund(wethRemaining, wethSpentAmount);
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
|
||||
@@ -42,39 +41,61 @@ contract MixinWeth is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Converts message call's ETH value into WETH.
|
||||
function _convertEthToWeth()
|
||||
internal
|
||||
{
|
||||
if (msg.value == 0) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.MsgValueCannotEqualZeroError());
|
||||
}
|
||||
ETHER_TOKEN.deposit.value(msg.value)();
|
||||
}
|
||||
|
||||
/// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
|
||||
/// Refunds any excess ETH to msg.sender.
|
||||
/// @param wethSpent Amount of WETH spent when filling orders.
|
||||
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
|
||||
/// @param feeRecipient Address that will receive ETH when orders are filled.
|
||||
/// @return ethFee Amount paid to feeRecipient as a percentage fee on the total WETH sold.
|
||||
function _transferEthFeeAndRefund(
|
||||
uint256 wethSpent,
|
||||
uint256 feePercentage,
|
||||
address payable feeRecipient
|
||||
/// @dev Transfers ETH denominated fees to all feeRecipient addresses
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return ethRemaining msg.value minus the amount of ETH spent on affiliate fees.
|
||||
function _transferEthFeesAndWrapRemaining(
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
internal
|
||||
returns (uint256 ethFee)
|
||||
returns (uint256 ethRemaining)
|
||||
{
|
||||
// Ensure feePercentage is less than 5%.
|
||||
if (feePercentage > MAX_FEE_PERCENTAGE) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.FeePercentageTooLargeError(
|
||||
feePercentage
|
||||
uint256 feesLen = ethFeeAmounts.length;
|
||||
// ethFeeAmounts len must equal feeRecipients len
|
||||
if (feesLen != feeRecipients.length) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.EthFeeLengthMismatchError(
|
||||
feesLen,
|
||||
feeRecipients.length
|
||||
));
|
||||
}
|
||||
|
||||
// This function is always called before any other function, so we assume that
|
||||
// the ETH remaining is the entire msg.value.
|
||||
ethRemaining = msg.value;
|
||||
|
||||
for (uint256 i = 0; i != feesLen; i++) {
|
||||
uint256 ethFeeAmount = ethFeeAmounts[i];
|
||||
// Ensure there is enough ETH to pay the fee
|
||||
if (ethRemaining < ethFeeAmount) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.InsufficientEthForFeeError(
|
||||
ethFeeAmount,
|
||||
ethRemaining
|
||||
));
|
||||
}
|
||||
// Decrease ethRemaining and transfer fee to corresponding feeRecipient
|
||||
ethRemaining = ethRemaining.safeSub(ethFeeAmount);
|
||||
feeRecipients[i].transfer(ethFeeAmount);
|
||||
}
|
||||
|
||||
// Convert remaining ETH to WETH.
|
||||
ETHER_TOKEN.deposit.value(ethRemaining)();
|
||||
|
||||
return ethRemaining;
|
||||
}
|
||||
|
||||
/// @dev Refunds any excess ETH to msg.sender.
|
||||
/// @param initialWethAmount Amount of WETH available after transferring affiliate fees.
|
||||
/// @param wethSpent Amount of WETH spent when filling orders.
|
||||
function _transferEthRefund(
|
||||
uint256 initialWethAmount,
|
||||
uint256 wethSpent
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Ensure that no extra WETH owned by this contract has been spent.
|
||||
if (wethSpent > msg.value) {
|
||||
if (wethSpent > initialWethAmount) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||
wethSpent,
|
||||
msg.value
|
||||
@@ -82,38 +103,15 @@ contract MixinWeth is
|
||||
}
|
||||
|
||||
// Calculate amount of WETH that hasn't been spent.
|
||||
uint256 wethRemaining = msg.value.safeSub(wethSpent);
|
||||
|
||||
// Calculate ETH fee to pay to feeRecipient.
|
||||
ethFee = LibMath.getPartialAmountFloor(
|
||||
feePercentage,
|
||||
PERCENTAGE_DENOMINATOR,
|
||||
wethSpent
|
||||
);
|
||||
|
||||
// Ensure fee is less than amount of WETH remaining.
|
||||
if (ethFee > wethRemaining) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.InsufficientEthForFeeError(
|
||||
ethFee,
|
||||
wethRemaining
|
||||
));
|
||||
}
|
||||
uint256 wethRemaining = initialWethAmount.safeSub(wethSpent);
|
||||
|
||||
// Do nothing if no WETH remaining
|
||||
if (wethRemaining > 0) {
|
||||
// Convert remaining WETH to ETH
|
||||
ETHER_TOKEN.withdraw(wethRemaining);
|
||||
|
||||
// Pay ETH to feeRecipient
|
||||
if (ethFee > 0) {
|
||||
feeRecipient.transfer(ethFee);
|
||||
}
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
uint256 ethRefund = wethRemaining.safeSub(ethFee);
|
||||
if (ethRefund > 0) {
|
||||
msg.sender.transfer(ethRefund);
|
||||
}
|
||||
// Transfer remaining ETH to sender
|
||||
msg.sender.transfer(wethRemaining);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,23 +29,21 @@ contract IForwarderCore {
|
||||
/// as possible, accounting for order and forwarder fees.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
|
||||
/// @param feeRecipient Address that will receive ETH when orders are filled.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
|
||||
function marketSellOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory signatures,
|
||||
uint256 feePercentage,
|
||||
address payable feeRecipient
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount,
|
||||
uint256 ethFeePaid
|
||||
uint256 makerAssetAcquiredAmount
|
||||
);
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
@@ -55,23 +53,21 @@ contract IForwarderCore {
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
|
||||
/// @param feeRecipient Address that will receive ETH when orders are filled.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
|
||||
function marketBuyOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256 feePercentage,
|
||||
address payable feeRecipient
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount,
|
||||
uint256 ethFeePaid
|
||||
uint256 makerAssetAcquiredAmount
|
||||
);
|
||||
}
|
||||
|
@@ -28,8 +28,6 @@ contract LibConstants {
|
||||
using LibBytes for bytes;
|
||||
|
||||
uint256 constant internal MAX_UINT = 2**256 - 1;
|
||||
uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
|
||||
uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
|
@@ -37,10 +37,6 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
||||
0x31360af1;
|
||||
|
||||
// bytes4(keccak256("FeePercentageTooLargeError(uint256)"))
|
||||
bytes4 internal constant FEE_PERCENTAGE_TOO_LARGE_ERROR_SELECTOR =
|
||||
0x1174fb80;
|
||||
|
||||
// bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)"))
|
||||
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
||||
0xecf40fd9;
|
||||
@@ -53,13 +49,13 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
|
||||
0x08b18698;
|
||||
|
||||
// bytes4(keccak256("MsgValueCannotEqualZeroError()"))
|
||||
bytes4 internal constant MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR =
|
||||
0x8c0e562b;
|
||||
|
||||
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
|
||||
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||
0xbaffa474;
|
||||
|
||||
// bytes4(keccak256("EthFeeLengthMismatchError(uint256,uint256)"))
|
||||
bytes4 internal constant ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR =
|
||||
0x3ecb6ceb;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function UnregisteredAssetProxyError()
|
||||
@@ -111,19 +107,6 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function FeePercentageTooLargeError(
|
||||
uint256 feePercentage
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
FEE_PERCENTAGE_TOO_LARGE_ERROR_SELECTOR,
|
||||
feePercentage
|
||||
);
|
||||
}
|
||||
|
||||
function InsufficientEthForFeeError(
|
||||
uint256 ethFeeRequired,
|
||||
uint256 ethAvailable
|
||||
@@ -167,14 +150,6 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function MsgValueCannotEqualZeroError()
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR);
|
||||
}
|
||||
|
||||
function Erc721AmountMustEqualOneError(
|
||||
uint256 amount
|
||||
)
|
||||
@@ -188,4 +163,18 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function EthFeeLengthMismatchError(
|
||||
uint256 ethFeesLength,
|
||||
uint256 feeRecipientsLength
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR,
|
||||
ethFeesLength,
|
||||
feeRecipientsLength
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,24 +52,24 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-asset-proxy": "^3.0.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-erc721": "^3.0.0",
|
||||
"@0x/contracts-exchange": "^3.0.0",
|
||||
"@0x/contracts-exchange-libs": "^4.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-asset-proxy": "^3.0.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-erc721": "^3.0.1",
|
||||
"@0x/contracts-exchange": "^3.0.1",
|
||||
"@0x/contracts-exchange-libs": "^4.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -89,7 +89,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
|
@@ -16,12 +16,10 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
hexRandom,
|
||||
hexSlice,
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, ExchangeForwarderRevertErrors } from '@0x/utils';
|
||||
import { BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestForwarderContract } from './wrappers';
|
||||
@@ -76,7 +74,7 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
erc721AssetData = assetDataEncoder.ERC721Token(erc721Token.address, nftId).getABIEncodedTransactionData();
|
||||
|
||||
bridgeAddress = randomAddress();
|
||||
bridgeData = hexRandom();
|
||||
bridgeData = hexUtils.random();
|
||||
erc20BridgeAssetData = assetDataEncoder
|
||||
.ERC20Bridge(erc20Token.address, bridgeAddress, bridgeData)
|
||||
.getABIEncodedTransactionData();
|
||||
@@ -171,12 +169,12 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
);
|
||||
});
|
||||
it('reverts if assetData is unsupported', async () => {
|
||||
const randomBytes = hexRandom();
|
||||
const randomBytes = hexUtils.random();
|
||||
const tx = forwarder
|
||||
.transferAssetToSender(randomBytes, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
const expectedError = new ExchangeForwarderRevertErrors.UnsupportedAssetProxyError(
|
||||
hexSlice(randomBytes, 0, 4),
|
||||
hexUtils.slice(randomBytes, 0, 4),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,15 +52,15 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/subproviders": "^6.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/subproviders": "^6.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -81,12 +81,12 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -3,13 +3,12 @@ import {
|
||||
constants,
|
||||
describe,
|
||||
expect,
|
||||
hexRandom,
|
||||
testCombinatoriallyWithReferenceFunc,
|
||||
uint256Values,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { SafeMathRevertErrors } from '@0x/contracts-utils';
|
||||
import { FillResults, MatchedFillResults, Order } from '@0x/types';
|
||||
import { BigNumber, LibMathRevertErrors } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, LibMathRevertErrors } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -46,9 +45,9 @@ blockchainTests('LibFillResults', env => {
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
};
|
||||
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomAssetData = () => hexRandom(36);
|
||||
const randomUint256 = () => new BigNumber(hexRandom(constants.WORD_LENGTH));
|
||||
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
const randomAssetData = () => hexUtils.random(36);
|
||||
const randomUint256 = () => new BigNumber(hexUtils.random(constants.WORD_LENGTH));
|
||||
|
||||
let libsContract: TestLibFillResultsContract;
|
||||
let makerAddressLeft: string;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { blockchainTests, constants, describe, expect, hexRandom, orderHashUtils } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, describe, expect, orderHashUtils } from '@0x/contracts-test-utils';
|
||||
import { eip712Utils } from '@0x/order-utils';
|
||||
import { Order } from '@0x/types';
|
||||
import { BigNumber, signTypedDataUtils } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -12,10 +12,10 @@ import { artifacts } from './artifacts';
|
||||
blockchainTests('LibOrder', env => {
|
||||
let libOrderContract: TestLibOrderContract;
|
||||
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexRandom(constants.WORD_LENGTH);
|
||||
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexUtils.random(constants.WORD_LENGTH);
|
||||
const randomUint256 = () => new BigNumber(randomHash());
|
||||
const randomAssetData = () => hexRandom(36);
|
||||
const randomAssetData = () => hexUtils.random(36);
|
||||
|
||||
const EMPTY_ORDER: Order = {
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
|
@@ -1,14 +1,7 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
describe,
|
||||
expect,
|
||||
hexRandom,
|
||||
transactionHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, describe, expect, transactionHashUtils } from '@0x/contracts-test-utils';
|
||||
import { eip712Utils } from '@0x/order-utils';
|
||||
import { ZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber, signTypedDataUtils } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -19,10 +12,10 @@ import { artifacts } from './artifacts';
|
||||
blockchainTests('LibZeroExTransaction', env => {
|
||||
let libZeroExTransactionContract: TestLibZeroExTransactionContract;
|
||||
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexRandom(constants.WORD_LENGTH);
|
||||
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexUtils.random(constants.WORD_LENGTH);
|
||||
const randomUint256 = () => new BigNumber(randomHash());
|
||||
const randomAssetData = () => hexRandom(36);
|
||||
const randomAssetData = () => hexUtils.random(36);
|
||||
|
||||
const EMPTY_TRANSACTION: ZeroExTransaction = {
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,21 +52,21 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-asset-proxy": "^3.0.0",
|
||||
"@0x/contracts-exchange-libs": "^4.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-multisig": "^4.0.0",
|
||||
"@0x/contracts-staking": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-asset-proxy": "^3.0.1",
|
||||
"@0x/contracts-exchange-libs": "^4.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-multisig": "^4.0.1",
|
||||
"@0x/contracts-staking": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -88,13 +88,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.0",
|
||||
"@0x/contracts-erc1155": "^2.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-erc721": "^3.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.1",
|
||||
"@0x/contracts-erc1155": "^2.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-erc721": "^3.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
|
||||
import { blockchainTests, constants, expect, hexRandom, orderHashUtils } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, expect, orderHashUtils } from '@0x/contracts-test-utils';
|
||||
import { SafeMathRevertErrors } from '@0x/contracts-utils';
|
||||
import { Order } from '@0x/types';
|
||||
import { BigNumber, ExchangeRevertErrors } from '@0x/utils';
|
||||
import { BigNumber, ExchangeRevertErrors, hexUtils } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
@@ -16,9 +16,9 @@ import {
|
||||
blockchainTests('Exchange core internal functions', env => {
|
||||
const CHAIN_ID = 1337;
|
||||
const ONE_ETHER = constants.ONE_ETHER;
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexRandom(constants.WORD_LENGTH);
|
||||
const randomAssetData = () => hexRandom(36);
|
||||
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
const randomHash = () => hexUtils.random(constants.WORD_LENGTH);
|
||||
const randomAssetData = () => hexUtils.random(36);
|
||||
let testExchange: TestExchangeInternalsContract;
|
||||
let senderAddress: string;
|
||||
const DEFAULT_PROTOCOL_MULTIPLIER = new BigNumber(150000);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { LibMathRevertErrors, ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
|
||||
import { blockchainTests, constants, expect, hexRandom } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
|
||||
import { SafeMathRevertErrors } from '@0x/contracts-utils';
|
||||
import { FillResults, OrderInfo, OrderStatus, SignatureType } from '@0x/types';
|
||||
import { BigNumber, ExchangeRevertErrors } from '@0x/utils';
|
||||
import { BigNumber, ExchangeRevertErrors, hexUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from './utils/isolated_exchange_wrapper';
|
||||
|
||||
blockchainTests('Isolated fillOrder() tests', env => {
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
const getCurrentTime = () => Math.floor(_.now() / 1000);
|
||||
const { ZERO_AMOUNT, ONE_ETHER, MAX_UINT256_ROOT } = constants;
|
||||
const ONE_DAY = 60 * 60 * 24;
|
||||
|
@@ -1,14 +1,6 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
hexRandom,
|
||||
OrderStatus,
|
||||
orderUtils,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, expect, OrderStatus, orderUtils, randomAddress } from '@0x/contracts-test-utils';
|
||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { BigNumber, ExchangeRevertErrors, RevertError } from '@0x/utils';
|
||||
import { BigNumber, ExchangeRevertErrors, hexUtils, RevertError } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
@@ -63,9 +55,9 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })
|
||||
const orderHash = orderUtils.generatePseudoRandomOrderHash();
|
||||
const signer = randomAddress();
|
||||
const validator = randomAddress();
|
||||
const data = hexRandom(ERROR_DATA_LENGTH);
|
||||
const signature = hexRandom(SIGNATURE_LENGTH);
|
||||
const errorData = hexRandom(ERROR_DATA_LENGTH);
|
||||
const data = hexUtils.random(ERROR_DATA_LENGTH);
|
||||
const signature = hexUtils.random(SIGNATURE_LENGTH);
|
||||
const errorData = hexUtils.random(ERROR_DATA_LENGTH);
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureError, [errorCode, orderHash, signer, signature]);
|
||||
createDecodeTest(ExchangeRevertErrors.SignatureValidatorNotApprovedError, [signer, validator]);
|
||||
createDecodeTest(ExchangeRevertErrors.EIP1271SignatureError, [validator, data, signature, errorData]);
|
||||
@@ -114,7 +106,7 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })
|
||||
(() => {
|
||||
const assetProxyAddress = randomAddress();
|
||||
createDecodeTest(ExchangeRevertErrors.AssetProxyExistsError, [
|
||||
hexRandom(ASSET_PROXY_ID_LENGTH),
|
||||
hexUtils.random(ASSET_PROXY_ID_LENGTH),
|
||||
assetProxyAddress,
|
||||
]);
|
||||
})();
|
||||
@@ -122,14 +114,14 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })
|
||||
(() => {
|
||||
const errorCode = ExchangeRevertErrors.AssetProxyDispatchErrorCode.UnknownAssetProxy;
|
||||
const orderHash = orderUtils.generatePseudoRandomOrderHash();
|
||||
const assetData = hexRandom(ASSET_DATA_LENGTH);
|
||||
const assetData = hexUtils.random(ASSET_DATA_LENGTH);
|
||||
createDecodeTest(ExchangeRevertErrors.AssetProxyDispatchError, [errorCode, orderHash, assetData]);
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const orderHash = orderUtils.generatePseudoRandomOrderHash();
|
||||
const assetData = hexRandom(ASSET_DATA_LENGTH);
|
||||
const errorData = hexRandom(ERROR_DATA_LENGTH);
|
||||
const assetData = hexUtils.random(ASSET_DATA_LENGTH);
|
||||
const errorData = hexUtils.random(ERROR_DATA_LENGTH);
|
||||
createDecodeTest(ExchangeRevertErrors.AssetProxyTransferError, [orderHash, assetData, errorData]);
|
||||
})();
|
||||
|
||||
@@ -147,14 +139,14 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults })
|
||||
|
||||
(() => {
|
||||
const transactionHash = orderUtils.generatePseudoRandomOrderHash();
|
||||
const errorData = hexRandom(ERROR_DATA_LENGTH);
|
||||
const errorData = hexUtils.random(ERROR_DATA_LENGTH);
|
||||
createDecodeTest(ExchangeRevertErrors.TransactionExecutionError, [transactionHash, errorData]);
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const errorCode = ExchangeRevertErrors.IncompleteFillErrorCode.IncompleteMarketSellOrders;
|
||||
const expectedAmount = new BigNumber(hexRandom(WORD_LENGTH));
|
||||
const actualAmount = new BigNumber(hexRandom(WORD_LENGTH));
|
||||
const expectedAmount = new BigNumber(hexUtils.random(WORD_LENGTH));
|
||||
const actualAmount = new BigNumber(hexUtils.random(WORD_LENGTH));
|
||||
createDecodeTest(ExchangeRevertErrors.IncompleteFillError, [errorCode, expectedAmount, actualAmount]);
|
||||
})();
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { blockchainTests, constants, describe, expect, hexRandom } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { blockchainTests, constants, describe, expect } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { DataItem, MethodAbi, TupleDataItem } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -47,11 +47,11 @@ blockchainTests.resets('Reentrancy Tests', env => {
|
||||
}
|
||||
// Handle bytes.
|
||||
if (item.type === 'bytes') {
|
||||
return hexRandom(36);
|
||||
return hexUtils.random(36);
|
||||
}
|
||||
// Handle addresses.
|
||||
if (item.type === 'address') {
|
||||
return hexRandom(constants.ADDRESS_LENGTH);
|
||||
return hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
}
|
||||
// Handle bools.
|
||||
if (item.type === 'bool') {
|
||||
@@ -84,7 +84,7 @@ blockchainTests.resets('Reentrancy Tests', env => {
|
||||
m = /^bytes(\d+)$/.exec(item.type);
|
||||
if (m) {
|
||||
const size = parseInt(m[1], 10) || 32;
|
||||
return hexRandom(size);
|
||||
return hexUtils.random(size);
|
||||
}
|
||||
throw new Error(`Unhandled input type: ${item.type}`);
|
||||
}
|
||||
|
@@ -5,8 +5,6 @@ import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
hexConcat,
|
||||
hexRandom,
|
||||
LogDecoder,
|
||||
OrderFactory,
|
||||
orderHashUtils,
|
||||
@@ -16,7 +14,7 @@ import {
|
||||
transactionHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { SignatureType, SignedOrder, SignedZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber, ExchangeRevertErrors, StringRevertError } from '@0x/utils';
|
||||
import { BigNumber, ExchangeRevertErrors, hexUtils, StringRevertError } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import ethUtil = require('ethereumjs-util');
|
||||
|
||||
@@ -89,11 +87,11 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
const SIGNATURE_LENGTH = 65;
|
||||
const generateRandomSignature = (): string => hexRandom(SIGNATURE_LENGTH);
|
||||
const generateRandomSignature = (): string => hexUtils.random(SIGNATURE_LENGTH);
|
||||
const hashBytes = (bytesHex: string): string => ethUtil.bufferToHex(ethUtil.sha3(ethUtil.toBuffer(bytesHex)));
|
||||
const signDataHex = (dataHex: string, privateKey: Buffer): string => {
|
||||
const ecSignature = ethUtil.ecsign(ethUtil.toBuffer(dataHex), privateKey);
|
||||
return hexConcat(ecSignature.v, ecSignature.r, ecSignature.s);
|
||||
return hexUtils.concat(ecSignature.v, ecSignature.r, ecSignature.s);
|
||||
};
|
||||
|
||||
type ValidateHashSignatureAsync = (
|
||||
@@ -123,7 +121,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when signature type is unsupported', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(SignatureType.NSignatureTypes);
|
||||
const signatureHex = hexUtils.concat(SignatureType.NSignatureTypes);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.Unsupported,
|
||||
hashHex,
|
||||
@@ -136,7 +134,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when SignatureType=Illegal', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(SignatureType.Illegal);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Illegal);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.Illegal,
|
||||
hashHex,
|
||||
@@ -149,14 +147,14 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should return false when SignatureType=Invalid and signature has a length of zero', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(SignatureType.Invalid);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Invalid);
|
||||
const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
|
||||
it('should revert when SignatureType=Invalid and signature length is non-zero', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat('0xdeadbeef', SignatureType.Invalid);
|
||||
const signatureHex = hexUtils.concat('0xdeadbeef', SignatureType.Invalid);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
|
||||
hashHex,
|
||||
@@ -169,14 +167,14 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should return true when SignatureType=EIP712 and signature is valid', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(signDataHex(hashHex, signerPrivateKey), SignatureType.EIP712);
|
||||
const signatureHex = hexUtils.concat(signDataHex(hashHex, signerPrivateKey), SignatureType.EIP712);
|
||||
const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=EIP712 and signature is invalid', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.EIP712);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP712);
|
||||
const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
@@ -187,7 +185,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
const orderHashWithEthSignPrefixHex = ethUtil.bufferToHex(
|
||||
ethUtil.hashPersonalMessage(ethUtil.toBuffer(hashHex)),
|
||||
);
|
||||
const signatureHex = hexConcat(
|
||||
const signatureHex = hexUtils.concat(
|
||||
signDataHex(orderHashWithEthSignPrefixHex, signerPrivateKey),
|
||||
SignatureType.EthSign,
|
||||
);
|
||||
@@ -198,7 +196,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
it('should return false when SignatureType=EthSign and signature is invalid', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
// Create EthSign signature
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.EthSign);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EthSign);
|
||||
const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
@@ -208,7 +206,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.Wallet);
|
||||
const isValidSignature = await validateAsync(
|
||||
hashHex,
|
||||
validatorWallet.address,
|
||||
@@ -225,7 +223,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const notSignatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(notSignatureDataHex, SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(notSignatureDataHex, SignatureType.Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
hashHex,
|
||||
@@ -241,7 +239,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
const hashHex = getCurrentHashHex(validatorWallet.address);
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.Wallet);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletError(
|
||||
hashHex,
|
||||
validatorWallet.address,
|
||||
@@ -254,7 +252,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when signer is an EOA and SignatureType=Wallet', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Wallet);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletError(
|
||||
hashHex,
|
||||
signerAddress,
|
||||
@@ -267,7 +265,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should return false when validator returns `true` and SignatureType=Wallet', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Wallet);
|
||||
const isValidSignature = await validateAsync(
|
||||
hashHex,
|
||||
validatorWallet.address,
|
||||
@@ -279,7 +277,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when validator returns nothing and SignatureType=Wallet', async () => {
|
||||
const hashHex = getCurrentHashHex(validatorWallet.address);
|
||||
const signatureHex = hexConcat(SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Wallet);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletError(
|
||||
hashHex,
|
||||
validatorWallet.address,
|
||||
@@ -299,7 +297,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
const hashHex = getCurrentHashHex(validatorWallet.address);
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.Wallet);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureWalletError(
|
||||
hashHex,
|
||||
validatorWallet.address,
|
||||
@@ -315,14 +313,14 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Presign the hash
|
||||
await exchange.preSign(hashHex).awaitTransactionSuccessAsync({ from: signerAddress });
|
||||
// Validate presigned signature
|
||||
const signatureHex = hexConcat(SignatureType.PreSigned);
|
||||
const signatureHex = hexUtils.concat(SignatureType.PreSigned);
|
||||
const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex);
|
||||
expect(isValidSignature).to.be.true();
|
||||
});
|
||||
|
||||
it('should return false when SignatureType=Presigned and signer has not presigned hash', async () => {
|
||||
const hashHex = getCurrentHashHex();
|
||||
const signatureHex = hexConcat(SignatureType.PreSigned);
|
||||
const signatureHex = hexUtils.concat(SignatureType.PreSigned);
|
||||
const isValidSignature = await validateAsync(hashHex, signerAddress, signatureHex);
|
||||
expect(isValidSignature).to.be.false();
|
||||
});
|
||||
@@ -355,7 +353,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
};
|
||||
|
||||
it('should revert when signerAddress == 0', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP712);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP712);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InvalidSigner,
|
||||
hashHex,
|
||||
@@ -367,7 +365,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert when SignatureType=Validator', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Validator);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InappropriateSignatureType,
|
||||
hashHex,
|
||||
@@ -379,7 +377,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert when SignatureType=EIP1271Wallet', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InappropriateSignatureType,
|
||||
hashHex,
|
||||
@@ -466,7 +464,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
};
|
||||
|
||||
it('should revert when signerAddress == 0', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP712);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP712);
|
||||
const nullMakerOrder = {
|
||||
...signedOrder,
|
||||
makerAddress: constants.NULL_ADDRESS,
|
||||
@@ -486,7 +484,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const isValidSignature = await validateAsync(
|
||||
signedOrder,
|
||||
signatureHex,
|
||||
@@ -501,7 +499,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const notSignatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(notSignatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(notSignatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const isValidSignature = await validateAsync(
|
||||
signedOrder,
|
||||
signatureHex,
|
||||
@@ -513,7 +511,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should return false when validator returns `true` and SignatureType=Validator', async () => {
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const isValidSignature = await validateAsync(
|
||||
signedOrder,
|
||||
signatureHex,
|
||||
@@ -525,7 +523,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when validator returns nothing and SignatureType=Validator', async () => {
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -542,7 +540,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -559,7 +557,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -579,7 +577,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
.awaitTransactionSuccessAsync({ from: signedOrder.makerAddress });
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Validator);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
|
||||
@@ -599,7 +597,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureValidatorNotApprovedError(
|
||||
signedOrder.makerAddress,
|
||||
validatorWallet.address,
|
||||
@@ -613,7 +611,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
signedOrder,
|
||||
@@ -630,7 +628,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const notSignatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(notSignatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(notSignatureDataHex, SignatureType.EIP1271Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
signedOrder,
|
||||
@@ -644,7 +642,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
it('should return false when validator returns `true` and SignatureType=EIP1271Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
signedOrder,
|
||||
@@ -658,7 +656,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
it('should revert when validator returns nothing and SignatureType=EIP1271Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -675,7 +673,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP1271Wallet);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -690,7 +688,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when validator reverts and SignatureType=EIP1271Wallet', async () => {
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
const signatureHex = hexConcat(SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -704,7 +702,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert when signer is an EOA and SignatureType=EIP1271Wallet', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet);
|
||||
signedOrder.makerAddress = notSignerAddress;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
@@ -719,7 +717,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert when signer is an EOA and SignatureType=Validator', async () => {
|
||||
const signatureHex = hexConcat(notSignerAddress, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(notSignerAddress, SignatureType.Validator);
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
const data = eip1271Data.OrderWithHash(signedOrder, orderHashHex).getABIEncodedTransactionData();
|
||||
const expectedError = new ExchangeRevertErrors.EIP1271SignatureError(
|
||||
@@ -766,7 +764,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// We don't actually do anything with the transaction so we can just
|
||||
// fill it with random data.
|
||||
signedTransaction = await transactionFactory.newSignedTransactionAsync({
|
||||
data: hexRandom(TRANSACTION_DATA_LENGTH),
|
||||
data: hexUtils.random(TRANSACTION_DATA_LENGTH),
|
||||
});
|
||||
});
|
||||
|
||||
@@ -790,7 +788,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
};
|
||||
|
||||
it('should revert when signerAddress == 0', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP712);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP712);
|
||||
const nullSignerTransaction = {
|
||||
...signedTransaction,
|
||||
signerAddress: constants.NULL_ADDRESS,
|
||||
@@ -810,7 +808,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const isValidSignature = await validateAsync(
|
||||
signedTransaction,
|
||||
signatureHex,
|
||||
@@ -825,7 +823,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const notSignatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(notSignatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(notSignatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const isValidSignature = await validateAsync(
|
||||
signedTransaction,
|
||||
signatureHex,
|
||||
@@ -837,7 +835,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should return false when validator returns `true` and SignatureType=Validator', async () => {
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const isValidSignature = await validateAsync(
|
||||
signedTransaction,
|
||||
signatureHex,
|
||||
@@ -854,7 +852,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
.awaitTransactionSuccessAsync({ from: signedTransaction.signerAddress });
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Validator);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
|
||||
@@ -868,7 +866,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
|
||||
it('should revert when validator returns nothing and SignatureType=Validator', async () => {
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -892,7 +890,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -911,7 +909,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -934,7 +932,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, validatorWallet.address, SignatureType.Validator);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureValidatorNotApprovedError(
|
||||
signedTransaction.signerAddress,
|
||||
validatorWallet.address,
|
||||
@@ -948,7 +946,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
signedTransaction,
|
||||
@@ -965,7 +963,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
// just does a hash comparison.
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const notSignatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(notSignatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(notSignatureDataHex, SignatureType.EIP1271Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
signedTransaction,
|
||||
@@ -979,7 +977,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
it('should return false when validator returns `true` and SignatureType=EIP1271Wallet', async () => {
|
||||
signedTransaction.signerAddress = validatorWallet.address;
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
// Validate signature
|
||||
const isValidSignature = await validateAsync(
|
||||
signedTransaction,
|
||||
@@ -993,7 +991,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
it('should revert when validator returns nothing and SignatureType=EIP1271Wallet', async () => {
|
||||
signedTransaction.signerAddress = validatorWallet.address;
|
||||
const signatureDataHex = generateRandomSignature();
|
||||
const signatureHex = hexConcat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(signatureDataHex, SignatureType.EIP1271Wallet);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -1017,7 +1015,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
signedTransaction.signerAddress = validatorWallet.address;
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP1271Wallet);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -1036,7 +1034,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
signedTransaction.signerAddress = validatorWallet.address;
|
||||
// Doesn't have to contain a real signature since our wallet contract
|
||||
// just does a hash comparison.
|
||||
const signatureHex = hexConcat(generateRandomSignature(), SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(generateRandomSignature(), SignatureType.EIP1271Wallet);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -1052,7 +1050,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert when signer is an EOA and SignatureType=EIP1271Wallet', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -1068,7 +1066,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert when signer is an EOA and SignatureType=Validator', async () => {
|
||||
const signatureHex = hexConcat(notSignerAddress, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(notSignerAddress, SignatureType.Validator);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(signedTransaction);
|
||||
const data = eip1271Data
|
||||
.ZeroExTransactionWithHash(signedTransaction, transactionHashHex)
|
||||
@@ -1206,7 +1204,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert if `Validator` signature type rejects during a second fill', async () => {
|
||||
const signatureHex = hexConcat(validatorWallet.address, SignatureType.Validator);
|
||||
const signatureHex = hexUtils.concat(validatorWallet.address, SignatureType.Validator);
|
||||
signedOrder.signature = signatureHex;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
// Allow the signature check for the first fill.
|
||||
@@ -1234,7 +1232,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert if `Wallet` signature type rejects during a second fill', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.Wallet);
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
signedOrder.signature = signatureHex;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
@@ -1263,7 +1261,7 @@ blockchainTests.resets('MixinSignatureValidator', env => {
|
||||
});
|
||||
|
||||
it('should revert if `EIP1271Wallet` signature type rejects during a second fill', async () => {
|
||||
const signatureHex = hexConcat(SignatureType.EIP1271Wallet);
|
||||
const signatureHex = hexUtils.concat(SignatureType.EIP1271Wallet);
|
||||
signedOrder.makerAddress = validatorWallet.address;
|
||||
signedOrder.signature = signatureHex;
|
||||
const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder);
|
||||
|
@@ -1,996 +0,0 @@
|
||||
// tslint:disable: max-file-line-count
|
||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
|
||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
describe,
|
||||
ExchangeFunctionName,
|
||||
expect,
|
||||
getLatestBlockTimestampAsync,
|
||||
OrderFactory,
|
||||
orderHashUtils,
|
||||
TransactionFactory,
|
||||
transactionHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { FillResults, OrderStatus } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, ExchangeRevertErrors } from '@0x/utils';
|
||||
import { LogWithDecodedArgs, MethodAbi } from 'ethereum-types';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { exchangeDataEncoder } from '../src/exchange_data_encoder';
|
||||
|
||||
import { artifacts as localArtifacts } from './artifacts';
|
||||
import { ExchangeWrapper } from './utils/exchange_wrapper';
|
||||
import {
|
||||
ExchangeCancelEventArgs,
|
||||
ExchangeCancelUpToEventArgs,
|
||||
ExchangeContract,
|
||||
ExchangeFillEventArgs,
|
||||
ExchangeSignatureValidatorApprovalEventArgs,
|
||||
ExchangeTransactionExecutionEventArgs,
|
||||
} from './wrappers';
|
||||
|
||||
const artifacts = { ...erc20Artifacts, ...localArtifacts };
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
blockchainTests.resets('Exchange transactions', env => {
|
||||
let chainId: number;
|
||||
let senderAddress: string;
|
||||
let owner: string;
|
||||
let makerAddress: string;
|
||||
let takerAddress: string;
|
||||
let feeRecipientAddress: string;
|
||||
let validatorAddress: string;
|
||||
let taker2Address: string;
|
||||
|
||||
let erc20TokenA: DummyERC20TokenContract;
|
||||
let erc20TokenB: DummyERC20TokenContract;
|
||||
let takerFeeToken: DummyERC20TokenContract;
|
||||
let makerFeeToken: DummyERC20TokenContract;
|
||||
let exchangeInstance: ExchangeContract;
|
||||
let erc20Proxy: ERC20ProxyContract;
|
||||
|
||||
let orderFactory: OrderFactory;
|
||||
let makerTransactionFactory: TransactionFactory;
|
||||
let takerTransactionFactory: TransactionFactory;
|
||||
let taker2TransactionFactory: TransactionFactory;
|
||||
let exchangeWrapper: ExchangeWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
|
||||
let defaultMakerTokenAddress: string;
|
||||
let defaultTakerTokenAddress: string;
|
||||
let defaultMakerFeeTokenAddress: string;
|
||||
let defaultTakerFeeTokenAddress: string;
|
||||
let makerPrivateKey: Buffer;
|
||||
let takerPrivateKey: Buffer;
|
||||
let taker2PrivateKey: Buffer;
|
||||
|
||||
const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, env.provider, env.txDefaults);
|
||||
before(async () => {
|
||||
chainId = await env.getChainIdAsync();
|
||||
const accounts = await env.getAccountAddressesAsync();
|
||||
const usedAddresses = ([
|
||||
owner,
|
||||
senderAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
feeRecipientAddress,
|
||||
validatorAddress,
|
||||
taker2Address,
|
||||
] = _.slice(accounts, 0, 7));
|
||||
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, usedAddresses, owner);
|
||||
|
||||
const numDummyErc20ToDeploy = 4;
|
||||
[erc20TokenA, erc20TokenB, takerFeeToken, makerFeeToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
numDummyErc20ToDeploy,
|
||||
constants.DUMMY_TOKEN_DECIMALS,
|
||||
);
|
||||
erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
|
||||
exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Exchange,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
|
||||
await erc20Proxy.addAuthorizedAddress(exchangeInstance.address).awaitTransactionSuccessAsync({ from: owner });
|
||||
|
||||
defaultMakerTokenAddress = erc20TokenA.address;
|
||||
defaultTakerTokenAddress = erc20TokenB.address;
|
||||
defaultMakerFeeTokenAddress = makerFeeToken.address;
|
||||
defaultTakerFeeTokenAddress = takerFeeToken.address;
|
||||
|
||||
const defaultOrderParams = {
|
||||
...constants.STATIC_ORDER_PARAMS,
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
makerAssetData: await devUtils.encodeERC20AssetData(defaultMakerTokenAddress).callAsync(),
|
||||
takerAssetData: await devUtils.encodeERC20AssetData(defaultTakerTokenAddress).callAsync(),
|
||||
makerFeeAssetData: await devUtils.encodeERC20AssetData(defaultMakerFeeTokenAddress).callAsync(),
|
||||
takerFeeAssetData: await devUtils.encodeERC20AssetData(defaultTakerFeeTokenAddress).callAsync(),
|
||||
exchangeAddress: exchangeInstance.address,
|
||||
chainId,
|
||||
};
|
||||
makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
taker2PrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(taker2Address)];
|
||||
orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
|
||||
makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchangeInstance.address, chainId);
|
||||
takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchangeInstance.address, chainId);
|
||||
taker2TransactionFactory = new TransactionFactory(taker2PrivateKey, exchangeInstance.address, chainId);
|
||||
});
|
||||
describe('executeTransaction', () => {
|
||||
describe('general functionality', () => {
|
||||
it('should log the correct transactionHash if successfully executed', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, takerAddress);
|
||||
const transactionExecutionLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeTransactionExecutionEventArgs>).event ===
|
||||
'TransactionExecution',
|
||||
);
|
||||
expect(transactionExecutionLogs.length).to.eq(1);
|
||||
const executionLogArgs = (transactionExecutionLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(executionLogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction),
|
||||
);
|
||||
});
|
||||
it('should revert if the transaction is expired', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, orders);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({
|
||||
data,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
transactionHashHex,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if the actual gasPrice is greater than expected', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({
|
||||
data,
|
||||
});
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const actualGasPrice = transaction.gasPrice.plus(1);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionGasPriceError(
|
||||
transactionHashHex,
|
||||
actualGasPrice,
|
||||
transaction.gasPrice,
|
||||
);
|
||||
const tx = exchangeInstance
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.sendTransactionAsync({ gasPrice: actualGasPrice, from: senderAddress });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if the actual gasPrice is less than expected', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({
|
||||
data,
|
||||
});
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const actualGasPrice = transaction.gasPrice.minus(1);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionGasPriceError(
|
||||
transactionHashHex,
|
||||
actualGasPrice,
|
||||
transaction.gasPrice,
|
||||
);
|
||||
const tx = exchangeInstance
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.sendTransactionAsync({ gasPrice: actualGasPrice, from: senderAddress });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
describe('fill methods', () => {
|
||||
for (const fnName of [
|
||||
...constants.SINGLE_FILL_FN_NAMES,
|
||||
...constants.BATCH_FILL_FN_NAMES,
|
||||
...constants.MARKET_FILL_FN_NAMES,
|
||||
]) {
|
||||
it(`${fnName} should revert if signature is invalid and not called by signer`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const v = ethUtil.toBuffer(transaction.signature.slice(0, 4));
|
||||
const invalidR = ethUtil.sha3('invalidR');
|
||||
const invalidS = ethUtil.sha3('invalidS');
|
||||
const signatureType = ethUtil.toBuffer(`0x${transaction.signature.slice(-2)}`);
|
||||
const invalidSigBuff = Buffer.concat([v, invalidR, invalidS, signatureType]);
|
||||
const invalidSigHex = `0x${invalidSigBuff.toString('hex')}`;
|
||||
transaction.signature = invalidSigHex;
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.BadTransactionSignature,
|
||||
transactionHashHex,
|
||||
transaction.signerAddress,
|
||||
transaction.signature,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should be successful if signed by taker and called by sender`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(
|
||||
transaction,
|
||||
senderAddress,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(1);
|
||||
const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
it(`${fnName} should be successful if called by taker without a transaction signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, takerAddress);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(1);
|
||||
const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
it(`${fnName} should return the correct data if successful`, async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const returnData = await exchangeInstance
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.callAsync({
|
||||
from: senderAddress,
|
||||
});
|
||||
const abi = artifacts.Exchange.compilerOutput.abi;
|
||||
const methodAbi = abi.filter(abiItem => (abiItem as MethodAbi).name === fnName)[0] as MethodAbi;
|
||||
const abiEncoder = new AbiEncoder.Method(methodAbi);
|
||||
|
||||
const decodedReturnData = abiEncoder.decodeReturnValues(returnData);
|
||||
const fillResults =
|
||||
constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1
|
||||
? decodedReturnData.fillResults[0]
|
||||
: decodedReturnData.fillResults;
|
||||
|
||||
expect(fillResults.makerAssetFilledAmount).to.be.bignumber.eq(order.makerAssetAmount);
|
||||
expect(fillResults.takerAssetFilledAmount).to.be.bignumber.eq(order.takerAssetAmount);
|
||||
expect(fillResults.makerFeePaid).to.be.bignumber.eq(order.makerFee);
|
||||
expect(fillResults.takerFeePaid).to.be.bignumber.eq(order.takerFee);
|
||||
});
|
||||
it(`${fnName} should revert if transaction has already been executed`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
await exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted,
|
||||
transactionHashHex,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should revert and rethrow error if executeTransaction is called recursively with a signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const recursiveData = exchangeInstance
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await takerTransactionFactory.newSignedTransactionAsync({
|
||||
data: recursiveData,
|
||||
});
|
||||
const recursiveTransactionHashHex = transactionHashUtils.getTransactionHashHex(
|
||||
recursiveTransaction,
|
||||
);
|
||||
const noReentrancyError = new ExchangeRevertErrors.TransactionInvalidContextError(
|
||||
transactionHashHex,
|
||||
transaction.signerAddress,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
recursiveTransactionHashHex,
|
||||
noReentrancyError,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(recursiveTransaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should be successful if executeTransaction is called recursively by taker without a signature`, async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const recursiveData = exchangeInstance
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await takerTransactionFactory.newSignedTransactionAsync({
|
||||
data: recursiveData,
|
||||
});
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(
|
||||
recursiveTransaction,
|
||||
takerAddress,
|
||||
);
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(1);
|
||||
const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
if (
|
||||
[
|
||||
ExchangeFunctionName.FillOrderNoThrow,
|
||||
ExchangeFunctionName.BatchFillOrdersNoThrow,
|
||||
ExchangeFunctionName.MarketBuyOrdersNoThrow,
|
||||
ExchangeFunctionName.MarketSellOrdersNoThrow,
|
||||
ExchangeFunctionName.MarketBuyOrdersFillOrKill,
|
||||
ExchangeFunctionName.MarketSellOrdersFillOrKill,
|
||||
].indexOf(fnName) === -1
|
||||
) {
|
||||
it(`${fnName} should revert and rethrow error if the underlying function reverts`, async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
order.signature = constants.NULL_BYTES;
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const nestedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAddress,
|
||||
order.signature,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
describe('cancelOrder', () => {
|
||||
it('should revert if not signed by or called by maker', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orders = [order];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const nestedError = new ExchangeRevertErrors.ExchangeInvalidContextError(
|
||||
ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker,
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
takerAddress,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should be successful if signed by maker and called by sender', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
it('should be successful if called by maker without a signature', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, orders);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, makerAddress);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
|
||||
});
|
||||
});
|
||||
describe('batchCancelOrders', () => {
|
||||
it('should revert if not signed by or called by maker', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
orders,
|
||||
);
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const nestedError = new ExchangeRevertErrors.ExchangeInvalidContextError(
|
||||
ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker,
|
||||
orderHashUtils.getOrderHashHex(orders[0]),
|
||||
takerAddress,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
);
|
||||
const tx = exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should be successful if signed by maker and called by sender', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
orders,
|
||||
);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(orders.length);
|
||||
orders.forEach((order, index) => {
|
||||
const cancelLogArgs = (cancelLogs[index] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
|
||||
});
|
||||
});
|
||||
it('should be successful if called by maker without a signature', async () => {
|
||||
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
orders,
|
||||
);
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, makerAddress);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(orders.length);
|
||||
orders.forEach((order, index) => {
|
||||
const cancelLogArgs = (cancelLogs[index] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(order.makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(order.takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('cancelOrdersUpTo', () => {
|
||||
it('should be successful if signed by maker and called by sender', async () => {
|
||||
const targetEpoch = constants.ZERO_AMOUNT;
|
||||
const data = exchangeInstance.cancelOrdersUpTo(targetEpoch).getABIEncodedTransactionData();
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).event === 'CancelUpTo',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.orderSenderAddress).to.eq(senderAddress);
|
||||
expect(cancelLogArgs.orderEpoch).to.bignumber.eq(targetEpoch.plus(1));
|
||||
});
|
||||
it('should be successful if called by maker without a signature', async () => {
|
||||
const targetEpoch = constants.ZERO_AMOUNT;
|
||||
const data = exchangeInstance.cancelOrdersUpTo(targetEpoch).getABIEncodedTransactionData();
|
||||
const transaction = await makerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, makerAddress);
|
||||
const cancelLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).event === 'CancelUpTo',
|
||||
);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.orderSenderAddress).to.eq(constants.NULL_ADDRESS);
|
||||
expect(cancelLogArgs.orderEpoch).to.bignumber.eq(targetEpoch.plus(1));
|
||||
});
|
||||
});
|
||||
describe('preSign', () => {
|
||||
it('should preSign a hash for the signer', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orderHash = orderHashUtils.getOrderHashHex(order);
|
||||
const data = exchangeInstance.preSign(orderHash).getABIEncodedTransactionData();
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
let isPreSigned = await exchangeInstance.preSigned(orderHash, takerAddress).callAsync();
|
||||
expect(isPreSigned).to.be.eq(false);
|
||||
await exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
isPreSigned = await exchangeInstance.preSigned(orderHash, takerAddress).callAsync();
|
||||
expect(isPreSigned).to.be.eq(true);
|
||||
});
|
||||
it('should preSign a hash for the caller if called without a signature', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const orderHash = orderHashUtils.getOrderHashHex(order);
|
||||
const data = exchangeInstance.preSign(orderHash).getABIEncodedTransactionData();
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = constants.NULL_BYTES;
|
||||
let isPreSigned = await exchangeInstance.preSigned(orderHash, takerAddress).callAsync();
|
||||
expect(isPreSigned).to.be.eq(false);
|
||||
await exchangeWrapper.executeTransactionAsync(transaction, takerAddress);
|
||||
isPreSigned = await exchangeInstance.preSigned(orderHash, takerAddress).callAsync();
|
||||
expect(isPreSigned).to.be.eq(true);
|
||||
});
|
||||
});
|
||||
describe('setSignatureValidatorApproval', () => {
|
||||
it('should approve a validator for the signer', async () => {
|
||||
const shouldApprove = true;
|
||||
const data = exchangeInstance
|
||||
.setSignatureValidatorApproval(validatorAddress, shouldApprove)
|
||||
.getABIEncodedTransactionData();
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, senderAddress);
|
||||
const validatorApprovalLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeSignatureValidatorApprovalEventArgs>).event ===
|
||||
'SignatureValidatorApproval',
|
||||
);
|
||||
expect(validatorApprovalLogs.length).to.eq(1);
|
||||
const validatorApprovalLogArgs = (validatorApprovalLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeSignatureValidatorApprovalEventArgs
|
||||
>).args;
|
||||
expect(validatorApprovalLogArgs.signerAddress).to.eq(takerAddress);
|
||||
expect(validatorApprovalLogArgs.validatorAddress).to.eq(validatorAddress);
|
||||
expect(validatorApprovalLogArgs.isApproved).to.eq(shouldApprove);
|
||||
});
|
||||
it('should approve a validator for the caller if called with no signature', async () => {
|
||||
const shouldApprove = true;
|
||||
const data = exchangeInstance
|
||||
.setSignatureValidatorApproval(validatorAddress, shouldApprove)
|
||||
.getABIEncodedTransactionData();
|
||||
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
|
||||
transaction.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await exchangeWrapper.executeTransactionAsync(transaction, takerAddress);
|
||||
const validatorApprovalLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeSignatureValidatorApprovalEventArgs>).event ===
|
||||
'SignatureValidatorApproval',
|
||||
);
|
||||
expect(validatorApprovalLogs.length).to.eq(1);
|
||||
const validatorApprovalLogArgs = (validatorApprovalLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeSignatureValidatorApprovalEventArgs
|
||||
>).args;
|
||||
expect(validatorApprovalLogArgs.signerAddress).to.eq(takerAddress);
|
||||
expect(validatorApprovalLogArgs.validatorAddress).to.eq(validatorAddress);
|
||||
expect(validatorApprovalLogArgs.isApproved).to.eq(shouldApprove);
|
||||
});
|
||||
});
|
||||
describe('batchExecuteTransactions', () => {
|
||||
it('should successfully call fillOrder via 2 transactions with different taker signatures', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await taker2TransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
const transactionReceipt = await exchangeWrapper.batchExecuteTransactionsAsync(
|
||||
[transaction1, transaction2],
|
||||
senderAddress,
|
||||
);
|
||||
|
||||
const transactionExecutionLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeTransactionExecutionEventArgs>).event ===
|
||||
'TransactionExecution',
|
||||
);
|
||||
expect(transactionExecutionLogs.length).to.eq(2);
|
||||
|
||||
const execution1LogArgs = (transactionExecutionLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution1LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction1),
|
||||
);
|
||||
|
||||
const execution2LogArgs = (transactionExecutionLogs[1] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution2LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
);
|
||||
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(2);
|
||||
|
||||
const fill1LogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fill1LogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fill1LogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fill1LogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(fill1LogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fill1LogArgs.makerAssetData).to.eq(order1.makerAssetData);
|
||||
expect(fill1LogArgs.takerAssetData).to.eq(order1.takerAssetData);
|
||||
expect(fill1LogArgs.makerAssetFilledAmount).to.bignumber.eq(order1.makerAssetAmount);
|
||||
expect(fill1LogArgs.takerAssetFilledAmount).to.bignumber.eq(order1.takerAssetAmount);
|
||||
expect(fill1LogArgs.makerFeePaid).to.bignumber.eq(order1.makerFee);
|
||||
expect(fill1LogArgs.takerFeePaid).to.bignumber.eq(order1.takerFee);
|
||||
expect(fill1LogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order1));
|
||||
|
||||
const fill2LogArgs = (fillLogs[1] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fill2LogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fill2LogArgs.takerAddress).to.eq(taker2Address);
|
||||
expect(fill2LogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(fill2LogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fill2LogArgs.makerAssetData).to.eq(order2.makerAssetData);
|
||||
expect(fill2LogArgs.takerAssetData).to.eq(order2.takerAssetData);
|
||||
expect(fill2LogArgs.makerAssetFilledAmount).to.bignumber.eq(order2.makerAssetAmount);
|
||||
expect(fill2LogArgs.takerAssetFilledAmount).to.bignumber.eq(order2.takerAssetAmount);
|
||||
expect(fill2LogArgs.makerFeePaid).to.bignumber.eq(order2.makerFee);
|
||||
expect(fill2LogArgs.takerFeePaid).to.bignumber.eq(order2.takerFee);
|
||||
expect(fill2LogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order2));
|
||||
});
|
||||
it('should successfully call fillOrder via 2 transactions when called by taker with no signatures', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takerTransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
transaction1.signature = constants.NULL_BYTES;
|
||||
transaction2.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await exchangeWrapper.batchExecuteTransactionsAsync(
|
||||
[transaction1, transaction2],
|
||||
takerAddress,
|
||||
);
|
||||
|
||||
const transactionExecutionLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeTransactionExecutionEventArgs>).event ===
|
||||
'TransactionExecution',
|
||||
);
|
||||
expect(transactionExecutionLogs.length).to.eq(2);
|
||||
|
||||
const execution1LogArgs = (transactionExecutionLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution1LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction1),
|
||||
);
|
||||
|
||||
const execution2LogArgs = (transactionExecutionLogs[1] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution2LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
);
|
||||
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(2);
|
||||
|
||||
const fill1LogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fill1LogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fill1LogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fill1LogArgs.senderAddress).to.eq(takerAddress);
|
||||
expect(fill1LogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fill1LogArgs.makerAssetData).to.eq(order1.makerAssetData);
|
||||
expect(fill1LogArgs.takerAssetData).to.eq(order1.takerAssetData);
|
||||
expect(fill1LogArgs.makerAssetFilledAmount).to.bignumber.eq(order1.makerAssetAmount);
|
||||
expect(fill1LogArgs.takerAssetFilledAmount).to.bignumber.eq(order1.takerAssetAmount);
|
||||
expect(fill1LogArgs.makerFeePaid).to.bignumber.eq(order1.makerFee);
|
||||
expect(fill1LogArgs.takerFeePaid).to.bignumber.eq(order1.takerFee);
|
||||
expect(fill1LogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order1));
|
||||
|
||||
const fill2LogArgs = (fillLogs[1] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fill2LogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fill2LogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fill2LogArgs.senderAddress).to.eq(takerAddress);
|
||||
expect(fill2LogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fill2LogArgs.makerAssetData).to.eq(order2.makerAssetData);
|
||||
expect(fill2LogArgs.takerAssetData).to.eq(order2.takerAssetData);
|
||||
expect(fill2LogArgs.makerAssetFilledAmount).to.bignumber.eq(order2.makerAssetAmount);
|
||||
expect(fill2LogArgs.takerAssetFilledAmount).to.bignumber.eq(order2.takerAssetAmount);
|
||||
expect(fill2LogArgs.makerFeePaid).to.bignumber.eq(order2.makerFee);
|
||||
expect(fill2LogArgs.takerFeePaid).to.bignumber.eq(order2.takerFee);
|
||||
expect(fill2LogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order2));
|
||||
});
|
||||
it('should successfully call fillOrder via 2 transactions when one is signed by taker1 and executeTransaction is called by taker2', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await taker2TransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
transaction2.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await exchangeWrapper.batchExecuteTransactionsAsync(
|
||||
[transaction1, transaction2],
|
||||
taker2Address,
|
||||
);
|
||||
|
||||
const transactionExecutionLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeTransactionExecutionEventArgs>).event ===
|
||||
'TransactionExecution',
|
||||
);
|
||||
expect(transactionExecutionLogs.length).to.eq(2);
|
||||
|
||||
const execution1LogArgs = (transactionExecutionLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution1LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction1),
|
||||
);
|
||||
|
||||
const execution2LogArgs = (transactionExecutionLogs[1] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution2LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
);
|
||||
|
||||
const fillLogs = transactionReceipt.logs.filter(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
expect(fillLogs.length).to.eq(2);
|
||||
|
||||
const fill1LogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fill1LogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fill1LogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fill1LogArgs.senderAddress).to.eq(taker2Address);
|
||||
expect(fill1LogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fill1LogArgs.makerAssetData).to.eq(order1.makerAssetData);
|
||||
expect(fill1LogArgs.takerAssetData).to.eq(order1.takerAssetData);
|
||||
expect(fill1LogArgs.makerAssetFilledAmount).to.bignumber.eq(order1.makerAssetAmount);
|
||||
expect(fill1LogArgs.takerAssetFilledAmount).to.bignumber.eq(order1.takerAssetAmount);
|
||||
expect(fill1LogArgs.makerFeePaid).to.bignumber.eq(order1.makerFee);
|
||||
expect(fill1LogArgs.takerFeePaid).to.bignumber.eq(order1.takerFee);
|
||||
expect(fill1LogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order1));
|
||||
|
||||
const fill2LogArgs = (fillLogs[1] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fill2LogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fill2LogArgs.takerAddress).to.eq(taker2Address);
|
||||
expect(fill2LogArgs.senderAddress).to.eq(taker2Address);
|
||||
expect(fill2LogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fill2LogArgs.makerAssetData).to.eq(order2.makerAssetData);
|
||||
expect(fill2LogArgs.takerAssetData).to.eq(order2.takerAssetData);
|
||||
expect(fill2LogArgs.makerAssetFilledAmount).to.bignumber.eq(order2.makerAssetAmount);
|
||||
expect(fill2LogArgs.takerAssetFilledAmount).to.bignumber.eq(order2.takerAssetAmount);
|
||||
expect(fill2LogArgs.makerFeePaid).to.bignumber.eq(order2.makerFee);
|
||||
expect(fill2LogArgs.takerFeePaid).to.bignumber.eq(order2.takerFee);
|
||||
expect(fill2LogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order2));
|
||||
});
|
||||
it('should return the correct data for 2 different fillOrder calls', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await taker2TransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
const returnData = await exchangeInstance
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.callAsync({ from: senderAddress });
|
||||
const abi = artifacts.Exchange.compilerOutput.abi;
|
||||
const methodAbi = abi.filter(
|
||||
abiItem => (abiItem as MethodAbi).name === ExchangeFunctionName.FillOrder,
|
||||
)[0] as MethodAbi;
|
||||
const abiEncoder = new AbiEncoder.Method(methodAbi);
|
||||
const fillResults1: FillResults = abiEncoder.decodeReturnValues(returnData[0]).fillResults;
|
||||
const fillResults2: FillResults = abiEncoder.decodeReturnValues(returnData[1]).fillResults;
|
||||
expect(fillResults1.makerAssetFilledAmount).to.be.bignumber.eq(order1.makerAssetAmount);
|
||||
expect(fillResults1.takerAssetFilledAmount).to.be.bignumber.eq(order1.takerAssetAmount);
|
||||
expect(fillResults1.makerFeePaid).to.be.bignumber.eq(order1.makerFee);
|
||||
expect(fillResults1.takerFeePaid).to.be.bignumber.eq(order1.takerFee);
|
||||
expect(fillResults2.makerAssetFilledAmount).to.be.bignumber.eq(order2.makerAssetAmount);
|
||||
expect(fillResults2.takerAssetFilledAmount).to.be.bignumber.eq(order2.takerAssetAmount);
|
||||
expect(fillResults2.makerFeePaid).to.be.bignumber.eq(order2.makerFee);
|
||||
expect(fillResults2.takerFeePaid).to.be.bignumber.eq(order2.takerFee);
|
||||
});
|
||||
it('should successfully call fillOrder and cancelOrder via 2 transactions', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [
|
||||
order2,
|
||||
]);
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await makerTransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
const transactionReceipt = await exchangeWrapper.batchExecuteTransactionsAsync(
|
||||
[transaction1, transaction2],
|
||||
senderAddress,
|
||||
);
|
||||
|
||||
const transactionExecutionLogs = transactionReceipt.logs.filter(
|
||||
log =>
|
||||
(log as LogWithDecodedArgs<ExchangeTransactionExecutionEventArgs>).event ===
|
||||
'TransactionExecution',
|
||||
);
|
||||
expect(transactionExecutionLogs.length).to.eq(2);
|
||||
|
||||
const execution1LogArgs = (transactionExecutionLogs[0] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution1LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction1),
|
||||
);
|
||||
|
||||
const execution2LogArgs = (transactionExecutionLogs[1] as LogWithDecodedArgs<
|
||||
ExchangeTransactionExecutionEventArgs
|
||||
>).args;
|
||||
expect(execution2LogArgs.transactionHash).to.equal(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
);
|
||||
|
||||
let fillLogIndex: number = 0;
|
||||
let cancelLogIndex: number = 0;
|
||||
const fillLogs = transactionReceipt.logs.filter((log, index) => {
|
||||
if ((log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill') {
|
||||
fillLogIndex = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const cancelLogs = transactionReceipt.logs.filter((log, index) => {
|
||||
if ((log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel') {
|
||||
cancelLogIndex = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
expect(fillLogs.length).to.eq(1);
|
||||
expect(cancelLogs.length).to.eq(1);
|
||||
expect(cancelLogIndex).to.greaterThan(fillLogIndex);
|
||||
|
||||
const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
|
||||
expect(fillLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(fillLogArgs.takerAddress).to.eq(takerAddress);
|
||||
expect(fillLogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(fillLogArgs.makerAssetData).to.eq(order1.makerAssetData);
|
||||
expect(fillLogArgs.takerAssetData).to.eq(order1.takerAssetData);
|
||||
expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order1.makerAssetAmount);
|
||||
expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order1.takerAssetAmount);
|
||||
expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order1.makerFee);
|
||||
expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order1.takerFee);
|
||||
expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order1));
|
||||
|
||||
const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
|
||||
expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
|
||||
expect(cancelLogArgs.senderAddress).to.eq(senderAddress);
|
||||
expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
|
||||
expect(cancelLogArgs.makerAssetData).to.eq(order2.makerAssetData);
|
||||
expect(cancelLogArgs.takerAssetData).to.eq(order2.takerAssetData);
|
||||
expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order2));
|
||||
});
|
||||
it('should return the correct data for a fillOrder and cancelOrder call', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [
|
||||
order2,
|
||||
]);
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await makerTransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
const returnData = await exchangeInstance
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.callAsync({ from: senderAddress });
|
||||
const abi = artifacts.Exchange.compilerOutput.abi;
|
||||
const methodAbi = abi.filter(
|
||||
abiItem => (abiItem as MethodAbi).name === ExchangeFunctionName.FillOrder,
|
||||
)[0] as MethodAbi;
|
||||
const abiEncoder = new AbiEncoder.Method(methodAbi);
|
||||
const fillResults: FillResults = abiEncoder.decodeReturnValues(returnData[0]).fillResults;
|
||||
expect(fillResults.makerAssetFilledAmount).to.be.bignumber.eq(order1.makerAssetAmount);
|
||||
expect(fillResults.takerAssetFilledAmount).to.be.bignumber.eq(order1.takerAssetAmount);
|
||||
expect(fillResults.makerFeePaid).to.be.bignumber.eq(order1.makerFee);
|
||||
expect(fillResults.takerFeePaid).to.be.bignumber.eq(order1.takerFee);
|
||||
expect(returnData[1]).to.eq(constants.NULL_BYTES);
|
||||
});
|
||||
it('should revert if a single transaction reverts', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction1 = await makerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takerTransactionFactory.newSignedTransactionAsync({ data: data2 });
|
||||
const tx = exchangeWrapper.batchExecuteTransactionsAsync([transaction1, transaction2], senderAddress);
|
||||
const nestedError = new ExchangeRevertErrors.OrderStatusError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
OrderStatus.Cancelled,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
nestedError,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if a single transaction is expired', async () => {
|
||||
const order1 = await orderFactory.newSignedOrderAsync();
|
||||
const order2 = await orderFactory.newSignedOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = await takerTransactionFactory.newSignedTransactionAsync({ data: data1 });
|
||||
const transaction2 = await taker2TransactionFactory.newSignedTransactionAsync({
|
||||
data: data2,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const tx = exchangeWrapper.batchExecuteTransactionsAsync([transaction1, transaction2], senderAddress);
|
||||
const expiredTransactionHash = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
expiredTransactionHash,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,13 +1,6 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
describe,
|
||||
expect,
|
||||
hexRandom,
|
||||
transactionHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, describe, expect, transactionHashUtils } from '@0x/contracts-test-utils';
|
||||
import { EIP712DomainWithDefaultSchema, ZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber, ExchangeRevertErrors, StringRevertError } from '@0x/utils';
|
||||
import { BigNumber, ExchangeRevertErrors, hexUtils, StringRevertError } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -19,7 +12,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
let accounts: string[];
|
||||
let domain: EIP712DomainWithDefaultSchema;
|
||||
|
||||
const randomSignature = () => hexRandom(66);
|
||||
const randomSignature = () => hexUtils.random(66);
|
||||
|
||||
const EMPTY_ZERO_EX_TRANSACTION = {
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
@@ -668,7 +661,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
|
||||
describe('setCurrentContextAddressIfRequired', () => {
|
||||
it('should set the currentContextAddress if signer not equal to sender', async () => {
|
||||
const randomAddress = hexRandom(20);
|
||||
const randomAddress = hexUtils.random(20);
|
||||
await transactionsContract
|
||||
.setCurrentContextAddressIfRequired(randomAddress, randomAddress)
|
||||
.awaitTransactionSuccessAsync();
|
||||
@@ -676,7 +669,7 @@ blockchainTests.resets('Transaction Unit Tests', ({ provider, web3Wrapper, txDef
|
||||
expect(currentContextAddress).to.eq(randomAddress);
|
||||
});
|
||||
it('should not set the currentContextAddress if signer equal to sender', async () => {
|
||||
const randomAddress = hexRandom(20);
|
||||
const randomAddress = hexUtils.random(20);
|
||||
await transactionsContract
|
||||
.setCurrentContextAddressIfRequired(accounts[0], randomAddress)
|
||||
.awaitTransactionSuccessAsync({
|
||||
|
@@ -6,12 +6,11 @@ import {
|
||||
describe,
|
||||
expect,
|
||||
getRandomPortion,
|
||||
hexRandom,
|
||||
orderHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { ReferenceFunctions as UtilReferenceFunctions, SafeMathRevertErrors } from '@0x/contracts-utils';
|
||||
import { FillResults, Order } from '@0x/types';
|
||||
import { AnyRevertError, BigNumber, ExchangeRevertErrors, StringRevertError } from '@0x/utils';
|
||||
import { AnyRevertError, BigNumber, ExchangeRevertErrors, hexUtils, StringRevertError } from '@0x/utils';
|
||||
import { LogEntry, LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as ethjs from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
@@ -30,11 +29,11 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
const { addFillResults, getPartialAmountCeil } = LibReferenceFunctions;
|
||||
const { safeSub } = UtilReferenceFunctions;
|
||||
const protocolFeeMultiplier = new BigNumber(150000);
|
||||
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
|
||||
const randomAssetData = () => hexRandom(34);
|
||||
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
|
||||
const randomAssetData = () => hexUtils.random(34);
|
||||
const randomAmount = (maxAmount: BigNumber = ONE_ETHER) => maxAmount.times(_.random(0, 100, true).toFixed(12));
|
||||
const randomTimestamp = () => new BigNumber(Math.floor(_.now() / 1000) + _.random(0, 34560));
|
||||
const randomSalt = () => new BigNumber(hexRandom(constants.WORD_LENGTH).substr(2), 16);
|
||||
const randomSalt = () => new BigNumber(hexUtils.random(constants.WORD_LENGTH).substr(2), 16);
|
||||
const ALWAYS_FAILING_SALT = constants.MAX_UINT256;
|
||||
const ALWAYS_FAILING_SALT_REVERT_ERROR = new StringRevertError('ALWAYS_FAILING_SALT');
|
||||
const EMPTY_FILL_RESULTS = {
|
||||
@@ -1090,7 +1089,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
takerAssetAmount: new BigNumber(20000),
|
||||
}),
|
||||
];
|
||||
const signatures = [hexRandom()];
|
||||
const signatures = [hexUtils.random()];
|
||||
const fillAmount = new BigNumber(10000);
|
||||
const fillResults = await roundingTestContract
|
||||
.marketBuyOrdersNoThrow(orders, fillAmount, signatures)
|
||||
@@ -1105,7 +1104,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
takerAssetAmount: new BigNumber('6300000000000000000'),
|
||||
}),
|
||||
];
|
||||
const signatures = [hexRandom()];
|
||||
const signatures = [hexUtils.random()];
|
||||
const fillAmount = new BigNumber('2400000000000000000');
|
||||
const fillResults = await roundingTestContract
|
||||
.marketBuyOrdersNoThrow(orders, fillAmount, signatures)
|
||||
@@ -1120,7 +1119,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
takerAssetAmount: new BigNumber('103048102885858024121'),
|
||||
}),
|
||||
];
|
||||
const signatures = [hexRandom()];
|
||||
const signatures = [hexUtils.random()];
|
||||
const fillAmount = new BigNumber('84819838457312347759');
|
||||
const fillResults = await roundingTestContract
|
||||
.marketBuyOrdersNoThrow(orders, fillAmount, signatures)
|
||||
@@ -1134,7 +1133,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
it(`${i + 1}/${FUZZ_COUNT}`, async () => {
|
||||
const ordersCount = _.random(1, 10);
|
||||
const orders = _.times(ordersCount, () => randomOrder());
|
||||
const signatures = orders.map(() => hexRandom());
|
||||
const signatures = orders.map(() => hexUtils.random());
|
||||
const totalMakerAssetAmount = BigNumber.sum(...orders.map(o => o.makerAssetAmount));
|
||||
const fillAmount = getRandomPortion(totalMakerAssetAmount);
|
||||
const fillResults = await roundingTestContract
|
||||
|
@@ -1,4 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "5.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Export function `encodeDutchAuctionAssetData`",
|
||||
"pr": 2373
|
||||
}
|
||||
],
|
||||
"timestamp": 1575931811
|
||||
},
|
||||
{
|
||||
"version": "5.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.1.0 - _December 9, 2019_
|
||||
|
||||
* Export function `encodeDutchAuctionAssetData` (#2373)
|
||||
|
||||
## v5.0.0 - _December 2, 2019_
|
||||
|
||||
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "5.0.0",
|
||||
"version": "5.1.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,24 +52,24 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/contracts-asset-proxy": "^3.0.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-erc721": "^3.0.0",
|
||||
"@0x/contracts-exchange": "^3.0.0",
|
||||
"@0x/contracts-exchange-libs": "^4.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contracts-asset-proxy": "^3.0.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-erc721": "^3.0.1",
|
||||
"@0x/contracts-exchange": "^3.0.1",
|
||||
"@0x/contracts-exchange-libs": "^4.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -77,6 +77,8 @@
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereumjs-abi": "0.6.5",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
@@ -89,7 +91,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
|
@@ -15,7 +15,7 @@ import {
|
||||
web3Wrapper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
@@ -26,6 +26,8 @@ import { DutchAuctionContract, DutchAuctionTestWrapper, WETH9Contract } from './
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { encodeDutchAuctionAssetData } from './utils';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
@@ -158,7 +160,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
feeRecipientAddress,
|
||||
// taker address or sender address should be set to the ducth auction contract
|
||||
takerAddress: dutchAuctionContract.address,
|
||||
makerAssetData: assetDataUtils.encodeDutchAuctionAssetData(
|
||||
makerAssetData: encodeDutchAuctionAssetData(
|
||||
await devUtils.encodeERC20AssetData(defaultMakerAssetAddress).callAsync(),
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@@ -202,7 +204,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
describe('matchOrders', () => {
|
||||
it('should be worth the begin price at the begining of the auction', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@@ -216,7 +218,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
it('should be be worth the end price at the end of the auction', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@@ -282,7 +284,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
it('should revert when auction expires', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@@ -310,7 +312,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
});
|
||||
it('begin time is less than end time', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
@@ -336,7 +338,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
const erc721MakerAssetData = await devUtils
|
||||
.encodeERC721AssetData(erc721Token.address, makerAssetId)
|
||||
.callAsync();
|
||||
const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData(
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
erc721MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
|
@@ -1,2 +1,23 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as ethAbi from 'ethereumjs-abi';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
export * from './balance_threshold_wrapper';
|
||||
export * from './dutch_auction_test_wrapper';
|
||||
|
||||
// tslint:disable-next-line:completed-docs
|
||||
export function encodeDutchAuctionAssetData(
|
||||
assetData: string,
|
||||
beginTimeSeconds: BigNumber,
|
||||
beginAmount: BigNumber,
|
||||
): string {
|
||||
const assetDataBuffer = ethUtil.toBuffer(assetData);
|
||||
const abiEncodedAuctionData = (ethAbi as any).rawEncode(
|
||||
['uint256', 'uint256'],
|
||||
[beginTimeSeconds.toString(), beginAmount.toString()],
|
||||
);
|
||||
const abiEncodedAuctionDataBuffer = ethUtil.toBuffer(abiEncodedAuctionData);
|
||||
const dutchAuctionDataBuffer = Buffer.concat([assetDataBuffer, abiEncodedAuctionDataBuffer]);
|
||||
const dutchAuctionData = ethUtil.bufferToHex(dutchAuctionDataBuffer);
|
||||
return dutchAuctionData;
|
||||
}
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.0 - _December 2, 2019_
|
||||
|
||||
* Forwader <> ERC20Bridge integration tests (#2356)
|
||||
|
@@ -20,7 +20,6 @@ pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IEth2Dai.sol";
|
||||
|
||||
|
||||
contract TestEth2DaiBridge is
|
||||
@@ -35,11 +34,11 @@ contract TestEth2DaiBridge is
|
||||
TEST_ETH2DAI_ADDRESS = testEth2Dai;
|
||||
}
|
||||
|
||||
function _getEth2DaiContract()
|
||||
function _getEth2DaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai exchange)
|
||||
returns (address exchange)
|
||||
{
|
||||
return IEth2Dai(TEST_ETH2DAI_ADDRESS);
|
||||
return TEST_ETH2DAI_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,6 @@ pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/bridges/UniswapBridge.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
|
||||
|
||||
contract TestUniswapBridge is
|
||||
@@ -41,19 +39,19 @@ contract TestUniswapBridge is
|
||||
TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS = testUniswapExchangeFactory;
|
||||
}
|
||||
|
||||
function getWethContract()
|
||||
public
|
||||
function _getWethAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEtherToken token)
|
||||
returns (address token)
|
||||
{
|
||||
return IEtherToken(TEST_WETH_ADDRESS);
|
||||
return TEST_WETH_ADDRESS;
|
||||
}
|
||||
|
||||
function getUniswapExchangeFactoryContract()
|
||||
public
|
||||
function _getUniswapExchangeFactoryAddress()
|
||||
internal
|
||||
view
|
||||
returns (IUniswapExchangeFactory factory)
|
||||
returns (address factory)
|
||||
{
|
||||
return IUniswapExchangeFactory(TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS);
|
||||
return TEST_UNISWAP_EXCHANGE_FACTORY_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-integrations",
|
||||
"version": "2.0.0",
|
||||
"version": "2.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,21 +50,21 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@0x/abi-gen": "^5.0.1",
|
||||
"@0x/contract-addresses": "^4.0.0",
|
||||
"@0x/contracts-coordinator": "^3.0.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.0",
|
||||
"@0x/contracts-exchange-forwarder": "^4.0.0",
|
||||
"@0x/contracts-exchange-libs": "^4.0.0",
|
||||
"@0x/contracts-gen": "^2.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/coordinator-server": "^1.0.3",
|
||||
"@0x/dev-utils": "^3.0.0",
|
||||
"@0x/migrations": "^5.0.0",
|
||||
"@0x/order-utils": "^9.0.0",
|
||||
"@0x/sol-compiler": "^4.0.0",
|
||||
"@0x/contracts-coordinator": "^3.0.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.1",
|
||||
"@0x/contracts-exchange-forwarder": "^4.0.1",
|
||||
"@0x/contracts-exchange-libs": "^4.0.1",
|
||||
"@0x/contracts-gen": "^2.0.1",
|
||||
"@0x/contracts-utils": "^4.0.1",
|
||||
"@0x/coordinator-server": "^1.0.4",
|
||||
"@0x/dev-utils": "^3.0.1",
|
||||
"@0x/migrations": "^5.0.1",
|
||||
"@0x/order-utils": "^10.0.0",
|
||||
"@0x/sol-compiler": "^4.0.1",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.1",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@@ -85,18 +85,18 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/contracts-asset-proxy": "^3.0.0",
|
||||
"@0x/contracts-erc1155": "^2.0.0",
|
||||
"@0x/contracts-erc20": "^3.0.0",
|
||||
"@0x/contracts-erc721": "^3.0.0",
|
||||
"@0x/contracts-exchange": "^3.0.0",
|
||||
"@0x/contracts-multisig": "^4.0.0",
|
||||
"@0x/contracts-staking": "^2.0.0",
|
||||
"@0x/contracts-test-utils": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/base-contract": "^6.0.1",
|
||||
"@0x/contracts-asset-proxy": "^3.0.1",
|
||||
"@0x/contracts-erc1155": "^2.0.1",
|
||||
"@0x/contracts-erc20": "^3.0.1",
|
||||
"@0x/contracts-erc721": "^3.0.1",
|
||||
"@0x/contracts-exchange": "^3.0.1",
|
||||
"@0x/contracts-multisig": "^4.0.1",
|
||||
"@0x/contracts-staking": "^2.0.1",
|
||||
"@0x/contracts-test-utils": "^5.0.0",
|
||||
"@0x/types": "^3.1.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/utils": "^5.1.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -11,15 +11,12 @@ import {
|
||||
constants,
|
||||
ExchangeFunctionName,
|
||||
expect,
|
||||
hexConcat,
|
||||
hexSlice,
|
||||
orderHashUtils,
|
||||
transactionHashUtils,
|
||||
verifyEvents,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { SignedOrder, SignedZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
|
||||
import { Actor } from '../framework/actors/base';
|
||||
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
||||
@@ -96,72 +93,9 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
async function simulateFillsAsync(
|
||||
orders: SignedOrder[],
|
||||
txReceipt: TransactionReceiptWithDecodedLogs,
|
||||
msgValue?: BigNumber,
|
||||
): Promise<LocalBalanceStore> {
|
||||
let remainingValue = msgValue || constants.ZERO_AMOUNT;
|
||||
const localBalanceStore = LocalBalanceStore.create(balanceStore);
|
||||
// Transaction gas cost
|
||||
localBalanceStore.burnGas(txReceipt.from, DeploymentManager.gasPrice.times(txReceipt.gasUsed));
|
||||
|
||||
for (const order of orders) {
|
||||
// Taker -> Maker
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
taker.address,
|
||||
maker.address,
|
||||
order.takerAssetAmount,
|
||||
order.takerAssetData,
|
||||
);
|
||||
// Maker -> Taker
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
maker.address,
|
||||
taker.address,
|
||||
order.makerAssetAmount,
|
||||
order.makerAssetData,
|
||||
);
|
||||
// Taker -> Fee Recipient
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
taker.address,
|
||||
feeRecipient.address,
|
||||
order.takerFee,
|
||||
order.takerFeeAssetData,
|
||||
);
|
||||
// Maker -> Fee Recipient
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
maker.address,
|
||||
feeRecipient.address,
|
||||
order.makerFee,
|
||||
order.makerFeeAssetData,
|
||||
);
|
||||
|
||||
// Protocol fee
|
||||
if (remainingValue.isGreaterThanOrEqualTo(DeploymentManager.protocolFee)) {
|
||||
localBalanceStore.sendEth(
|
||||
txReceipt.from,
|
||||
deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
);
|
||||
remainingValue = remainingValue.minus(DeploymentManager.protocolFee);
|
||||
} else {
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
taker.address,
|
||||
deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
deployment.assetDataEncoder
|
||||
.ERC20Token(deployment.tokens.weth.address)
|
||||
.getABIEncodedTransactionData(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return localBalanceStore;
|
||||
}
|
||||
|
||||
function expectedFillEvent(order: SignedOrder): ExchangeFillEventArgs {
|
||||
return {
|
||||
makerAddress: order.makerAddress,
|
||||
@@ -191,10 +125,7 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
before(async () => {
|
||||
order = await maker.signOrderAsync();
|
||||
data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
transaction = await taker.signTransactionAsync({
|
||||
data,
|
||||
gasPrice: DeploymentManager.gasPrice,
|
||||
});
|
||||
transaction = await taker.signTransactionAsync({ data });
|
||||
approval = await feeRecipient.signCoordinatorApprovalAsync(transaction, taker.address);
|
||||
});
|
||||
|
||||
@@ -204,7 +135,14 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, taker.address, transaction.signature, [approval.signature])
|
||||
.awaitTransactionSuccessAsync({ from: taker.address, value: DeploymentManager.protocolFee });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync([order], txReceipt, DeploymentManager.protocolFee);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills(
|
||||
[order],
|
||||
taker.address,
|
||||
txReceipt,
|
||||
deployment,
|
||||
DeploymentManager.protocolFee,
|
||||
);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill);
|
||||
@@ -215,7 +153,14 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, feeRecipient.address, transaction.signature, [])
|
||||
.awaitTransactionSuccessAsync({ from: feeRecipient.address, value: DeploymentManager.protocolFee });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync([order], txReceipt, DeploymentManager.protocolFee);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills(
|
||||
[order],
|
||||
taker.address,
|
||||
txReceipt,
|
||||
deployment,
|
||||
DeploymentManager.protocolFee,
|
||||
);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill);
|
||||
@@ -229,9 +174,12 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
value: DeploymentManager.protocolFee.plus(1),
|
||||
});
|
||||
|
||||
const expectedBalances = await simulateFillsAsync(
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills(
|
||||
[order],
|
||||
taker.address,
|
||||
txReceipt,
|
||||
deployment,
|
||||
DeploymentManager.protocolFee.plus(1),
|
||||
);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
@@ -244,7 +192,8 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, feeRecipient.address, transaction.signature, [])
|
||||
.awaitTransactionSuccessAsync({ from: feeRecipient.address });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync([order], txReceipt);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills([order], taker.address, txReceipt, deployment);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill);
|
||||
@@ -255,7 +204,8 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, feeRecipient.address, transaction.signature, [])
|
||||
.awaitTransactionSuccessAsync({ from: feeRecipient.address, value: new BigNumber(1) });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync([order], txReceipt, new BigNumber(1));
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills([order], taker.address, txReceipt, deployment, new BigNumber(1));
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, [expectedFillEvent(order)], ExchangeEvents.Fill);
|
||||
@@ -273,10 +223,10 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should revert with an invalid approval signature`, async () => {
|
||||
const approvalSignature = hexConcat(
|
||||
hexSlice(approval.signature, 0, 2),
|
||||
const approvalSignature = hexUtils.concat(
|
||||
hexUtils.slice(approval.signature, 0, 2),
|
||||
'0xFFFFFFFF',
|
||||
hexSlice(approval.signature, 6),
|
||||
hexUtils.slice(approval.signature, 6),
|
||||
);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const tx = coordinator
|
||||
@@ -309,10 +259,7 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
before(async () => {
|
||||
orders = [await maker.signOrderAsync(), await maker.signOrderAsync()];
|
||||
data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
|
||||
transaction = await taker.signTransactionAsync({
|
||||
data,
|
||||
gasPrice: DeploymentManager.gasPrice,
|
||||
});
|
||||
transaction = await taker.signTransactionAsync({ data });
|
||||
approval = await feeRecipient.signCoordinatorApprovalAsync(transaction, taker.address);
|
||||
});
|
||||
|
||||
@@ -323,7 +270,8 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, taker.address, transaction.signature, [approval.signature])
|
||||
.awaitTransactionSuccessAsync({ from: taker.address, value });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync(orders, txReceipt, value);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill);
|
||||
@@ -335,7 +283,8 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, feeRecipient.address, transaction.signature, [])
|
||||
.awaitTransactionSuccessAsync({ from: feeRecipient.address, value });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync(orders, txReceipt, value);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill);
|
||||
@@ -347,16 +296,17 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
.executeTransaction(transaction, feeRecipient.address, transaction.signature, [])
|
||||
.awaitTransactionSuccessAsync({ from: feeRecipient.address, value });
|
||||
|
||||
const expectedBalances = await simulateFillsAsync(orders, txReceipt, value);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill);
|
||||
});
|
||||
it(`${fnName} should revert with an invalid approval signature`, async () => {
|
||||
const approvalSignature = hexConcat(
|
||||
hexSlice(approval.signature, 0, 2),
|
||||
const approvalSignature = hexUtils.concat(
|
||||
hexUtils.slice(approval.signature, 0, 2),
|
||||
'0xFFFFFFFF',
|
||||
hexSlice(approval.signature, 6),
|
||||
hexUtils.slice(approval.signature, 6),
|
||||
);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const tx = coordinator
|
||||
@@ -400,7 +350,6 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]);
|
||||
const transaction = await maker.signTransactionAsync({
|
||||
data,
|
||||
gasPrice: DeploymentManager.gasPrice,
|
||||
});
|
||||
const txReceipt = await coordinator
|
||||
.executeTransaction(transaction, maker.address, transaction.signature, [])
|
||||
@@ -413,7 +362,6 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.BatchCancelOrders, orders);
|
||||
const transaction = await maker.signTransactionAsync({
|
||||
data,
|
||||
gasPrice: DeploymentManager.gasPrice,
|
||||
});
|
||||
const txReceipt = await coordinator
|
||||
.executeTransaction(transaction, maker.address, transaction.signature, [])
|
||||
@@ -425,7 +373,6 @@ blockchainTests.resets('Coordinator integration tests', env => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo, []);
|
||||
const transaction = await maker.signTransactionAsync({
|
||||
data,
|
||||
gasPrice: DeploymentManager.gasPrice,
|
||||
});
|
||||
const txReceipt = await coordinator
|
||||
.executeTransaction(transaction, maker.address, transaction.signature, [])
|
||||
|
@@ -146,7 +146,7 @@ blockchainTests.resets('matchOrders integration tests', env => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
describe('batchMatchOrders and batchMatchOrdersWithMaximalFill rich errors', async () => {
|
||||
|
@@ -124,7 +124,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
interface SignedOrderWithValidity {
|
||||
@@ -132,13 +132,9 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
isValid: boolean;
|
||||
}
|
||||
|
||||
async function simulateFillAsync(
|
||||
signedOrder: SignedOrder,
|
||||
expectedFillResults: FillResults,
|
||||
shouldUseWeth: boolean,
|
||||
): Promise<void> {
|
||||
function simulateFill(signedOrder: SignedOrder, expectedFillResults: FillResults, shouldUseWeth: boolean): void {
|
||||
// taker -> maker
|
||||
await localBalances.transferAssetAsync(
|
||||
localBalances.transferAsset(
|
||||
taker.address,
|
||||
maker.address,
|
||||
expectedFillResults.takerAssetFilledAmount,
|
||||
@@ -146,7 +142,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
);
|
||||
|
||||
// maker -> taker
|
||||
await localBalances.transferAssetAsync(
|
||||
localBalances.transferAsset(
|
||||
maker.address,
|
||||
taker.address,
|
||||
expectedFillResults.makerAssetFilledAmount,
|
||||
@@ -154,7 +150,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
);
|
||||
|
||||
// maker -> feeRecipient
|
||||
await localBalances.transferAssetAsync(
|
||||
localBalances.transferAsset(
|
||||
maker.address,
|
||||
feeRecipient,
|
||||
expectedFillResults.makerFeePaid,
|
||||
@@ -162,7 +158,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
);
|
||||
|
||||
// taker -> feeRecipient
|
||||
await localBalances.transferAssetAsync(
|
||||
localBalances.transferAsset(
|
||||
taker.address,
|
||||
feeRecipient,
|
||||
expectedFillResults.takerFeePaid,
|
||||
@@ -171,7 +167,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
|
||||
// taker -> protocol fees
|
||||
if (shouldUseWeth) {
|
||||
await localBalances.transferAssetAsync(
|
||||
localBalances.transferAsset(
|
||||
taker.address,
|
||||
deployment.staking.stakingProxy.address,
|
||||
expectedFillResults.protocolFeePaid,
|
||||
@@ -343,7 +339,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
const shouldPayWethFees = DeploymentManager.protocolFee.gt(value);
|
||||
|
||||
// Simulate filling the order
|
||||
await simulateFillAsync(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
simulateFill(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
|
||||
// Ensure that the correct logs were emitted and that the balances are accurate.
|
||||
await assertResultsAsync(receipt, [{ signedOrder, expectedFillResults, shouldPayWethFees }]);
|
||||
@@ -444,7 +440,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
}
|
||||
|
||||
fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees });
|
||||
await simulateFillAsync(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
simulateFill(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
}
|
||||
|
||||
const contractFn = deployment.exchange.batchFillOrders(
|
||||
@@ -506,7 +502,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
}
|
||||
|
||||
fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees });
|
||||
await simulateFillAsync(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
simulateFill(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
}
|
||||
|
||||
const contractFn = deployment.exchange.batchFillOrKillOrders(
|
||||
@@ -600,7 +596,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
}
|
||||
|
||||
fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees });
|
||||
await simulateFillAsync(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
simulateFill(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
} else {
|
||||
totalFillResults.push(nullFillResults);
|
||||
}
|
||||
@@ -714,7 +710,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
takerFillAmount,
|
||||
);
|
||||
|
||||
await simulateFillAsync(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
simulateFill(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees });
|
||||
|
||||
totalFillResults = addFillResults(totalFillResults, expectedFillResults);
|
||||
@@ -912,7 +908,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
makerAssetBought,
|
||||
);
|
||||
|
||||
await simulateFillAsync(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
simulateFill(signedOrder, expectedFillResults, shouldPayWethFees);
|
||||
fillTestInfo.push({ signedOrder, expectedFillResults, shouldPayWethFees });
|
||||
|
||||
totalFillResults = addFillResults(totalFillResults, expectedFillResults);
|
||||
|
@@ -99,7 +99,7 @@ export class FillOrderWrapper {
|
||||
await this._assertOrderStateAsync(signedOrder, initTakerAssetFilledAmount);
|
||||
// Simulate and execute fill then assert outputs
|
||||
const [fillResults, fillEvent, txReceipt] = await this._fillOrderAsync(signedOrder, from, opts);
|
||||
const [simulatedFillResults, simulatedFillEvent, simulatedFinalBalanceStore] = await simulateFillOrderAsync(
|
||||
const [simulatedFillResults, simulatedFillEvent, simulatedFinalBalanceStore] = simulateFillOrder(
|
||||
txReceipt,
|
||||
signedOrder,
|
||||
from,
|
||||
@@ -169,13 +169,13 @@ export class FillOrderWrapper {
|
||||
* @param initBalanceStore Account balances prior to the fill.
|
||||
* @return The expected account balances, fill results, and fill events.
|
||||
*/
|
||||
async function simulateFillOrderAsync(
|
||||
function simulateFillOrder(
|
||||
txReceipt: TransactionReceiptWithDecodedLogs,
|
||||
signedOrder: SignedOrder,
|
||||
takerAddress: string,
|
||||
initBalanceStore: BalanceStore,
|
||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||
): Promise<[FillResults, FillEventArgs, BalanceStore]> {
|
||||
): [FillResults, FillEventArgs, BalanceStore] {
|
||||
const balanceStore = LocalBalanceStore.create(initBalanceStore);
|
||||
const takerAssetFillAmount =
|
||||
opts.takerAssetFillAmount !== undefined ? opts.takerAssetFillAmount : signedOrder.takerAssetAmount;
|
||||
@@ -188,28 +188,28 @@ async function simulateFillOrderAsync(
|
||||
);
|
||||
const fillEvent = FillOrderWrapper.simulateFillEvent(signedOrder, takerAddress, fillResults);
|
||||
// Taker -> Maker
|
||||
await balanceStore.transferAssetAsync(
|
||||
balanceStore.transferAsset(
|
||||
takerAddress,
|
||||
signedOrder.makerAddress,
|
||||
fillResults.takerAssetFilledAmount,
|
||||
signedOrder.takerAssetData,
|
||||
);
|
||||
// Maker -> Taker
|
||||
await balanceStore.transferAssetAsync(
|
||||
balanceStore.transferAsset(
|
||||
signedOrder.makerAddress,
|
||||
takerAddress,
|
||||
fillResults.makerAssetFilledAmount,
|
||||
signedOrder.makerAssetData,
|
||||
);
|
||||
// Taker -> Fee Recipient
|
||||
await balanceStore.transferAssetAsync(
|
||||
balanceStore.transferAsset(
|
||||
takerAddress,
|
||||
signedOrder.feeRecipientAddress,
|
||||
fillResults.takerFeePaid,
|
||||
signedOrder.takerFeeAssetData,
|
||||
);
|
||||
// Maker -> Fee Recipient
|
||||
await balanceStore.transferAssetAsync(
|
||||
balanceStore.transferAsset(
|
||||
signedOrder.makerAddress,
|
||||
signedOrder.feeRecipientAddress,
|
||||
fillResults.makerFeePaid,
|
||||
|
@@ -109,54 +109,9 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
async function simulateFillAsync(
|
||||
order: SignedOrder,
|
||||
txReceipt: TransactionReceiptWithDecodedLogs,
|
||||
msgValue?: BigNumber,
|
||||
): Promise<LocalBalanceStore> {
|
||||
let remainingValue = msgValue !== undefined ? msgValue : DeploymentManager.protocolFee;
|
||||
const localBalanceStore = LocalBalanceStore.create(balanceStore);
|
||||
// Transaction gas cost
|
||||
localBalanceStore.burnGas(txReceipt.from, DeploymentManager.gasPrice.times(txReceipt.gasUsed));
|
||||
|
||||
// Taker -> Maker
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
taker.address,
|
||||
maker.address,
|
||||
order.takerAssetAmount,
|
||||
order.takerAssetData,
|
||||
);
|
||||
// Maker -> Taker
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
maker.address,
|
||||
taker.address,
|
||||
order.makerAssetAmount,
|
||||
order.makerAssetData,
|
||||
);
|
||||
|
||||
// Protocol fee
|
||||
if (remainingValue.isGreaterThanOrEqualTo(DeploymentManager.protocolFee)) {
|
||||
localBalanceStore.sendEth(
|
||||
txReceipt.from,
|
||||
deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
);
|
||||
remainingValue = remainingValue.minus(DeploymentManager.protocolFee);
|
||||
} else {
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
taker.address,
|
||||
deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
deployment.assetDataEncoder.ERC20Token(deployment.tokens.weth.address).getABIEncodedTransactionData(),
|
||||
);
|
||||
}
|
||||
|
||||
return localBalanceStore;
|
||||
}
|
||||
|
||||
function verifyFillEvents(order: SignedOrder, receipt: TransactionReceiptWithDecodedLogs): void {
|
||||
// Ensure that the fill event was correct.
|
||||
verifyEvents<ExchangeFillEventArgs>(
|
||||
@@ -207,7 +162,8 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
|
||||
// Check balances
|
||||
const expectedBalances = await simulateFillAsync(order, receipt);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
|
||||
@@ -233,7 +189,8 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
|
||||
// Check balances
|
||||
const expectedBalances = await simulateFillAsync(order, receipt);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
|
||||
@@ -310,7 +267,7 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
const [finalizePoolReceipt] = await delegator.finalizePoolsAsync([poolId]);
|
||||
|
||||
// Check balances
|
||||
await expectedBalances.transferAssetAsync(
|
||||
expectedBalances.transferAsset(
|
||||
deployment.staking.stakingProxy.address,
|
||||
operator.address,
|
||||
operatorReward,
|
||||
@@ -371,7 +328,8 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount, { value: constants.ZERO_AMOUNT });
|
||||
const rewardsAvailable = DeploymentManager.protocolFee;
|
||||
const expectedBalances = await simulateFillAsync(order, receipt, constants.ZERO_AMOUNT);
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.simulateFills([order], taker.address, receipt, deployment);
|
||||
|
||||
// End the epoch. This should wrap the staking proxy's ETH balance.
|
||||
const endEpochReceipt = await delegator.endEpochAsync();
|
||||
@@ -392,7 +350,7 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
const [finalizePoolReceipt] = await delegator.finalizePoolsAsync([poolId]);
|
||||
|
||||
// Check balances
|
||||
await expectedBalances.transferAssetAsync(
|
||||
expectedBalances.transferAsset(
|
||||
deployment.staking.stakingProxy.address,
|
||||
operator.address,
|
||||
operatorReward,
|
||||
|
@@ -296,7 +296,7 @@ export class MatchOrderTester {
|
||||
localBalanceStore.burnGas(takerAddress, DeploymentManager.gasPrice.times(transactionReceipt.gasUsed));
|
||||
|
||||
// Simulate the fill.
|
||||
const expectedMatchResults = await this._simulateMatchOrdersAsync(
|
||||
const expectedMatchResults = this._simulateMatchOrders(
|
||||
orders,
|
||||
takerAddress,
|
||||
toFullMatchTransferAmounts(expectedTransferAmounts),
|
||||
@@ -319,12 +319,12 @@ export class MatchOrderTester {
|
||||
* @param localBalanceStore The balance store to use for the simulation.
|
||||
* @return The new account balances and fill events that occurred during the match.
|
||||
*/
|
||||
protected async _simulateMatchOrdersAsync(
|
||||
protected _simulateMatchOrders(
|
||||
orders: MatchedOrders,
|
||||
takerAddress: string,
|
||||
transferAmounts: MatchTransferAmounts,
|
||||
localBalanceStore: LocalBalanceStore,
|
||||
): Promise<MatchResults> {
|
||||
): MatchResults {
|
||||
// prettier-ignore
|
||||
const matchResults = {
|
||||
orders: {
|
||||
@@ -343,7 +343,7 @@ export class MatchOrderTester {
|
||||
};
|
||||
|
||||
// Right maker asset -> left maker
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
orders.rightOrder.makerAddress,
|
||||
orders.leftOrder.makerAddress,
|
||||
transferAmounts.rightMakerAssetBoughtByLeftMakerAmount,
|
||||
@@ -352,7 +352,7 @@ export class MatchOrderTester {
|
||||
|
||||
if (orders.leftOrder.makerAddress !== orders.leftOrder.feeRecipientAddress) {
|
||||
// Left maker fees
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
orders.leftOrder.makerAddress,
|
||||
orders.leftOrder.feeRecipientAddress,
|
||||
transferAmounts.leftMakerFeeAssetPaidByLeftMakerAmount,
|
||||
@@ -361,7 +361,7 @@ export class MatchOrderTester {
|
||||
}
|
||||
|
||||
// Left maker asset -> right maker
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
orders.leftOrder.makerAddress,
|
||||
orders.rightOrder.makerAddress,
|
||||
transferAmounts.leftMakerAssetBoughtByRightMakerAmount,
|
||||
@@ -370,7 +370,7 @@ export class MatchOrderTester {
|
||||
|
||||
if (orders.rightOrder.makerAddress !== orders.rightOrder.feeRecipientAddress) {
|
||||
// Right maker fees
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
orders.rightOrder.makerAddress,
|
||||
orders.rightOrder.feeRecipientAddress,
|
||||
transferAmounts.rightMakerFeeAssetPaidByRightMakerAmount,
|
||||
@@ -379,7 +379,7 @@ export class MatchOrderTester {
|
||||
}
|
||||
|
||||
// Left taker profit
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
orders.leftOrder.makerAddress,
|
||||
takerAddress,
|
||||
transferAmounts.leftMakerAssetReceivedByTakerAmount,
|
||||
@@ -387,7 +387,7 @@ export class MatchOrderTester {
|
||||
);
|
||||
|
||||
// Right taker profit
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
orders.rightOrder.makerAddress,
|
||||
takerAddress,
|
||||
transferAmounts.rightMakerAssetReceivedByTakerAmount,
|
||||
@@ -395,7 +395,7 @@ export class MatchOrderTester {
|
||||
);
|
||||
|
||||
// Left taker fees
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
takerAddress,
|
||||
orders.leftOrder.feeRecipientAddress,
|
||||
transferAmounts.leftTakerFeeAssetPaidByTakerAmount,
|
||||
@@ -403,7 +403,7 @@ export class MatchOrderTester {
|
||||
);
|
||||
|
||||
// Right taker fees
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
takerAddress,
|
||||
orders.rightOrder.feeRecipientAddress,
|
||||
transferAmounts.rightTakerFeeAssetPaidByTakerAmount,
|
||||
@@ -424,13 +424,13 @@ export class MatchOrderTester {
|
||||
this._deployment.staking.stakingProxy.address,
|
||||
transferAmounts.rightProtocolFeePaidByTakerInEthAmount,
|
||||
);
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
takerAddress,
|
||||
this._deployment.staking.stakingProxy.address,
|
||||
transferAmounts.leftProtocolFeePaidByTakerInWethAmount,
|
||||
wethAssetData,
|
||||
);
|
||||
await localBalanceStore.transferAssetAsync(
|
||||
localBalanceStore.transferAsset(
|
||||
takerAddress,
|
||||
this._deployment.staking.stakingProxy.address,
|
||||
transferAmounts.rightProtocolFeePaidByTakerInWethAmount,
|
||||
@@ -513,7 +513,7 @@ export class MatchOrderTester {
|
||||
|
||||
// Add the latest match to the batch match results
|
||||
batchMatchResults.matches.push(
|
||||
await this._simulateMatchOrdersAsync(
|
||||
this._simulateMatchOrders(
|
||||
matchedOrders,
|
||||
takerAddress,
|
||||
toFullMatchTransferAmounts(transferAmounts[i]),
|
||||
|
@@ -163,7 +163,7 @@ blockchainTests.resets('matchOrdersWithMaximalFill integration tests', env => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
describe('matchOrdersWithMaximalFill', () => {
|
||||
|
@@ -163,7 +163,7 @@ blockchainTests.resets('matchOrders integration tests', env => {
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
describe('matchOrders', () => {
|
||||
|
@@ -0,0 +1,500 @@
|
||||
// tslint:disable: max-file-line-count
|
||||
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
|
||||
import { exchangeDataEncoder, ExchangeRevertErrors } from '@0x/contracts-exchange';
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
describe,
|
||||
ExchangeFunctionName,
|
||||
expect,
|
||||
orderHashUtils,
|
||||
transactionHashUtils,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { SignedOrder, SignedZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { Actor } from '../framework/actors/base';
|
||||
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
||||
import { Maker } from '../framework/actors/maker';
|
||||
import { Taker } from '../framework/actors/taker';
|
||||
import { actorAddressesByName } from '../framework/actors/utils';
|
||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||
import { LocalBalanceStore } from '../framework/balances/local_balance_store';
|
||||
import { DeploymentManager } from '../framework/deployment_manager';
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
blockchainTests.resets('Transaction <> protocol fee integration tests', env => {
|
||||
let deployment: DeploymentManager;
|
||||
let balanceStore: BlockchainBalanceStore;
|
||||
|
||||
let maker: Maker;
|
||||
let feeRecipient: FeeRecipient;
|
||||
let alice: Taker;
|
||||
let bob: Taker;
|
||||
let charlie: Taker;
|
||||
let wethless: Taker; // Used to test revert scenarios
|
||||
|
||||
let order: SignedOrder; // All orders will have the same fields, modulo salt and expiration time
|
||||
let transactionA: SignedZeroExTransaction; // fillOrder transaction signed by Alice
|
||||
let transactionB: SignedZeroExTransaction; // fillOrder transaction signed by Bob
|
||||
let transactionC: SignedZeroExTransaction; // fillOrder transaction signed by Charlie
|
||||
|
||||
before(async () => {
|
||||
deployment = await DeploymentManager.deployAsync(env, {
|
||||
numErc20TokensToDeploy: 4,
|
||||
numErc721TokensToDeploy: 0,
|
||||
numErc1155TokensToDeploy: 0,
|
||||
});
|
||||
const assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider);
|
||||
const [makerToken, takerToken, makerFeeToken, takerFeeToken] = deployment.tokens.erc20;
|
||||
|
||||
alice = new Taker({ name: 'Alice', deployment });
|
||||
bob = new Taker({ name: 'Bob', deployment });
|
||||
charlie = new Taker({ name: 'Charlie', deployment });
|
||||
wethless = new Taker({ name: 'wethless', deployment });
|
||||
feeRecipient = new FeeRecipient({
|
||||
name: 'Fee recipient',
|
||||
deployment,
|
||||
});
|
||||
maker = new Maker({
|
||||
name: 'Maker',
|
||||
deployment,
|
||||
orderConfig: {
|
||||
feeRecipientAddress: feeRecipient.address,
|
||||
makerAssetData: assetDataEncoder.ERC20Token(makerToken.address).getABIEncodedTransactionData(),
|
||||
takerAssetData: assetDataEncoder.ERC20Token(takerToken.address).getABIEncodedTransactionData(),
|
||||
makerFeeAssetData: assetDataEncoder.ERC20Token(makerFeeToken.address).getABIEncodedTransactionData(),
|
||||
takerFeeAssetData: assetDataEncoder.ERC20Token(takerFeeToken.address).getABIEncodedTransactionData(),
|
||||
},
|
||||
});
|
||||
|
||||
for (const taker of [alice, bob, charlie]) {
|
||||
await taker.configureERC20TokenAsync(takerToken);
|
||||
await taker.configureERC20TokenAsync(takerFeeToken);
|
||||
await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address);
|
||||
}
|
||||
await wethless.configureERC20TokenAsync(takerToken);
|
||||
await wethless.configureERC20TokenAsync(takerFeeToken);
|
||||
await wethless.configureERC20TokenAsync(
|
||||
deployment.tokens.weth,
|
||||
deployment.staking.stakingProxy.address,
|
||||
constants.ZERO_AMOUNT, // wethless taker has approved the proxy, but has no weth
|
||||
);
|
||||
await maker.configureERC20TokenAsync(makerToken);
|
||||
await maker.configureERC20TokenAsync(makerFeeToken);
|
||||
|
||||
balanceStore = new BlockchainBalanceStore(
|
||||
{
|
||||
...actorAddressesByName([alice, bob, charlie, maker, feeRecipient]),
|
||||
StakingProxy: deployment.staking.stakingProxy.address,
|
||||
},
|
||||
{ erc20: { makerToken, takerToken, makerFeeToken, takerFeeToken, wETH: deployment.tokens.weth } },
|
||||
{},
|
||||
);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
|
||||
order = await maker.signOrderAsync();
|
||||
let data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
transactionA = await alice.signTransactionAsync({ data });
|
||||
|
||||
order = await maker.signOrderAsync();
|
||||
data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
transactionB = await bob.signTransactionAsync({ data });
|
||||
|
||||
order = await maker.signOrderAsync();
|
||||
data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
transactionC = await charlie.signTransactionAsync({ data });
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
const REFUND_AMOUNT = new BigNumber(1);
|
||||
|
||||
function protocolFeeError(
|
||||
failedOrder: SignedOrder,
|
||||
failedTransaction: SignedZeroExTransaction,
|
||||
): ExchangeRevertErrors.TransactionExecutionError {
|
||||
const nestedError = new ExchangeRevertErrors.PayProtocolFeeError(
|
||||
orderHashUtils.getOrderHashHex(failedOrder),
|
||||
DeploymentManager.protocolFee,
|
||||
maker.address,
|
||||
wethless.address,
|
||||
'0x',
|
||||
).encode();
|
||||
return new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(failedTransaction),
|
||||
nestedError,
|
||||
);
|
||||
}
|
||||
|
||||
describe('executeTransaction', () => {
|
||||
const ETH_FEE_WITH_REFUND = DeploymentManager.protocolFee.plus(REFUND_AMOUNT);
|
||||
|
||||
let expectedBalances: LocalBalanceStore;
|
||||
beforeEach(async () => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
|
||||
describe('Simple', () => {
|
||||
it('Alice executeTransaction => Alice fillOrder; protocol fee in ETH', async () => {
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(transactionA, transactionA.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND });
|
||||
expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, ETH_FEE_WITH_REFUND);
|
||||
});
|
||||
it('Alice executeTransaction => Bob fillOrder; protocol fee in ETH', async () => {
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(transactionB, transactionB.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND });
|
||||
expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, ETH_FEE_WITH_REFUND);
|
||||
});
|
||||
it('Alice executeTransaction => Alice fillOrder; protocol fee in wETH', async () => {
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(transactionA, transactionA.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, REFUND_AMOUNT);
|
||||
});
|
||||
it('Alice executeTransaction => Bob fillOrder; protocol fee in wETH', async () => {
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(transactionB, transactionB.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, REFUND_AMOUNT);
|
||||
});
|
||||
it('Alice executeTransaction => wETH-less taker fillOrder; reverts because protocol fee cannot be paid', async () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction = await wethless.signTransactionAsync({ data });
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
return expect(tx).to.revertWith(protocolFeeError(order, transaction));
|
||||
});
|
||||
it('Alice executeTransaction => Alice batchFillOrders; mixed protocol fees', async () => {
|
||||
const orders = [order, await maker.signOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchFillOrders,
|
||||
orders,
|
||||
);
|
||||
const batchFillTransaction = await alice.signTransactionAsync({ data });
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(batchFillTransaction, batchFillTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND });
|
||||
expectedBalances.simulateFills(orders, alice.address, txReceipt, deployment, ETH_FEE_WITH_REFUND);
|
||||
});
|
||||
it('Alice executeTransaction => Bob batchFillOrders; mixed protocol fees', async () => {
|
||||
const orders = [order, await maker.signOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchFillOrders,
|
||||
orders,
|
||||
);
|
||||
const batchFillTransaction = await bob.signTransactionAsync({ data });
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(batchFillTransaction, batchFillTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND });
|
||||
expectedBalances.simulateFills(orders, bob.address, txReceipt, deployment, ETH_FEE_WITH_REFUND);
|
||||
});
|
||||
});
|
||||
describe('Nested', () => {
|
||||
it('Alice executeTransaction => Alice executeTransaction => Alice fillOrder; protocol fee in ETH', async () => {
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transactionA, transactionA.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData });
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND });
|
||||
expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, ETH_FEE_WITH_REFUND);
|
||||
});
|
||||
it('Alice executeTransaction => Alice executeTransaction => Bob fillOrder; protocol fee in ETH', async () => {
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transactionB, transactionB.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData });
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEE_WITH_REFUND });
|
||||
expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, ETH_FEE_WITH_REFUND);
|
||||
});
|
||||
it('Alice executeTransaction => Alice executeTransaction => Alice fillOrder; protocol fee in wETH', async () => {
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transactionA, transactionA.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData });
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills([order], alice.address, txReceipt, deployment, REFUND_AMOUNT);
|
||||
});
|
||||
it('Alice executeTransaction => Alice executeTransaction => Bob fillOrder; protocol fee in wETH', async () => {
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transactionB, transactionB.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData });
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills([order], bob.address, txReceipt, deployment, REFUND_AMOUNT);
|
||||
});
|
||||
it('Alice executeTransaction => Alice executeTransaction => wETH-less taker fillOrder; reverts because protocol fee cannot be paid', async () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction = await wethless.signTransactionAsync({ data });
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await alice.signTransactionAsync({ data: recursiveData });
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(recursiveTransaction),
|
||||
protocolFeeError(order, transaction).encode(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('batchExecuteTransactions', () => {
|
||||
let expectedBalances: LocalBalanceStore;
|
||||
beforeEach(async () => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
|
||||
describe('Simple', () => {
|
||||
// All orders' protocol fees paid in ETH by sender
|
||||
const ETH_FEES_WITH_REFUND = DeploymentManager.protocolFee.times(3).plus(REFUND_AMOUNT);
|
||||
// First order's protocol fee paid in ETH by sender, the other two paid in WETH by their respective takers
|
||||
const MIXED_FEES_WITH_REFUND = DeploymentManager.protocolFee.times(1).plus(REFUND_AMOUNT);
|
||||
|
||||
it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder; protocol fees in ETH', async () => {
|
||||
const transactions = [transactionA, transactionB, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[alice.address, bob.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
ETH_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Alice fillOrder, Charlie fillOrder; protocol fees in ETH', async () => {
|
||||
const transactions = [transactionB, transactionA, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[bob.address, alice.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
ETH_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, Alice fillOrder; protocol fees in ETH', async () => {
|
||||
const transactions = [transactionB, transactionC, transactionA];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: ETH_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[bob.address, charlie.address, alice.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
ETH_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder; protocol fees in wETH', async () => {
|
||||
const transactions = [transactionA, transactionB, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[alice.address, bob.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
REFUND_AMOUNT,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Alice fillOrder, Charlie fillOrder; protocol fees in wETH', async () => {
|
||||
const transactions = [transactionB, transactionA, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[bob.address, alice.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
REFUND_AMOUNT,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, Alice fillOrder; protocol fees in wETH', async () => {
|
||||
const transactions = [transactionB, transactionC, transactionA];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: REFUND_AMOUNT });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[bob.address, charlie.address, alice.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
REFUND_AMOUNT,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder; mixed protocol fees', async () => {
|
||||
const transactions = [transactionA, transactionB, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[alice.address, bob.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Alice fillOrder, Charlie fillOrder; mixed protocol fees', async () => {
|
||||
const transactions = [transactionB, transactionA, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[bob.address, alice.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, Alice fillOrder; mixed protocol fees', async () => {
|
||||
const transactions = [transactionB, transactionC, transactionA];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[bob.address, charlie.address, alice.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, wETH-less taker fillOrder; reverts because protocol fee cannot be paid', async () => {
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const failTransaction = await wethless.signTransactionAsync({ data });
|
||||
const transactions = [transactionA, transactionB, failTransaction];
|
||||
const signatures = transactions.map(transaction => transaction.signature);
|
||||
const tx = deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
return expect(tx).to.revertWith(protocolFeeError(order, failTransaction));
|
||||
});
|
||||
});
|
||||
describe('Nested', () => {
|
||||
// First two orders' protocol fees paid in ETH by sender, the others paid in WETH by their respective takers
|
||||
const MIXED_FEES_WITH_REFUND = DeploymentManager.protocolFee.times(2.5);
|
||||
|
||||
// Alice batchExecuteTransactions => Alice fillOrder, Bob fillOrder, Charlie fillOrder
|
||||
let nestedTransaction: SignedZeroExTransaction;
|
||||
// Second fillOrder transaction signed by Bob
|
||||
let transactionB2: SignedZeroExTransaction;
|
||||
// Second fillOrder transaction signed by Charlie
|
||||
let transactionC2: SignedZeroExTransaction;
|
||||
|
||||
before(async () => {
|
||||
let newOrder = await maker.signOrderAsync();
|
||||
let data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [newOrder]);
|
||||
transactionB2 = await bob.signTransactionAsync({ data });
|
||||
|
||||
newOrder = await maker.signOrderAsync();
|
||||
data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [newOrder]);
|
||||
transactionC2 = await charlie.signTransactionAsync({ data });
|
||||
|
||||
const transactions = [transactionA, transactionB, transactionC];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const recursiveData = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.getABIEncodedTransactionData();
|
||||
nestedTransaction = await alice.signTransactionAsync({ data: recursiveData });
|
||||
});
|
||||
|
||||
it('Alice executeTransaction => nested batchExecuteTransactions; mixed protocol fees', async () => {
|
||||
const txReceipt = await deployment.exchange
|
||||
.executeTransaction(nestedTransaction, nestedTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order],
|
||||
[alice.address, bob.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => nested batchExecuteTransactions, Bob fillOrder, Charlie fillOrder; mixed protocol fees', async () => {
|
||||
const transactions = [nestedTransaction, transactionB2, transactionC2];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order, order, order],
|
||||
[alice.address, bob.address, charlie.address, bob.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, nested batchExecuteTransactions, Charlie fillOrder; mixed protocol fees', async () => {
|
||||
const transactions = [transactionB2, nestedTransaction, transactionC2];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order, order, order],
|
||||
[bob.address, alice.address, bob.address, charlie.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
it('Alice batchExecuteTransactions => Bob fillOrder, Charlie fillOrder, nested batchExecuteTransactions; mixed protocol fees', async () => {
|
||||
const transactions = [transactionB2, transactionC2, nestedTransaction];
|
||||
const signatures = transactions.map(tx => tx.signature);
|
||||
const txReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(transactions, signatures)
|
||||
.awaitTransactionSuccessAsync({ from: alice.address, value: MIXED_FEES_WITH_REFUND });
|
||||
expectedBalances.simulateFills(
|
||||
[order, order, order, order, order],
|
||||
[bob.address, charlie.address, alice.address, bob.address, charlie.address],
|
||||
txReceipt,
|
||||
deployment,
|
||||
MIXED_FEES_WITH_REFUND,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
807
contracts/integrations/test/exchange/transaction_test.ts
Normal file
807
contracts/integrations/test/exchange/transaction_test.ts
Normal file
@@ -0,0 +1,807 @@
|
||||
// tslint:disable: max-file-line-count
|
||||
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
|
||||
import {
|
||||
ExchangeCancelEventArgs,
|
||||
ExchangeCancelUpToEventArgs,
|
||||
exchangeDataEncoder,
|
||||
ExchangeEvents,
|
||||
ExchangeFillEventArgs,
|
||||
ExchangeRevertErrors,
|
||||
ExchangeSignatureValidatorApprovalEventArgs,
|
||||
ExchangeTransactionExecutionEventArgs,
|
||||
} from '@0x/contracts-exchange';
|
||||
import { ReferenceFunctions } from '@0x/contracts-exchange-libs';
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
describe,
|
||||
ExchangeFunctionName,
|
||||
expect,
|
||||
getLatestBlockTimestampAsync,
|
||||
orderHashUtils,
|
||||
randomAddress,
|
||||
transactionHashUtils,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { FillResults, OrderStatus, SignatureType, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { Actor } from '../framework/actors/base';
|
||||
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
||||
import { Maker } from '../framework/actors/maker';
|
||||
import { Taker } from '../framework/actors/taker';
|
||||
import { DeploymentManager } from '../framework/deployment_manager';
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
blockchainTests.resets('Transaction integration tests', env => {
|
||||
let deployment: DeploymentManager;
|
||||
|
||||
let maker: Maker;
|
||||
let takers: [Taker, Taker];
|
||||
let feeRecipient: FeeRecipient;
|
||||
let sender: Actor;
|
||||
|
||||
before(async () => {
|
||||
deployment = await DeploymentManager.deployAsync(env, {
|
||||
numErc20TokensToDeploy: 4,
|
||||
numErc721TokensToDeploy: 0,
|
||||
numErc1155TokensToDeploy: 0,
|
||||
});
|
||||
const assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider);
|
||||
const [makerToken, takerToken, makerFeeToken, takerFeeToken] = deployment.tokens.erc20;
|
||||
|
||||
takers = [new Taker({ name: 'Taker 1', deployment }), new Taker({ name: 'Taker 2', deployment })];
|
||||
feeRecipient = new FeeRecipient({
|
||||
name: 'Fee recipient',
|
||||
deployment,
|
||||
});
|
||||
maker = new Maker({
|
||||
name: 'Maker',
|
||||
deployment,
|
||||
orderConfig: {
|
||||
feeRecipientAddress: feeRecipient.address,
|
||||
makerAssetData: assetDataEncoder.ERC20Token(makerToken.address).getABIEncodedTransactionData(),
|
||||
takerAssetData: assetDataEncoder.ERC20Token(takerToken.address).getABIEncodedTransactionData(),
|
||||
makerFeeAssetData: assetDataEncoder.ERC20Token(makerFeeToken.address).getABIEncodedTransactionData(),
|
||||
takerFeeAssetData: assetDataEncoder.ERC20Token(takerFeeToken.address).getABIEncodedTransactionData(),
|
||||
},
|
||||
});
|
||||
sender = new Actor({ name: 'Transaction sender', deployment });
|
||||
|
||||
for (const taker of takers) {
|
||||
await taker.configureERC20TokenAsync(takerToken);
|
||||
await taker.configureERC20TokenAsync(takerFeeToken);
|
||||
await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address);
|
||||
}
|
||||
await maker.configureERC20TokenAsync(makerToken);
|
||||
await maker.configureERC20TokenAsync(makerFeeToken);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
function defaultFillEvent(order: SignedOrder): ExchangeFillEventArgs {
|
||||
return {
|
||||
makerAddress: maker.address,
|
||||
feeRecipientAddress: feeRecipient.address,
|
||||
makerAssetData: order.makerAssetData,
|
||||
takerAssetData: order.takerAssetData,
|
||||
makerFeeAssetData: order.makerFeeAssetData,
|
||||
takerFeeAssetData: order.takerFeeAssetData,
|
||||
orderHash: orderHashUtils.getOrderHashHex(order),
|
||||
takerAddress: takers[0].address,
|
||||
senderAddress: sender.address,
|
||||
makerAssetFilledAmount: order.makerAssetAmount,
|
||||
takerAssetFilledAmount: order.takerAssetAmount,
|
||||
makerFeePaid: order.makerFee,
|
||||
takerFeePaid: order.takerFee,
|
||||
protocolFeePaid: DeploymentManager.protocolFee,
|
||||
};
|
||||
}
|
||||
|
||||
function defaultCancelEvent(order: SignedOrder): ExchangeCancelEventArgs {
|
||||
return {
|
||||
makerAddress: maker.address,
|
||||
feeRecipientAddress: feeRecipient.address,
|
||||
makerAssetData: order.makerAssetData,
|
||||
takerAssetData: order.takerAssetData,
|
||||
senderAddress: sender.address,
|
||||
orderHash: orderHashUtils.getOrderHashHex(order),
|
||||
};
|
||||
}
|
||||
|
||||
describe('executeTransaction', () => {
|
||||
describe('general functionality', () => {
|
||||
it('should log the correct transactionHash if successfully executed', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs(
|
||||
transactionReceipt.logs,
|
||||
[{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction) }],
|
||||
ExchangeEvents.TransactionExecution,
|
||||
);
|
||||
});
|
||||
it('should revert if the transaction is expired', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction = await takers[0].signTransactionAsync({
|
||||
data,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
transactionHashHex,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if the actual gasPrice is greater than expected', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const actualGasPrice = transaction.gasPrice.plus(1);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionGasPriceError(
|
||||
transactionHashHex,
|
||||
actualGasPrice,
|
||||
transaction.gasPrice,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ gasPrice: actualGasPrice, from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if the actual gasPrice is less than expected', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const actualGasPrice = transaction.gasPrice.minus(1);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionGasPriceError(
|
||||
transactionHashHex,
|
||||
actualGasPrice,
|
||||
transaction.gasPrice,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ gasPrice: actualGasPrice, from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
describe('fill methods', () => {
|
||||
for (const fnName of [
|
||||
...constants.SINGLE_FILL_FN_NAMES,
|
||||
...constants.BATCH_FILL_FN_NAMES,
|
||||
...constants.MARKET_FILL_FN_NAMES,
|
||||
]) {
|
||||
it(`${fnName} should revert if signature is invalid and not called by signer`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
transaction.signature = hexUtils.concat(hexUtils.random(65), SignatureType.EthSign);
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.BadTransactionSignature,
|
||||
transactionHashHex,
|
||||
transaction.signerAddress,
|
||||
transaction.signature,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should be successful if signed by taker and called by sender`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[defaultFillEvent(order)],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should be successful if called by taker without a transaction signature`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: takers[0].address });
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[{ ...defaultFillEvent(order), senderAddress: takers[0].address }],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
});
|
||||
it(`${fnName} should return the correct data if successful`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const returnData = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.callAsync({ from: sender.address });
|
||||
|
||||
const decodedReturnData = deployment.exchange.getABIDecodedReturnData(fnName, returnData);
|
||||
const fillResults = Array.isArray(decodedReturnData) ? decodedReturnData[0] : decodedReturnData;
|
||||
|
||||
expect(fillResults).to.deep.equal(
|
||||
ReferenceFunctions.calculateFillResults(
|
||||
order,
|
||||
order.takerAssetAmount,
|
||||
DeploymentManager.protocolFeeMultiplier,
|
||||
DeploymentManager.gasPrice,
|
||||
),
|
||||
);
|
||||
});
|
||||
it(`${fnName} should revert if transaction has already been executed`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.AlreadyExecuted,
|
||||
transactionHashHex,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should revert and rethrow error if executeTransaction is called recursively with a signature`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await takers[0].signTransactionAsync({
|
||||
data: recursiveData,
|
||||
});
|
||||
const recursiveTransactionHashHex = transactionHashUtils.getTransactionHashHex(
|
||||
recursiveTransaction,
|
||||
);
|
||||
const noReentrancyError = new ExchangeRevertErrors.TransactionInvalidContextError(
|
||||
transactionHashHex,
|
||||
transaction.signerAddress,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
recursiveTransactionHashHex,
|
||||
noReentrancyError,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it(`${fnName} should be successful if executeTransaction is called recursively by taker without a signature`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const recursiveData = deployment.exchange
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.getABIEncodedTransactionData();
|
||||
const recursiveTransaction = await takers[0].signTransactionAsync({
|
||||
data: recursiveData,
|
||||
});
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(recursiveTransaction, recursiveTransaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: takers[0].address });
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[{ ...defaultFillEvent(order), senderAddress: takers[0].address }],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
});
|
||||
if (
|
||||
[
|
||||
ExchangeFunctionName.FillOrderNoThrow,
|
||||
ExchangeFunctionName.BatchFillOrdersNoThrow,
|
||||
ExchangeFunctionName.MarketBuyOrdersNoThrow,
|
||||
ExchangeFunctionName.MarketSellOrdersNoThrow,
|
||||
ExchangeFunctionName.MarketBuyOrdersFillOrKill,
|
||||
ExchangeFunctionName.MarketSellOrdersFillOrKill,
|
||||
].indexOf(fnName) === -1
|
||||
) {
|
||||
it(`${fnName} should revert and rethrow error if the underlying function reverts`, async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
order.signature = constants.NULL_BYTES;
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const nestedError = new ExchangeRevertErrors.SignatureError(
|
||||
ExchangeRevertErrors.SignatureErrorCode.InvalidLength,
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAddress,
|
||||
order.signature,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
describe('cancelOrder', () => {
|
||||
it('should revert if not signed by or called by maker', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const nestedError = new ExchangeRevertErrors.ExchangeInvalidContextError(
|
||||
ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker,
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
takers[0].address,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should be successful if signed by maker and called by sender', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]);
|
||||
const transaction = await maker.signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs<ExchangeCancelEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[defaultCancelEvent(order)],
|
||||
ExchangeEvents.Cancel,
|
||||
);
|
||||
});
|
||||
it('should be successful if called by maker without a signature', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]);
|
||||
const transaction = await maker.signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: maker.address });
|
||||
verifyEventsFromLogs<ExchangeCancelEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[{ ...defaultCancelEvent(order), senderAddress: maker.address }],
|
||||
ExchangeEvents.Cancel,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('batchCancelOrders', () => {
|
||||
it('should revert if not signed by or called by maker', async () => {
|
||||
const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
orders,
|
||||
);
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionHashHex = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const nestedError = new ExchangeRevertErrors.ExchangeInvalidContextError(
|
||||
ExchangeRevertErrors.ExchangeContextErrorCodes.InvalidMaker,
|
||||
orderHashUtils.getOrderHashHex(orders[0]),
|
||||
takers[0].address,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashHex,
|
||||
nestedError,
|
||||
);
|
||||
const tx = deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should be successful if signed by maker and called by sender', async () => {
|
||||
const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
orders,
|
||||
);
|
||||
const transaction = await maker.signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs<ExchangeCancelEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[defaultCancelEvent(orders[0]), defaultCancelEvent(orders[1])],
|
||||
ExchangeEvents.Cancel,
|
||||
);
|
||||
});
|
||||
it('should be successful if called by maker without a signature', async () => {
|
||||
const orders = [await maker.signOrderAsync(), await maker.signOrderAsync()];
|
||||
const data = exchangeDataEncoder.encodeOrdersToExchangeData(
|
||||
ExchangeFunctionName.BatchCancelOrders,
|
||||
orders,
|
||||
);
|
||||
const transaction = await maker.signTransactionAsync({ data });
|
||||
transaction.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: maker.address });
|
||||
verifyEventsFromLogs<ExchangeCancelEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ ...defaultCancelEvent(orders[0]), senderAddress: maker.address },
|
||||
{ ...defaultCancelEvent(orders[1]), senderAddress: maker.address },
|
||||
],
|
||||
ExchangeEvents.Cancel,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('cancelOrdersUpTo', () => {
|
||||
it('should be successful if signed by maker and called by sender', async () => {
|
||||
const targetEpoch = constants.ZERO_AMOUNT;
|
||||
const data = deployment.exchange.cancelOrdersUpTo(targetEpoch).getABIEncodedTransactionData();
|
||||
const transaction = await maker.signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs<ExchangeCancelUpToEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{
|
||||
makerAddress: maker.address,
|
||||
orderSenderAddress: sender.address,
|
||||
orderEpoch: targetEpoch.plus(1),
|
||||
},
|
||||
],
|
||||
ExchangeEvents.CancelUpTo,
|
||||
);
|
||||
});
|
||||
it('should be successful if called by maker without a signature', async () => {
|
||||
const targetEpoch = constants.ZERO_AMOUNT;
|
||||
const data = deployment.exchange.cancelOrdersUpTo(targetEpoch).getABIEncodedTransactionData();
|
||||
const transaction = await maker.signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: maker.address });
|
||||
verifyEventsFromLogs<ExchangeCancelUpToEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{
|
||||
makerAddress: maker.address,
|
||||
orderSenderAddress: constants.NULL_ADDRESS,
|
||||
orderEpoch: targetEpoch.plus(1),
|
||||
},
|
||||
],
|
||||
ExchangeEvents.CancelUpTo,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('preSign', () => {
|
||||
it('should preSign a hash for the signer', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const orderHash = orderHashUtils.getOrderHashHex(order);
|
||||
const data = deployment.exchange.preSign(orderHash).getABIEncodedTransactionData();
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
let isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync();
|
||||
expect(isPreSigned).to.be.eq(false);
|
||||
await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync();
|
||||
expect(isPreSigned).to.be.eq(true);
|
||||
});
|
||||
it('should preSign a hash for the caller if called without a signature', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const orderHash = orderHashUtils.getOrderHashHex(order);
|
||||
const data = deployment.exchange.preSign(orderHash).getABIEncodedTransactionData();
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
let isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync();
|
||||
expect(isPreSigned).to.be.eq(false);
|
||||
await deployment.exchange
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: takers[0].address });
|
||||
isPreSigned = await deployment.exchange.preSigned(orderHash, takers[0].address).callAsync();
|
||||
expect(isPreSigned).to.be.eq(true);
|
||||
});
|
||||
});
|
||||
describe('setSignatureValidatorApproval', () => {
|
||||
it('should approve a validator for the signer', async () => {
|
||||
const validatorAddress = randomAddress();
|
||||
const shouldApprove = true;
|
||||
const data = deployment.exchange
|
||||
.setSignatureValidatorApproval(validatorAddress, shouldApprove)
|
||||
.getABIEncodedTransactionData();
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, transaction.signature)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs<ExchangeSignatureValidatorApprovalEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{
|
||||
signerAddress: takers[0].address,
|
||||
validatorAddress,
|
||||
isApproved: shouldApprove,
|
||||
},
|
||||
],
|
||||
ExchangeEvents.SignatureValidatorApproval,
|
||||
);
|
||||
});
|
||||
it('should approve a validator for the caller if called with no signature', async () => {
|
||||
const validatorAddress = randomAddress();
|
||||
const shouldApprove = true;
|
||||
const data = deployment.exchange
|
||||
.setSignatureValidatorApproval(validatorAddress, shouldApprove)
|
||||
.getABIEncodedTransactionData();
|
||||
const transaction = await takers[0].signTransactionAsync({ data });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.executeTransaction(transaction, constants.NULL_BYTES)
|
||||
.awaitTransactionSuccessAsync({ from: takers[0].address });
|
||||
verifyEventsFromLogs<ExchangeSignatureValidatorApprovalEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{
|
||||
signerAddress: takers[0].address,
|
||||
validatorAddress,
|
||||
isApproved: shouldApprove,
|
||||
},
|
||||
],
|
||||
ExchangeEvents.SignatureValidatorApproval,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('batchExecuteTransactions', () => {
|
||||
it('should successfully call fillOrder via 2 transactions with different taker signatures', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takers[1].signTransactionAsync({ data: data2 });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
verifyEventsFromLogs<ExchangeTransactionExecutionEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) },
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) },
|
||||
],
|
||||
ExchangeEvents.TransactionExecution,
|
||||
);
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[defaultFillEvent(order1), { ...defaultFillEvent(order2), takerAddress: takers[1].address }],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
});
|
||||
it('should successfully call fillOrder via 2 transactions when called by taker with no signatures', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takers[0].signTransactionAsync({ data: data2 });
|
||||
transaction1.signature = constants.NULL_BYTES;
|
||||
transaction2.signature = constants.NULL_BYTES;
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: takers[0].address });
|
||||
|
||||
verifyEventsFromLogs<ExchangeTransactionExecutionEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) },
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) },
|
||||
],
|
||||
ExchangeEvents.TransactionExecution,
|
||||
);
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ ...defaultFillEvent(order1), senderAddress: takers[0].address },
|
||||
{ ...defaultFillEvent(order2), senderAddress: takers[0].address },
|
||||
],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
});
|
||||
it('should successfully call fillOrder via 2 transactions when one is signed by taker1 and executeTransaction is called by taker2', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takers[1].signTransactionAsync({ data: data2 });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions([transaction1, transaction2], [transaction1.signature, constants.NULL_BYTES])
|
||||
.awaitTransactionSuccessAsync({ from: takers[1].address });
|
||||
|
||||
verifyEventsFromLogs<ExchangeTransactionExecutionEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) },
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) },
|
||||
],
|
||||
ExchangeEvents.TransactionExecution,
|
||||
);
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ ...defaultFillEvent(order1), senderAddress: takers[1].address },
|
||||
{
|
||||
...defaultFillEvent(order2),
|
||||
takerAddress: takers[1].address,
|
||||
senderAddress: takers[1].address,
|
||||
},
|
||||
],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
});
|
||||
it('should return the correct data for 2 different fillOrder calls', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takers[1].signTransactionAsync({ data: data2 });
|
||||
const returnData = await deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.callAsync({ from: sender.address });
|
||||
const fillResults1: FillResults = deployment.exchange.getABIDecodedReturnData('fillOrder', returnData[0]);
|
||||
const fillResults2: FillResults = deployment.exchange.getABIDecodedReturnData('fillOrder', returnData[1]);
|
||||
expect(fillResults1).to.deep.equal(
|
||||
ReferenceFunctions.calculateFillResults(
|
||||
order1,
|
||||
order1.takerAssetAmount,
|
||||
DeploymentManager.protocolFeeMultiplier,
|
||||
DeploymentManager.gasPrice,
|
||||
),
|
||||
);
|
||||
expect(fillResults2).to.deep.equal(
|
||||
ReferenceFunctions.calculateFillResults(
|
||||
order2,
|
||||
order2.takerAssetAmount,
|
||||
DeploymentManager.protocolFeeMultiplier,
|
||||
DeploymentManager.gasPrice,
|
||||
),
|
||||
);
|
||||
});
|
||||
it('should successfully call fillOrder and cancelOrder via 2 transactions', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order2]);
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await maker.signTransactionAsync({ data: data2 });
|
||||
const transactionReceipt = await deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
|
||||
verifyEventsFromLogs<ExchangeTransactionExecutionEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction1) },
|
||||
{ transactionHash: transactionHashUtils.getTransactionHashHex(transaction2) },
|
||||
],
|
||||
ExchangeEvents.TransactionExecution,
|
||||
);
|
||||
|
||||
const fillLogIndex = transactionReceipt.logs.findIndex(
|
||||
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
|
||||
);
|
||||
const cancelLogIndex = transactionReceipt.logs.findIndex(
|
||||
log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
|
||||
);
|
||||
expect(cancelLogIndex).to.greaterThan(fillLogIndex);
|
||||
|
||||
verifyEventsFromLogs<ExchangeFillEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[defaultFillEvent(order1)],
|
||||
ExchangeEvents.Fill,
|
||||
);
|
||||
verifyEventsFromLogs<ExchangeCancelEventArgs>(
|
||||
transactionReceipt.logs,
|
||||
[defaultCancelEvent(order2)],
|
||||
ExchangeEvents.Cancel,
|
||||
);
|
||||
});
|
||||
it('should return the correct data for a fillOrder and cancelOrder call', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order2]);
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await maker.signTransactionAsync({ data: data2 });
|
||||
const returnData = await deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.callAsync({ from: sender.address });
|
||||
const fillResults: FillResults = deployment.exchange.getABIDecodedReturnData('fillOrder', returnData[0]);
|
||||
expect(fillResults).to.deep.equal(
|
||||
ReferenceFunctions.calculateFillResults(
|
||||
order1,
|
||||
order1.takerAssetAmount,
|
||||
DeploymentManager.protocolFeeMultiplier,
|
||||
DeploymentManager.gasPrice,
|
||||
),
|
||||
);
|
||||
expect(returnData[1]).to.eq(constants.NULL_BYTES);
|
||||
});
|
||||
it('should revert if a single transaction reverts', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrder, [order]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order]);
|
||||
const transaction1 = await maker.signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takers[0].signTransactionAsync({ data: data2 });
|
||||
const tx = deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
const nestedError = new ExchangeRevertErrors.OrderStatusError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
OrderStatus.Cancelled,
|
||||
).encode();
|
||||
const expectedError = new ExchangeRevertErrors.TransactionExecutionError(
|
||||
transactionHashUtils.getTransactionHashHex(transaction2),
|
||||
nestedError,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('should revert if a single transaction is expired', async () => {
|
||||
const order1 = await maker.signOrderAsync();
|
||||
const order2 = await maker.signOrderAsync();
|
||||
const data1 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order1]);
|
||||
const data2 = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.FillOrder, [order2]);
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
const transaction1 = await takers[0].signTransactionAsync({ data: data1 });
|
||||
const transaction2 = await takers[1].signTransactionAsync({
|
||||
data: data2,
|
||||
expirationTimeSeconds: new BigNumber(currentTimestamp).minus(10),
|
||||
});
|
||||
const tx = deployment.exchange
|
||||
.batchExecuteTransactions(
|
||||
[transaction1, transaction2],
|
||||
[transaction1.signature, transaction2.signature],
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: sender.address });
|
||||
const expiredTransactionHash = transactionHashUtils.getTransactionHashHex(transaction2);
|
||||
const expectedError = new ExchangeRevertErrors.TransactionError(
|
||||
ExchangeRevertErrors.TransactionErrorCode.Expired,
|
||||
expiredTransactionHash,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,16 +1,10 @@
|
||||
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
import { ForwarderContract } from '@0x/contracts-exchange-forwarder';
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
getLatestBlockTimestampAsync,
|
||||
hexConcat,
|
||||
toBaseUnitAmount,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, getLatestBlockTimestampAsync, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { SignatureType, SignedOrder } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, ExchangeForwarderRevertErrors } from '@0x/utils';
|
||||
import { AbiEncoder, BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils';
|
||||
|
||||
import { deployEth2DaiBridgeAsync } from '../bridges/deploy_eth2dai_bridge';
|
||||
import { deployUniswapBridgeAsync } from '../bridges/deploy_uniswap_bridge';
|
||||
@@ -111,7 +105,7 @@ blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => {
|
||||
takerFeeAssetData: wethAssetData,
|
||||
expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(fifteenMinutesInSeconds),
|
||||
salt: generatePseudoRandomSalt(),
|
||||
signature: hexConcat(SignatureType.Wallet),
|
||||
signature: hexUtils.concat(SignatureType.Wallet),
|
||||
};
|
||||
eth2DaiBridgeOrder = {
|
||||
...orderDefaults,
|
||||
@@ -152,11 +146,11 @@ blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => {
|
||||
const tokenIds = { erc721: { [erc721Token.address]: [nftId] } };
|
||||
balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts, tokenIds);
|
||||
|
||||
testFactory = new ForwarderTestFactory(forwarder, deployment, balanceStore, taker, forwarderFeeRecipient);
|
||||
testFactory = new ForwarderTestFactory(forwarder, deployment, balanceStore, taker);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
describe('marketSellOrdersWithEth', () => {
|
||||
@@ -199,7 +193,10 @@ blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => {
|
||||
eth2DaiBridgeOrder,
|
||||
await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20
|
||||
];
|
||||
await testFactory.marketSellTestAsync(orders, 2.56, { forwarderFeePercentage: 1 });
|
||||
await testFactory.marketSellTestAsync(orders, 2.56, {
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.1)],
|
||||
forwarderFeeRecipientAddresses: [forwarderFeeRecipient.address],
|
||||
});
|
||||
});
|
||||
it('should fully fill a single UniswapBridge order without a taker fee', async () => {
|
||||
await testFactory.marketSellTestAsync([uniswapBridgeOrder], 1);
|
||||
@@ -240,7 +237,7 @@ blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => {
|
||||
uniswapBridgeOrder,
|
||||
await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20
|
||||
];
|
||||
await testFactory.marketSellTestAsync(orders, 2.56, { forwarderFeePercentage: 1 });
|
||||
await testFactory.marketSellTestAsync(orders, 2.56);
|
||||
});
|
||||
it('should fill multiple bridge orders', async () => {
|
||||
await testFactory.marketSellTestAsync([eth2DaiBridgeOrder, uniswapBridgeOrder], 1.23);
|
||||
@@ -298,7 +295,10 @@ blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => {
|
||||
eth2DaiBridgeOrder,
|
||||
await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20
|
||||
];
|
||||
await testFactory.marketBuyTestAsync(orders, 2.56, { forwarderFeePercentage: 1 });
|
||||
await testFactory.marketBuyTestAsync(orders, 2.56, {
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.1)],
|
||||
forwarderFeeRecipientAddresses: [forwarderFeeRecipient.address],
|
||||
});
|
||||
});
|
||||
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount (Eth2Dai)', async () => {
|
||||
const expectedError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError(
|
||||
@@ -349,7 +349,7 @@ blockchainTests.resets('Forwarder <> ERC20Bridge integration tests', env => {
|
||||
uniswapBridgeOrder,
|
||||
await maker.signOrderAsync({ makerAssetData: makerTokenAssetData }), // Non-bridge order of the same ERC20
|
||||
];
|
||||
await testFactory.marketBuyTestAsync(orders, 2.56, { forwarderFeePercentage: 1 });
|
||||
await testFactory.marketBuyTestAsync(orders, 2.56);
|
||||
});
|
||||
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount (Uniswap)', async () => {
|
||||
const expectedError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError(
|
||||
|
@@ -7,7 +7,7 @@ import {
|
||||
constants,
|
||||
expect,
|
||||
getLatestBlockTimestampAsync,
|
||||
getPercentageOfValue,
|
||||
randomAddress,
|
||||
toBaseUnitAmount,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
@@ -102,11 +102,11 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
const tokenIds = { erc721: { [erc721Token.address]: [nftId] } };
|
||||
balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts, tokenIds);
|
||||
|
||||
testFactory = new ForwarderTestFactory(forwarder, deployment, balanceStore, taker, forwarderFeeRecipient);
|
||||
testFactory = new ForwarderTestFactory(forwarder, deployment, balanceStore, taker);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.count = 0;
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
blockchainTests.resets('constructor', () => {
|
||||
@@ -180,12 +180,7 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
// Execute test case
|
||||
const tx = await forwarder
|
||||
.marketSellOrdersWithEth(
|
||||
[order],
|
||||
[order.signature],
|
||||
constants.ZERO_AMOUNT,
|
||||
forwarderFeeRecipient.address,
|
||||
)
|
||||
.marketSellOrdersWithEth([order], [order.signature], [], [])
|
||||
.awaitTransactionSuccessAsync({
|
||||
value: order.takerAssetAmount.plus(DeploymentManager.protocolFee),
|
||||
from: taker.address,
|
||||
@@ -224,12 +219,7 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
const ethValue = order.takerAssetAmount.plus(DeploymentManager.protocolFee).plus(2);
|
||||
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(taker.address);
|
||||
const tx = await forwarder
|
||||
.marketSellOrdersWithEth(
|
||||
[order],
|
||||
[order.signature],
|
||||
constants.ZERO_AMOUNT,
|
||||
forwarderFeeRecipient.address,
|
||||
)
|
||||
.marketSellOrdersWithEth([order], [order.signature], [], [])
|
||||
.awaitTransactionSuccessAsync({
|
||||
value: ethValue,
|
||||
from: taker.address,
|
||||
@@ -312,17 +302,83 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeePercentage: new BigNumber(2),
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.2)],
|
||||
forwarderFeeRecipientAddresses: [forwarderFeeRecipient.address],
|
||||
});
|
||||
});
|
||||
it('should fail if the fee is set too high', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const forwarderFeePercentage = new BigNumber(6);
|
||||
const revertError = new ExchangeForwarderRevertErrors.FeePercentageTooLargeError(
|
||||
getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
|
||||
it('should fill the order and send the same fees to different feeRecipient addresses', async () => {
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: toBaseUnitAmount(157),
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.2)],
|
||||
forwarderFeeRecipientAddresses: [randomAddress(), randomAddress()],
|
||||
});
|
||||
});
|
||||
it('should fill the order and send different fees to different feeRecipient addresses', async () => {
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: toBaseUnitAmount(157),
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.1)],
|
||||
forwarderFeeRecipientAddresses: [randomAddress(), randomAddress()],
|
||||
});
|
||||
});
|
||||
it('should fill the order and send the same fees to multiple instances of the same feeRecipient address', async () => {
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: toBaseUnitAmount(157),
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
const feeRecipient = randomAddress();
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.2)],
|
||||
forwarderFeeRecipientAddresses: [feeRecipient, feeRecipient],
|
||||
});
|
||||
});
|
||||
it('should fill the order and send different fees to multiple instances of the same feeRecipient address', async () => {
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: toBaseUnitAmount(157),
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
const feeRecipient = randomAddress();
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.2), toBaseUnitAmount(0.1)],
|
||||
forwarderFeeRecipientAddresses: [feeRecipient, feeRecipient],
|
||||
});
|
||||
});
|
||||
it('should fail if ethFeeAmounts is longer than feeRecipients', async () => {
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: toBaseUnitAmount(157),
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
const forwarderFeeAmounts = [toBaseUnitAmount(0.2)];
|
||||
const forwarderFeeRecipientAddresses: string[] = [];
|
||||
const revertError = new ExchangeForwarderRevertErrors.EthFeeLengthMismatchError(
|
||||
new BigNumber(forwarderFeeAmounts.length),
|
||||
new BigNumber(forwarderFeeRecipientAddresses.length),
|
||||
);
|
||||
await testFactory.marketSellTestAsync([order], 0.5, {
|
||||
forwarderFeePercentage,
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeeAmounts,
|
||||
forwarderFeeRecipientAddresses,
|
||||
revertError,
|
||||
});
|
||||
});
|
||||
it('should fail if feeRecipients is longer than ethFeeAmounts', async () => {
|
||||
const order = await maker.signOrderAsync({
|
||||
makerAssetAmount: toBaseUnitAmount(157),
|
||||
takerAssetAmount: toBaseUnitAmount(36),
|
||||
});
|
||||
const forwarderFeeAmounts: BigNumber[] = [];
|
||||
const forwarderFeeRecipientAddresses = [randomAddress()];
|
||||
const revertError = new ExchangeForwarderRevertErrors.EthFeeLengthMismatchError(
|
||||
new BigNumber(forwarderFeeAmounts.length),
|
||||
new BigNumber(forwarderFeeRecipientAddresses.length),
|
||||
);
|
||||
await testFactory.marketSellTestAsync([order], 0.67, {
|
||||
forwarderFeeAmounts,
|
||||
forwarderFeeRecipientAddresses,
|
||||
revertError,
|
||||
});
|
||||
});
|
||||
@@ -497,13 +553,7 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
// Execute test case
|
||||
const tx = await forwarder
|
||||
.marketBuyOrdersWithEth(
|
||||
[order],
|
||||
desiredMakerAssetFillAmount,
|
||||
[order.signature],
|
||||
constants.ZERO_AMOUNT,
|
||||
forwarderFeeRecipient.address,
|
||||
)
|
||||
.marketBuyOrdersWithEth([order], desiredMakerAssetFillAmount, [order.signature], [], [])
|
||||
.awaitTransactionSuccessAsync({
|
||||
value: ethValue,
|
||||
from: taker.address,
|
||||
@@ -511,20 +561,10 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
|
||||
// Compute expected balances
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
await expectedBalances.transferAssetAsync(
|
||||
maker.address,
|
||||
taker.address,
|
||||
makerAssetFillAmount,
|
||||
makerAssetData,
|
||||
);
|
||||
expectedBalances.transferAsset(maker.address, taker.address, makerAssetFillAmount, makerAssetData);
|
||||
expectedBalances.wrapEth(taker.address, deployment.tokens.weth.address, ethValue);
|
||||
await expectedBalances.transferAssetAsync(
|
||||
taker.address,
|
||||
maker.address,
|
||||
primaryTakerAssetFillAmount,
|
||||
wethAssetData,
|
||||
);
|
||||
await expectedBalances.transferAssetAsync(
|
||||
expectedBalances.transferAsset(taker.address, maker.address, primaryTakerAssetFillAmount, wethAssetData);
|
||||
expectedBalances.transferAsset(
|
||||
taker.address,
|
||||
deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
@@ -554,13 +594,7 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
await balanceStore.updateBalancesAsync();
|
||||
// Execute test case
|
||||
const tx = await forwarder
|
||||
.marketBuyOrdersWithEth(
|
||||
[order],
|
||||
desiredMakerAssetFillAmount,
|
||||
[order.signature],
|
||||
constants.ZERO_AMOUNT,
|
||||
forwarderFeeRecipient.address,
|
||||
)
|
||||
.marketBuyOrdersWithEth([order], desiredMakerAssetFillAmount, [order.signature], [], [])
|
||||
.awaitTransactionSuccessAsync({
|
||||
value: takerAssetFillAmount.plus(DeploymentManager.protocolFee),
|
||||
from: taker.address,
|
||||
@@ -568,24 +602,14 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
|
||||
// Compute expected balances
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
await expectedBalances.transferAssetAsync(
|
||||
maker.address,
|
||||
taker.address,
|
||||
makerAssetFillAmount,
|
||||
makerAssetData,
|
||||
);
|
||||
expectedBalances.transferAsset(maker.address, taker.address, makerAssetFillAmount, makerAssetData);
|
||||
expectedBalances.wrapEth(
|
||||
taker.address,
|
||||
deployment.tokens.weth.address,
|
||||
takerAssetFillAmount.plus(DeploymentManager.protocolFee),
|
||||
);
|
||||
await expectedBalances.transferAssetAsync(
|
||||
taker.address,
|
||||
maker.address,
|
||||
takerAssetFillAmount,
|
||||
wethAssetData,
|
||||
);
|
||||
await expectedBalances.transferAssetAsync(
|
||||
expectedBalances.transferAsset(taker.address, maker.address, takerAssetFillAmount, wethAssetData);
|
||||
expectedBalances.transferAsset(
|
||||
taker.address,
|
||||
deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
@@ -605,31 +629,37 @@ blockchainTests('Forwarder integration tests', env => {
|
||||
takerAssetAmount: toBaseUnitAmount(11),
|
||||
});
|
||||
await testFactory.marketBuyTestAsync([order], 0.33, {
|
||||
forwarderFeePercentage: new BigNumber(2),
|
||||
forwarderFeeAmounts: [toBaseUnitAmount(0.2)],
|
||||
forwarderFeeRecipientAddresses: [randomAddress()],
|
||||
});
|
||||
});
|
||||
it('should fail if the fee is set too high', async () => {
|
||||
it('should fail if there is not enough ETH remaining to complete the fill', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const revertError = new ExchangeForwarderRevertErrors.FeePercentageTooLargeError(
|
||||
getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, new BigNumber(6)),
|
||||
const forwarderFeeAmounts = [toBaseUnitAmount(1)];
|
||||
const revertError = new ExchangeForwarderRevertErrors.CompleteBuyFailedError(
|
||||
order.takerAssetAmount,
|
||||
constants.ZERO_AMOUNT,
|
||||
);
|
||||
await testFactory.marketBuyTestAsync([order], 0.5, {
|
||||
forwarderFeePercentage: new BigNumber(6),
|
||||
ethValueAdjustment: -1,
|
||||
forwarderFeeAmounts,
|
||||
forwarderFeeRecipientAddresses: [randomAddress()],
|
||||
revertError,
|
||||
});
|
||||
});
|
||||
it('should fail if there is not enough ETH remaining to pay the fee', async () => {
|
||||
const order = await maker.signOrderAsync();
|
||||
const forwarderFeePercentage = new BigNumber(2);
|
||||
const ethFee = getPercentageOfValue(
|
||||
order.takerAssetAmount.times(0.5).plus(DeploymentManager.protocolFee),
|
||||
forwarderFeePercentage,
|
||||
const forwarderFeeAmounts = [toBaseUnitAmount(1)];
|
||||
const value = forwarderFeeAmounts[0].minus(1);
|
||||
const revertError = new ExchangeForwarderRevertErrors.InsufficientEthForFeeError(
|
||||
forwarderFeeAmounts[0],
|
||||
value,
|
||||
);
|
||||
const revertError = new ExchangeForwarderRevertErrors.InsufficientEthForFeeError(ethFee, ethFee.minus(1));
|
||||
await testFactory.marketBuyTestAsync([order], 0.5, {
|
||||
ethValueAdjustment: -1,
|
||||
forwarderFeePercentage,
|
||||
await testFactory.marketBuyTestAsync([order], 0, {
|
||||
revertError,
|
||||
ethValueAdjustment: -1,
|
||||
forwarderFeeAmounts,
|
||||
forwarderFeeRecipientAddresses: [randomAddress()],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,19 +1,10 @@
|
||||
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
|
||||
import { ForwarderContract } from '@0x/contracts-exchange-forwarder';
|
||||
import {
|
||||
constants,
|
||||
expect,
|
||||
getPercentageOfValue,
|
||||
hexSlice,
|
||||
Numberish,
|
||||
OrderStatus,
|
||||
provider,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { constants, expect, OrderStatus, provider } from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId, OrderInfo, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, RevertError } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, RevertError } from '@0x/utils';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
|
||||
import { FeeRecipient } from '../framework/actors/fee_recipient';
|
||||
import { Taker } from '../framework/actors/taker';
|
||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||
import { LocalBalanceStore } from '../framework/balances/local_balance_store';
|
||||
@@ -27,7 +18,8 @@ interface ForwarderFillState {
|
||||
}
|
||||
|
||||
interface MarketSellOptions {
|
||||
forwarderFeePercentage: Numberish;
|
||||
forwarderFeeAmounts: BigNumber[];
|
||||
forwarderFeeRecipientAddresses: string[];
|
||||
revertError: RevertError;
|
||||
bridgeExcessBuyAmount: BigNumber;
|
||||
}
|
||||
@@ -37,8 +29,8 @@ interface MarketBuyOptions extends MarketSellOptions {
|
||||
}
|
||||
|
||||
function areUnderlyingAssetsEqual(assetData1: string, assetData2: string): boolean {
|
||||
const assetProxyId1 = hexSlice(assetData1, 0, 4);
|
||||
const assetProxyId2 = hexSlice(assetData2, 0, 4);
|
||||
const assetProxyId1 = hexUtils.slice(assetData1, 0, 4);
|
||||
const assetProxyId2 = hexUtils.slice(assetData2, 0, 4);
|
||||
if (
|
||||
(assetProxyId1 === AssetProxyId.ERC20 || assetProxyId1 === AssetProxyId.ERC20Bridge) &&
|
||||
(assetProxyId2 === AssetProxyId.ERC20 || assetProxyId2 === AssetProxyId.ERC20Bridge)
|
||||
@@ -64,7 +56,6 @@ export class ForwarderTestFactory {
|
||||
private readonly _deployment: DeploymentManager,
|
||||
private readonly _balanceStore: BlockchainBalanceStore,
|
||||
private readonly _taker: Taker,
|
||||
private readonly _forwarderFeeRecipient: FeeRecipient,
|
||||
) {}
|
||||
|
||||
public async marketBuyTestAsync(
|
||||
@@ -73,7 +64,8 @@ export class ForwarderTestFactory {
|
||||
options: Partial<MarketBuyOptions> = {},
|
||||
): Promise<void> {
|
||||
const ethValueAdjustment = options.ethValueAdjustment || 0;
|
||||
const forwarderFeePercentage = options.forwarderFeePercentage || 0;
|
||||
const forwarderFeeAmounts = options.forwarderFeeAmounts || [];
|
||||
const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || [];
|
||||
|
||||
const orderInfoBefore = await Promise.all(
|
||||
orders.map(order => this._deployment.exchange.getOrderInfo(order).callAsync()),
|
||||
@@ -90,19 +82,16 @@ export class ForwarderTestFactory {
|
||||
makerAssetAcquiredAmount,
|
||||
} = await this._simulateForwarderFillAsync(orders, orderInfoBefore, fractionalNumberOfOrdersToFill, options);
|
||||
|
||||
const ethSpentOnForwarderFee = getPercentageOfValue(wethSpentAmount, forwarderFeePercentage);
|
||||
const feePercentage = getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage);
|
||||
|
||||
const tx = this._forwarder
|
||||
.marketBuyOrdersWithEth(
|
||||
orders,
|
||||
makerAssetAcquiredAmount.minus(options.bridgeExcessBuyAmount || 0),
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
feePercentage,
|
||||
this._forwarderFeeRecipient.address,
|
||||
forwarderFeeAmounts,
|
||||
forwarderFeeRecipientAddresses,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({
|
||||
value: wethSpentAmount.plus(ethSpentOnForwarderFee).plus(ethValueAdjustment),
|
||||
value: wethSpentAmount.plus(BigNumber.sum(0, ...forwarderFeeAmounts)).plus(ethValueAdjustment),
|
||||
from: this._taker.address,
|
||||
});
|
||||
|
||||
@@ -135,19 +124,18 @@ export class ForwarderTestFactory {
|
||||
options,
|
||||
);
|
||||
|
||||
const forwarderFeePercentage = options.forwarderFeePercentage || 0;
|
||||
const ethSpentOnForwarderFee = getPercentageOfValue(wethSpentAmount, forwarderFeePercentage);
|
||||
const feePercentage = getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage);
|
||||
const forwarderFeeAmounts = options.forwarderFeeAmounts || [];
|
||||
const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || [];
|
||||
|
||||
const tx = this._forwarder
|
||||
.marketSellOrdersWithEth(
|
||||
orders,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
feePercentage,
|
||||
this._forwarderFeeRecipient.address,
|
||||
forwarderFeeAmounts,
|
||||
forwarderFeeRecipientAddresses,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({
|
||||
value: wethSpentAmount.plus(ethSpentOnForwarderFee),
|
||||
value: wethSpentAmount.plus(BigNumber.sum(0, ...forwarderFeeAmounts)),
|
||||
from: this._taker.address,
|
||||
});
|
||||
|
||||
@@ -192,6 +180,15 @@ export class ForwarderTestFactory {
|
||||
): Promise<ForwarderFillState> {
|
||||
await this._balanceStore.updateBalancesAsync();
|
||||
const balances = LocalBalanceStore.create(this._balanceStore);
|
||||
|
||||
const forwarderFeeAmounts = options.forwarderFeeAmounts || [];
|
||||
const forwarderFeeRecipientAddresses = options.forwarderFeeRecipientAddresses || [];
|
||||
|
||||
forwarderFeeAmounts.forEach((feeAmount, i) =>
|
||||
// In reality the Forwarder is a middleman in this transaction and the ETH gets wrapped and unwrapped.
|
||||
balances.sendEth(this._taker.address, forwarderFeeRecipientAddresses[i], feeAmount),
|
||||
);
|
||||
|
||||
const currentTotal = {
|
||||
wethSpentAmount: constants.ZERO_AMOUNT,
|
||||
makerAssetAcquiredAmount: constants.ZERO_AMOUNT,
|
||||
@@ -207,7 +204,7 @@ export class ForwarderTestFactory {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { wethSpentAmount, makerAssetAcquiredAmount } = await this._simulateSingleFillAsync(
|
||||
const { wethSpentAmount, makerAssetAcquiredAmount } = this._simulateSingleFill(
|
||||
balances,
|
||||
order,
|
||||
ordersInfoBefore[i].orderTakerAssetFilledAmount,
|
||||
@@ -222,23 +219,16 @@ export class ForwarderTestFactory {
|
||||
);
|
||||
}
|
||||
|
||||
const ethSpentOnForwarderFee = getPercentageOfValue(
|
||||
currentTotal.wethSpentAmount,
|
||||
options.forwarderFeePercentage || 0,
|
||||
);
|
||||
// In reality the Forwarder is a middleman in this transaction and the ETH gets wrapped and unwrapped.
|
||||
balances.sendEth(this._taker.address, this._forwarderFeeRecipient.address, ethSpentOnForwarderFee);
|
||||
|
||||
return { ...currentTotal, balances };
|
||||
}
|
||||
|
||||
private async _simulateSingleFillAsync(
|
||||
private _simulateSingleFill(
|
||||
balances: LocalBalanceStore,
|
||||
order: SignedOrder,
|
||||
takerAssetFilled: BigNumber,
|
||||
fillFraction: number,
|
||||
bridgeExcessBuyAmount: BigNumber,
|
||||
): Promise<ForwarderFillState> {
|
||||
): ForwarderFillState {
|
||||
let { makerAssetAmount, takerAssetAmount, makerFee, takerFee } = order;
|
||||
makerAssetAmount = makerAssetAmount.times(fillFraction).integerValue(BigNumber.ROUND_CEIL);
|
||||
takerAssetAmount = takerAssetAmount.times(fillFraction).integerValue(BigNumber.ROUND_CEIL);
|
||||
@@ -272,43 +262,23 @@ export class ForwarderTestFactory {
|
||||
balances.wrapEth(this._forwarder.address, this._deployment.tokens.weth.address, wethSpentAmount);
|
||||
// (In reality this is done all at once, but we simulate it order by order)
|
||||
|
||||
// Maker -> Forwarder
|
||||
await balances.transferAssetAsync(
|
||||
order.makerAddress,
|
||||
this._forwarder.address,
|
||||
makerAssetAmount,
|
||||
order.makerAssetData,
|
||||
);
|
||||
// Maker -> Order fee recipient
|
||||
await balances.transferAssetAsync(
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
makerFee,
|
||||
order.makerFeeAssetData,
|
||||
);
|
||||
// Forwarder -> Maker
|
||||
await balances.transferAssetAsync(
|
||||
this._forwarder.address,
|
||||
order.makerAddress,
|
||||
takerAssetAmount,
|
||||
order.takerAssetData,
|
||||
);
|
||||
balances.transferAsset(this._forwarder.address, order.makerAddress, takerAssetAmount, order.takerAssetData);
|
||||
// Maker -> Forwarder
|
||||
balances.transferAsset(order.makerAddress, this._forwarder.address, makerAssetAmount, order.makerAssetData);
|
||||
// Forwarder -> Order fee recipient
|
||||
await balances.transferAssetAsync(
|
||||
this._forwarder.address,
|
||||
order.feeRecipientAddress,
|
||||
takerFee,
|
||||
order.takerFeeAssetData,
|
||||
);
|
||||
balances.transferAsset(this._forwarder.address, order.feeRecipientAddress, takerFee, order.takerFeeAssetData);
|
||||
// Maker -> Order fee recipient
|
||||
balances.transferAsset(order.makerAddress, order.feeRecipientAddress, makerFee, order.makerFeeAssetData);
|
||||
// Forwarder pays the protocol fee in WETH
|
||||
await balances.transferAssetAsync(
|
||||
balances.transferAsset(
|
||||
this._forwarder.address,
|
||||
this._deployment.staking.stakingProxy.address,
|
||||
DeploymentManager.protocolFee,
|
||||
order.takerAssetData,
|
||||
);
|
||||
// Forwarder gives acquired maker asset to taker
|
||||
await balances.transferAssetAsync(
|
||||
balances.transferAsset(
|
||||
this._forwarder.address,
|
||||
this._taker.address,
|
||||
makerAssetAcquiredAmount,
|
||||
|
@@ -31,6 +31,10 @@ export class Actor {
|
||||
} = {};
|
||||
protected readonly _transactionFactory: TransactionFactory;
|
||||
|
||||
public static reset(): void {
|
||||
Actor.count = 0;
|
||||
}
|
||||
|
||||
constructor(config: ActorConfig) {
|
||||
Actor.count++;
|
||||
|
||||
@@ -142,6 +146,12 @@ export class Actor {
|
||||
customTransactionParams: Partial<ZeroExTransaction>,
|
||||
signatureType: SignatureType = SignatureType.EthSign,
|
||||
): Promise<SignedZeroExTransaction> {
|
||||
return this._transactionFactory.newSignedTransactionAsync(customTransactionParams, signatureType);
|
||||
return this._transactionFactory.newSignedTransactionAsync(
|
||||
{
|
||||
gasPrice: DeploymentManager.gasPrice,
|
||||
...customTransactionParams,
|
||||
},
|
||||
signatureType,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -3,9 +3,11 @@ import { KeeperMixin } from './keeper';
|
||||
import { MakerMixin } from './maker';
|
||||
import { PoolOperatorMixin } from './pool_operator';
|
||||
import { StakerMixin } from './staker';
|
||||
import { TakerMixin } from './taker';
|
||||
|
||||
export class OperatorMaker extends PoolOperatorMixin(MakerMixin(Actor)) {}
|
||||
export class StakerMaker extends StakerMixin(MakerMixin(Actor)) {}
|
||||
export class StakerOperator extends StakerMixin(PoolOperatorMixin(Actor)) {}
|
||||
export class OperatorStakerMaker extends PoolOperatorMixin(StakerMixin(MakerMixin(Actor))) {}
|
||||
export class StakerKeeper extends StakerMixin(KeeperMixin(Actor)) {}
|
||||
export class MakerTaker extends MakerMixin(TakerMixin(Actor)) {}
|
||||
|
@@ -1,6 +1,10 @@
|
||||
import { constants, OrderFactory, orderUtils } from '@0x/contracts-test-utils';
|
||||
import { constants, OrderFactory } from '@0x/contracts-test-utils';
|
||||
import { Order, SignedOrder } from '@0x/types';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { AssertionResult } from '../assertions/function_assertion';
|
||||
import { validJoinStakingPoolAssertion } from '../assertions/joinStakingPool';
|
||||
|
||||
import { Actor, ActorConfig, Constructor } from './base';
|
||||
|
||||
@@ -45,6 +49,12 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
||||
...orderConfig,
|
||||
};
|
||||
this.orderFactory = new OrderFactory(this.actor.privateKey, defaultOrderParams);
|
||||
|
||||
// Register this mixin's assertion generators
|
||||
this.actor.simulationActions = {
|
||||
...this.actor.simulationActions,
|
||||
validJoinStakingPool: this._validJoinStakingPool(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,8 +68,7 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
||||
* Cancels one of the maker's orders.
|
||||
*/
|
||||
public async cancelOrderAsync(order: SignedOrder): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createCancel(order);
|
||||
return this.actor.deployment.exchange.cancelOrder(params.order).awaitTransactionSuccessAsync({
|
||||
return this.actor.deployment.exchange.cancelOrder(order).awaitTransactionSuccessAsync({
|
||||
from: this.actor.address,
|
||||
});
|
||||
}
|
||||
@@ -74,6 +83,19 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
||||
from: this.actor.address,
|
||||
});
|
||||
}
|
||||
|
||||
private async *_validJoinStakingPool(): AsyncIterableIterator<AssertionResult | void> {
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validJoinStakingPoolAssertion(this.actor.deployment);
|
||||
while (true) {
|
||||
const poolId = _.sample(Object.keys(stakingPools));
|
||||
if (poolId === undefined) {
|
||||
yield undefined;
|
||||
} else {
|
||||
yield assertion.executeAsync([poolId], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -83,8 +83,8 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools);
|
||||
while (true) {
|
||||
const operatorShare = getRandomInteger(0, constants.PPM);
|
||||
yield assertion.executeAsync(operatorShare, false, { from: this.actor.address });
|
||||
const operatorShare = getRandomInteger(0, constants.PPM).toNumber();
|
||||
yield assertion.executeAsync([operatorShare, false], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +96,8 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
||||
if (poolId === undefined) {
|
||||
yield undefined;
|
||||
} else {
|
||||
const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare);
|
||||
yield assertion.executeAsync(poolId, operatorShare, { from: this.actor.address });
|
||||
const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare).toNumber();
|
||||
yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user