Compare commits
88 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
51ca3109eb | ||
|
2bcb79dc44 | ||
|
ecec985649 | ||
|
994908549d | ||
|
6808e0d531 | ||
|
410c95308a | ||
|
bec1f23616 | ||
|
34596b7f83 | ||
|
5ca7169ee5 | ||
|
3300aaa1b9 | ||
|
54afc8a4a1 | ||
|
f19f4310f4 | ||
|
444125a7e1 | ||
|
56cbb69401 | ||
|
70870ffcd2 | ||
|
a556d91673 | ||
|
8ecbde8e1e | ||
|
a24b293818 | ||
|
cab5ebf94b | ||
|
a54b5baef2 | ||
|
c324fe204e | ||
|
37d972ed9e | ||
|
e4a3b1cb05 | ||
|
49538f272e | ||
|
1283232144 | ||
|
2f9891f0aa | ||
|
865a2b1fb0 | ||
|
1fde62eeb6 | ||
|
6754cd48e2 | ||
|
ccb477687a | ||
|
be0e6c8925 | ||
|
1c2cb947c0 | ||
|
4663eec950 | ||
|
fff3c1eb36 | ||
|
4b7434d1e8 | ||
|
8cc35a60e6 | ||
|
130653a1aa | ||
|
1dcbebd130 | ||
|
faf306ad23 | ||
|
d11cdcd5d2 | ||
|
0e59bd0bf3 | ||
|
c0c6154ec1 | ||
|
cb5384c2fb | ||
|
038c836fe5 | ||
|
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,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
@@ -55,6 +73,10 @@
|
||||
{
|
||||
"note": "Implement `KyberBridge`.",
|
||||
"pr": 2352
|
||||
},
|
||||
{
|
||||
"note": "Implement `DydxBridge`.",
|
||||
"pr": 2365
|
||||
}
|
||||
],
|
||||
"timestamp": 1575290197
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.0 - _December 2, 2019_
|
||||
|
||||
* Implement `KyberBridge`. (#2352)
|
||||
@@ -22,6 +30,7 @@ CHANGELOG
|
||||
## v2.3.0-beta.4 - _December 2, 2019_
|
||||
|
||||
* Implement `KyberBridge`. (#2352)
|
||||
* Implement `DydxBridge`. (#2365)
|
||||
|
||||
## v2.3.0-beta.3 - _November 20, 2019_
|
||||
|
||||
|
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;
|
||||
}
|
||||
}
|
241
contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
Normal file
241
contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
|
||||
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 "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IDydxBridge.sol";
|
||||
import "../interfaces/IDydx.sol";
|
||||
|
||||
|
||||
contract DydxBridge is
|
||||
IERC20Bridge,
|
||||
IDydxBridge,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account.
|
||||
/// Notes:
|
||||
/// 1. This bridge must be set as an operator of the input dydx account.
|
||||
/// 2. This function may only be called in the context of the 0x Exchange.
|
||||
/// 3. The maker or taker of the 0x order must be the dydx account owner.
|
||||
/// 4. Deposits into dydx are made from the `from` address.
|
||||
/// 5. Withdrawals from dydx are made to the `to` address.
|
||||
/// 6. Calling this function must always withdraw at least `amount`,
|
||||
/// otherwise the `ERC20Bridge` will revert.
|
||||
/// @param from The sender of the tokens and owner of the dydx account.
|
||||
/// @param to The recipient of the tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw.
|
||||
/// @param encodedBridgeData An abi-encoded `BridgeData` struct.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata encodedBridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Ensure that only the `ERC20BridgeProxy` can call this function.
|
||||
require(
|
||||
msg.sender == _getERC20BridgeProxyAddress(),
|
||||
"DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
|
||||
);
|
||||
|
||||
// Decode bridge data.
|
||||
(BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData));
|
||||
|
||||
// The dydx accounts are owned by the `from` address.
|
||||
IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData);
|
||||
|
||||
// Create dydx actions to run on the dydx accounts.
|
||||
IDydx.ActionArgs[] memory actions = _createActions(
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
bridgeData
|
||||
);
|
||||
|
||||
// Run operation. This will revert on failure.
|
||||
IDydx(_getDydxAddress()).operate(accounts, actions);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev Creates an array of accounts for dydx to operate on.
|
||||
/// All accounts must belong to the same owner.
|
||||
/// @param accountOwner Owner of the dydx account.
|
||||
/// @param bridgeData A `BridgeData` struct.
|
||||
function _createAccounts(
|
||||
address accountOwner,
|
||||
BridgeData memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (IDydx.AccountInfo[] memory accounts)
|
||||
{
|
||||
uint256[] memory accountNumbers = bridgeData.accountNumbers;
|
||||
uint256 nAccounts = accountNumbers.length;
|
||||
accounts = new IDydx.AccountInfo[](nAccounts);
|
||||
for (uint256 i = 0; i < nAccounts; ++i) {
|
||||
accounts[i] = IDydx.AccountInfo({
|
||||
owner: accountOwner,
|
||||
number: accountNumbers[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Creates an array of actions to carry out on dydx.
|
||||
/// @param depositFrom Deposit value from this address (owner of the dydx account).
|
||||
/// @param withdrawTo Withdraw value to this address.
|
||||
/// @param amount The amount of value available to operate on.
|
||||
/// @param bridgeData A `BridgeData` struct.
|
||||
function _createActions(
|
||||
address depositFrom,
|
||||
address withdrawTo,
|
||||
uint256 amount,
|
||||
BridgeData memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (IDydx.ActionArgs[] memory actions)
|
||||
{
|
||||
BridgeAction[] memory bridgeActions = bridgeData.actions;
|
||||
uint256 nBridgeActions = bridgeActions.length;
|
||||
actions = new IDydx.ActionArgs[](nBridgeActions);
|
||||
for (uint256 i = 0; i < nBridgeActions; ++i) {
|
||||
// Cache current bridge action.
|
||||
BridgeAction memory bridgeAction = bridgeActions[i];
|
||||
|
||||
// Scale amount, if conversion rate is set.
|
||||
uint256 scaledAmount;
|
||||
if (bridgeAction.conversionRateDenominator > 0) {
|
||||
scaledAmount = LibMath.safeGetPartialAmountFloor(
|
||||
bridgeAction.conversionRateNumerator,
|
||||
bridgeAction.conversionRateDenominator,
|
||||
amount
|
||||
);
|
||||
} else {
|
||||
scaledAmount = amount;
|
||||
}
|
||||
|
||||
// Construct dydx action.
|
||||
if (bridgeAction.actionType == BridgeActionType.Deposit) {
|
||||
// Deposit tokens from the account owner into their dydx account.
|
||||
actions[i] = _createDepositAction(
|
||||
depositFrom,
|
||||
scaledAmount,
|
||||
bridgeAction
|
||||
);
|
||||
} else if (bridgeAction.actionType == BridgeActionType.Withdraw) {
|
||||
// Withdraw tokens from dydx to the `otherAccount`.
|
||||
actions[i] = _createWithdrawAction(
|
||||
withdrawTo,
|
||||
scaledAmount,
|
||||
bridgeAction
|
||||
);
|
||||
} else {
|
||||
// If all values in the `Action` enum are handled then this
|
||||
// revert is unreachable: Solidity will revert when casting
|
||||
// from `uint8` to `Action`.
|
||||
revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Returns a dydx `DepositAction`.
|
||||
/// @param depositFrom Deposit tokens from this address who is also the account owner.
|
||||
/// @param amount of tokens to deposit.
|
||||
/// @param bridgeAction A `BridgeAction` struct.
|
||||
/// @return depositAction The encoded dydx action.
|
||||
function _createDepositAction(
|
||||
address depositFrom,
|
||||
uint256 amount,
|
||||
BridgeAction memory bridgeAction
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
IDydx.ActionArgs memory depositAction
|
||||
)
|
||||
{
|
||||
// Create dydx amount.
|
||||
IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({
|
||||
sign: true, // true if positive.
|
||||
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
|
||||
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
|
||||
value: amount // amount to deposit.
|
||||
});
|
||||
|
||||
// Create dydx deposit action.
|
||||
depositAction = IDydx.ActionArgs({
|
||||
actionType: IDydx.ActionType.Deposit, // deposit tokens.
|
||||
amount: dydxAmount, // amount to deposit.
|
||||
accountId: bridgeAction.accountId, // index in the `accounts` when calling `operate`.
|
||||
primaryMarketId: bridgeAction.marketId, // indicates which token to deposit.
|
||||
otherAddress: depositFrom, // deposit from the account owner.
|
||||
// unused parameters
|
||||
secondaryMarketId: 0,
|
||||
otherAccountId: 0,
|
||||
data: hex''
|
||||
});
|
||||
}
|
||||
|
||||
/// @dev Returns a dydx `WithdrawAction`.
|
||||
/// @param withdrawTo Withdraw tokens to this address.
|
||||
/// @param amount of tokens to withdraw.
|
||||
/// @param bridgeAction A `BridgeAction` struct.
|
||||
/// @return withdrawAction The encoded dydx action.
|
||||
function _createWithdrawAction(
|
||||
address withdrawTo,
|
||||
uint256 amount,
|
||||
BridgeAction memory bridgeAction
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (
|
||||
IDydx.ActionArgs memory withdrawAction
|
||||
)
|
||||
{
|
||||
// Create dydx amount.
|
||||
IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({
|
||||
sign: false, // false if negative.
|
||||
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
|
||||
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
|
||||
value: amount // amount to withdraw.
|
||||
});
|
||||
|
||||
// Create withdraw action.
|
||||
withdrawAction = IDydx.ActionArgs({
|
||||
actionType: IDydx.ActionType.Withdraw, // withdraw tokens.
|
||||
amount: amountToWithdraw, // amount to withdraw.
|
||||
accountId: bridgeAction.accountId, // index in the `accounts` when calling `operate`.
|
||||
primaryMarketId: bridgeAction.marketId, // indicates which token to withdraw.
|
||||
otherAddress: withdrawTo, // withdraw tokens to this address.
|
||||
// unused parameters
|
||||
secondaryMarketId: 0,
|
||||
otherAccountId: 0,
|
||||
data: hex''
|
||||
});
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
89
contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
Normal file
89
contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
interface IDydx {
|
||||
|
||||
/// @dev Represents the unique key that specifies an account
|
||||
struct AccountInfo {
|
||||
address owner; // The address that owns the account
|
||||
uint256 number; // A nonce that allows a single address to control many accounts
|
||||
}
|
||||
|
||||
enum ActionType {
|
||||
Deposit, // supply tokens
|
||||
Withdraw, // borrow tokens
|
||||
Transfer, // transfer balance between accounts
|
||||
Buy, // buy an amount of some token (externally)
|
||||
Sell, // sell an amount of some token (externally)
|
||||
Trade, // trade tokens against another account
|
||||
Liquidate, // liquidate an undercollateralized or expiring account
|
||||
Vaporize, // use excess tokens to zero-out a completely negative account
|
||||
Call // send arbitrary data to an address
|
||||
}
|
||||
|
||||
/// @dev Arguments that are passed to Solo in an ordered list as part of a single operation.
|
||||
/// Each ActionArgs has an actionType which specifies which action struct that this data will be
|
||||
/// parsed into before being processed.
|
||||
struct ActionArgs {
|
||||
ActionType actionType;
|
||||
uint256 accountId;
|
||||
AssetAmount amount;
|
||||
uint256 primaryMarketId;
|
||||
uint256 secondaryMarketId;
|
||||
address otherAddress;
|
||||
uint256 otherAccountId;
|
||||
bytes data;
|
||||
}
|
||||
|
||||
enum AssetDenomination {
|
||||
Wei, // the amount is denominated in wei
|
||||
Par // the amount is denominated in par
|
||||
}
|
||||
|
||||
enum AssetReference {
|
||||
Delta, // the amount is given as a delta from the current value
|
||||
Target // the amount is given as an exact number to end up at
|
||||
}
|
||||
|
||||
struct AssetAmount {
|
||||
bool sign; // true if positive
|
||||
AssetDenomination denomination;
|
||||
AssetReference ref;
|
||||
uint256 value;
|
||||
}
|
||||
|
||||
/// @dev The main entry-point to Solo that allows users and contracts to manage accounts.
|
||||
/// Take one or more actions on one or more accounts. The msg.sender must be the owner or
|
||||
/// operator of all accounts except for those being liquidated, vaporized, or traded with.
|
||||
/// One call to operate() is considered a singular "operation". Account collateralization is
|
||||
/// ensured only after the completion of the entire operation.
|
||||
/// @param accounts A list of all accounts that will be used in this operation. Cannot contain
|
||||
/// duplicates. In each action, the relevant account will be referred-to by its
|
||||
/// index in the list.
|
||||
/// @param actions An ordered list of all actions that will be taken in this operation. The
|
||||
/// actions will be processed in order.
|
||||
function operate(
|
||||
AccountInfo[] calldata accounts,
|
||||
ActionArgs[] calldata actions
|
||||
)
|
||||
external;
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
interface IDydxBridge {
|
||||
|
||||
/// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge.
|
||||
enum BridgeActionType {
|
||||
Deposit, // Deposit tokens into dydx account.
|
||||
Withdraw // Withdraw tokens from dydx account.
|
||||
}
|
||||
|
||||
struct BridgeAction {
|
||||
BridgeActionType actionType; // Action to run on dydx account.
|
||||
uint256 accountId; // Index in `BridgeData.accountNumbers` for this action.
|
||||
uint256 marketId; // Market to operate on.
|
||||
uint256 conversionRateNumerator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
|
||||
uint256 conversionRateDenominator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
|
||||
}
|
||||
|
||||
struct BridgeData {
|
||||
uint256[] accountNumbers; // Account number used to identify the owner's specific account.
|
||||
BridgeAction[] actions; // Actions to carry out on the owner's accounts.
|
||||
}
|
||||
}
|
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;
|
||||
}
|
||||
}
|
101
contracts/asset-proxy/contracts/test/TestDydxBridge.sol
Normal file
101
contracts/asset-proxy/contracts/test/TestDydxBridge.sol
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
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/DydxBridge.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
contract TestDydxBridge is
|
||||
IDydx,
|
||||
DydxBridge
|
||||
{
|
||||
|
||||
address private constant ALWAYS_REVERT_ADDRESS = address(1);
|
||||
|
||||
event OperateAccount(
|
||||
address owner,
|
||||
uint256 number
|
||||
);
|
||||
|
||||
event OperateAction(
|
||||
ActionType actionType,
|
||||
uint256 accountId,
|
||||
bool amountSign,
|
||||
AssetDenomination amountDenomination,
|
||||
AssetReference amountRef,
|
||||
uint256 amountValue,
|
||||
uint256 primaryMarketId,
|
||||
uint256 secondaryMarketId,
|
||||
address otherAddress,
|
||||
uint256 otherAccountId,
|
||||
bytes data
|
||||
);
|
||||
|
||||
/// @dev Simulates `operate` in dydx contract.
|
||||
/// Emits events so that arguments can be validated client-side.
|
||||
function operate(
|
||||
AccountInfo[] calldata accounts,
|
||||
ActionArgs[] calldata actions
|
||||
)
|
||||
external
|
||||
{
|
||||
for (uint i = 0; i < accounts.length; ++i) {
|
||||
emit OperateAccount(
|
||||
accounts[i].owner,
|
||||
accounts[i].number
|
||||
);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < actions.length; ++i) {
|
||||
emit OperateAction(
|
||||
actions[i].actionType,
|
||||
actions[i].accountId,
|
||||
actions[i].amount.sign,
|
||||
actions[i].amount.denomination,
|
||||
actions[i].amount.ref,
|
||||
actions[i].amount.value,
|
||||
actions[i].primaryMarketId,
|
||||
actions[i].secondaryMarketId,
|
||||
actions[i].otherAddress,
|
||||
actions[i].otherAccountId,
|
||||
actions[i].data
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address.
|
||||
function _getDydxAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return address(this);
|
||||
}
|
||||
|
||||
/// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing.
|
||||
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.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,8 +38,7 @@
|
||||
"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",
|
||||
"abis": "./test/generated-artifacts/@(ChaiBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -52,15 +51,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.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -80,15 +79,16 @@
|
||||
"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/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.2",
|
||||
"@0x/contracts-erc1155": "^2.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-erc721": "^3.0.2",
|
||||
"@0x/contracts-exchange-libs": "^4.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
|
||||
import * as DydxBridge from '../generated-artifacts/DydxBridge.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';
|
||||
@@ -12,22 +14,62 @@ import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
||||
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
|
||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||
import * as IChai from '../generated-artifacts/IChai.json';
|
||||
import * as IDydx from '../generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
|
||||
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
|
||||
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
|
||||
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
|
||||
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
|
||||
import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
|
||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||
import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json';
|
||||
import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json';
|
||||
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json';
|
||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||
import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json';
|
||||
import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json';
|
||||
export const artifacts = {
|
||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
Ownable: Ownable as ContractArtifact,
|
||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
IAssetData: IAssetData as ContractArtifact,
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
IDydx: IDydx as ContractArtifact,
|
||||
IDydxBridge: IDydxBridge 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,
|
||||
TestDydxBridge: TestDydxBridge as ContractArtifact,
|
||||
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
|
||||
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
|
||||
TestKyberBridge: TestKyberBridge as ContractArtifact,
|
||||
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||
TestUniswapBridge: TestUniswapBridge as ContractArtifact,
|
||||
};
|
||||
|
@@ -5,6 +5,7 @@ export {
|
||||
ERC20ProxyContract,
|
||||
ERC721ProxyContract,
|
||||
Eth2DaiBridgeContract,
|
||||
DydxBridgeContract,
|
||||
IAssetDataContract,
|
||||
IAssetProxyContract,
|
||||
MultiAssetProxyContract,
|
||||
|
@@ -3,6 +3,8 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/chai_bridge';
|
||||
export * from '../generated-wrappers/dydx_bridge';
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../generated-wrappers/erc20_proxy';
|
||||
@@ -10,8 +12,27 @@ export * from '../generated-wrappers/erc721_proxy';
|
||||
export * from '../generated-wrappers/eth2_dai_bridge';
|
||||
export * from '../generated-wrappers/i_asset_data';
|
||||
export * from '../generated-wrappers/i_asset_proxy';
|
||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/i_authorizable';
|
||||
export * from '../generated-wrappers/i_chai';
|
||||
export * from '../generated-wrappers/i_dydx';
|
||||
export * from '../generated-wrappers/i_dydx_bridge';
|
||||
export * from '../generated-wrappers/i_erc20_bridge';
|
||||
export * from '../generated-wrappers/i_eth2_dai';
|
||||
export * from '../generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../generated-wrappers/kyber_bridge';
|
||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/mixin_authorizable';
|
||||
export * from '../generated-wrappers/multi_asset_proxy';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/static_call_proxy';
|
||||
export * from '../generated-wrappers/test_chai_bridge';
|
||||
export * from '../generated-wrappers/test_dydx_bridge';
|
||||
export * from '../generated-wrappers/test_erc20_bridge';
|
||||
export * from '../generated-wrappers/test_eth2_dai_bridge';
|
||||
export * from '../generated-wrappers/test_kyber_bridge';
|
||||
export * from '../generated-wrappers/test_static_call_target';
|
||||
export * from '../generated-wrappers/test_uniswap_bridge';
|
||||
export * from '../generated-wrappers/uniswap_bridge';
|
||||
|
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
|
||||
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.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 +16,9 @@ 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 IDydx from '../test/generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.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 +30,8 @@ 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 TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.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 +48,8 @@ export const artifacts = {
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
@@ -48,11 +57,16 @@ export const artifacts = {
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
IDydx: IDydx as ContractArtifact,
|
||||
IDydxBridge: IDydxBridge 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,
|
||||
TestDydxBridge: TestDydxBridge 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);
|
||||
});
|
||||
});
|
||||
});
|
244
contracts/asset-proxy/test/dydx_bridge.ts
Normal file
244
contracts/asset-proxy/test/dydx_bridge.ts
Normal file
@@ -0,0 +1,244 @@
|
||||
import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||
import { AssetProxyId, RevertReason } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers';
|
||||
|
||||
blockchainTests.resets('DydxBridge unit tests', env => {
|
||||
const defaultAccountNumber = new BigNumber(1);
|
||||
const marketId = new BigNumber(2);
|
||||
const defaultAmount = new BigNumber(4);
|
||||
const notAuthorized = '0x0000000000000000000000000000000000000001';
|
||||
let testContract: TestDydxBridgeContract;
|
||||
let authorized: string;
|
||||
let accountOwner: string;
|
||||
let receiver: string;
|
||||
|
||||
before(async () => {
|
||||
// Get accounts
|
||||
const accounts = await env.web3Wrapper.getAvailableAddressesAsync();
|
||||
[, /* owner */ authorized, accountOwner, receiver] = accounts;
|
||||
|
||||
// Deploy dydx bridge
|
||||
testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestDydxBridge,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
enum BridgeActionType {
|
||||
Deposit,
|
||||
Withdraw,
|
||||
}
|
||||
interface BrigeAction {
|
||||
actionType: BridgeActionType;
|
||||
accountId: BigNumber;
|
||||
marketId: BigNumber;
|
||||
conversionRateNumerator: BigNumber;
|
||||
conversionRateDenominator: BigNumber;
|
||||
}
|
||||
interface BridgeData {
|
||||
accountNumbers: BigNumber[];
|
||||
actions: BrigeAction[];
|
||||
}
|
||||
const defaultDepositAction = {
|
||||
actionType: BridgeActionType.Deposit as number,
|
||||
accountId: constants.ZERO_AMOUNT,
|
||||
marketId,
|
||||
conversionRateNumerator: constants.ZERO_AMOUNT,
|
||||
conversionRateDenominator: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const defaultWithdrawAction = {
|
||||
actionType: BridgeActionType.Withdraw as number,
|
||||
accountId: constants.ZERO_AMOUNT,
|
||||
marketId,
|
||||
conversionRateNumerator: constants.ZERO_AMOUNT,
|
||||
conversionRateDenominator: constants.ZERO_AMOUNT,
|
||||
};
|
||||
const bridgeDataEncoder = AbiEncoder.create([
|
||||
{
|
||||
name: 'bridgeData',
|
||||
type: 'tuple',
|
||||
components: [
|
||||
{ name: 'accountNumbers', type: 'uint256[]' },
|
||||
{
|
||||
name: 'actions',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{ name: 'actionType', type: 'uint8' },
|
||||
{ name: 'accountId', type: 'uint256' },
|
||||
{ name: 'marketId', type: 'uint256' },
|
||||
{ name: 'conversionRateNumerator', type: 'uint256' },
|
||||
{ name: 'conversionRateDenominator', type: 'uint256' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
const callBridgeTransferFrom = async (
|
||||
from: string,
|
||||
to: string,
|
||||
amount: BigNumber,
|
||||
bridgeData: BridgeData,
|
||||
sender: string,
|
||||
): Promise<string> => {
|
||||
const returnValue = await testContract
|
||||
.bridgeTransferFrom(constants.NULL_ADDRESS, from, to, amount, bridgeDataEncoder.encode({ bridgeData }))
|
||||
.callAsync({ from: sender });
|
||||
return returnValue;
|
||||
};
|
||||
const callBridgeTransferFromAndVerifyEvents = async (
|
||||
from: string,
|
||||
to: string,
|
||||
amount: BigNumber,
|
||||
bridgeData: BridgeData,
|
||||
sender: string,
|
||||
): Promise<void> => {
|
||||
// Execute transaction.
|
||||
const txReceipt = await testContract
|
||||
.bridgeTransferFrom(constants.NULL_ADDRESS, from, to, amount, bridgeDataEncoder.encode({ bridgeData }))
|
||||
.awaitTransactionSuccessAsync({ from: sender });
|
||||
|
||||
// Verify `OperateAccount` event.
|
||||
const expectedOperateAccountEvents = [];
|
||||
for (const accountNumber of bridgeData.accountNumbers) {
|
||||
expectedOperateAccountEvents.push({
|
||||
owner: accountOwner,
|
||||
number: accountNumber,
|
||||
});
|
||||
}
|
||||
verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount);
|
||||
|
||||
// Verify `OperateAction` event.
|
||||
const weiDenomination = 0;
|
||||
const deltaAmountRef = 0;
|
||||
const expectedOperateActionEvents = [];
|
||||
for (const action of bridgeData.actions) {
|
||||
expectedOperateActionEvents.push({
|
||||
actionType: action.actionType as number,
|
||||
accountId: action.accountId,
|
||||
amountSign: action.actionType === BridgeActionType.Deposit ? true : false,
|
||||
amountDenomination: weiDenomination,
|
||||
amountRef: deltaAmountRef,
|
||||
amountValue: action.conversionRateDenominator.gt(0)
|
||||
? amount.times(action.conversionRateNumerator).div(action.conversionRateDenominator)
|
||||
: amount,
|
||||
primaryMarketId: marketId,
|
||||
secondaryMarketId: constants.ZERO_AMOUNT,
|
||||
otherAddress: action.actionType === BridgeActionType.Deposit ? from : to,
|
||||
otherAccountId: constants.ZERO_AMOUNT,
|
||||
data: '0x',
|
||||
});
|
||||
}
|
||||
verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction);
|
||||
};
|
||||
it('succeeds when calling `operate` with the `deposit` action and a single account', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `withdraw` action and a single accuont', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultWithdrawAction],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
|
||||
actions: [defaultWithdrawAction, defaultDepositAction],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when calling `operate` with multiple actions under a single account', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultWithdrawAction, defaultDepositAction],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when scaling the `amount` to deposit', async () => {
|
||||
const conversionRateNumerator = new BigNumber(1);
|
||||
const conversionRateDenominator = new BigNumber(2);
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [
|
||||
defaultWithdrawAction,
|
||||
{
|
||||
...defaultDepositAction,
|
||||
conversionRateNumerator,
|
||||
conversionRateDenominator,
|
||||
},
|
||||
],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('succeeds when scaling the `amount` to withdraw', async () => {
|
||||
const conversionRateNumerator = new BigNumber(1);
|
||||
const conversionRateDenominator = new BigNumber(2);
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [
|
||||
defaultDepositAction,
|
||||
{
|
||||
...defaultWithdrawAction,
|
||||
conversionRateNumerator,
|
||||
conversionRateDenominator,
|
||||
},
|
||||
],
|
||||
};
|
||||
await callBridgeTransferFromAndVerifyEvents(accountOwner, receiver, defaultAmount, bridgeData, authorized);
|
||||
});
|
||||
it('reverts if not called by the ERC20 Bridge Proxy', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
const callBridgeTransferFromPromise = callBridgeTransferFrom(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
notAuthorized,
|
||||
);
|
||||
const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy;
|
||||
return expect(callBridgeTransferFromPromise).to.revertWith(expectedError);
|
||||
});
|
||||
it('should return magic bytes if call succeeds', async () => {
|
||||
const bridgeData = {
|
||||
accountNumbers: [defaultAccountNumber],
|
||||
actions: [defaultDepositAction],
|
||||
};
|
||||
const returnValue = await callBridgeTransferFrom(
|
||||
accountOwner,
|
||||
receiver,
|
||||
defaultAmount,
|
||||
bridgeData,
|
||||
authorized,
|
||||
);
|
||||
expect(returnValue).to.equal(AssetProxyId.ERC20Bridge);
|
||||
});
|
||||
});
|
||||
});
|
@@ -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,8 @@
|
||||
* 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/dydx_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 +14,9 @@ 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_dydx';
|
||||
export * from '../test/generated-wrappers/i_dydx_bridge';
|
||||
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 +28,8 @@ 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_dydx_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,8 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/DydxBridge.json",
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
"generated-artifacts/ERC20Proxy.json",
|
||||
@@ -10,11 +12,32 @@
|
||||
"generated-artifacts/Eth2DaiBridge.json",
|
||||
"generated-artifacts/IAssetData.json",
|
||||
"generated-artifacts/IAssetProxy.json",
|
||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/IChai.json",
|
||||
"generated-artifacts/IDydx.json",
|
||||
"generated-artifacts/IDydxBridge.json",
|
||||
"generated-artifacts/IERC20Bridge.json",
|
||||
"generated-artifacts/IEth2Dai.json",
|
||||
"generated-artifacts/IKyberNetworkProxy.json",
|
||||
"generated-artifacts/IUniswapExchange.json",
|
||||
"generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"generated-artifacts/KyberBridge.json",
|
||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MultiAssetProxy.json",
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/StaticCallProxy.json",
|
||||
"generated-artifacts/TestChaiBridge.json",
|
||||
"generated-artifacts/TestDydxBridge.json",
|
||||
"generated-artifacts/TestERC20Bridge.json",
|
||||
"generated-artifacts/TestEth2DaiBridge.json",
|
||||
"generated-artifacts/TestKyberBridge.json",
|
||||
"generated-artifacts/TestStaticCallTarget.json",
|
||||
"generated-artifacts/TestUniswapBridge.json",
|
||||
"generated-artifacts/UniswapBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/DydxBridge.json",
|
||||
"test/generated-artifacts/ERC1155Proxy.json",
|
||||
"test/generated-artifacts/ERC20BridgeProxy.json",
|
||||
"test/generated-artifacts/ERC20Proxy.json",
|
||||
@@ -24,6 +47,9 @@
|
||||
"test/generated-artifacts/IAssetProxy.json",
|
||||
"test/generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/IAuthorizable.json",
|
||||
"test/generated-artifacts/IChai.json",
|
||||
"test/generated-artifacts/IDydx.json",
|
||||
"test/generated-artifacts/IDydxBridge.json",
|
||||
"test/generated-artifacts/IERC20Bridge.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
@@ -35,6 +61,8 @@
|
||||
"test/generated-artifacts/MultiAssetProxy.json",
|
||||
"test/generated-artifacts/Ownable.json",
|
||||
"test/generated-artifacts/StaticCallProxy.json",
|
||||
"test/generated-artifacts/TestChaiBridge.json",
|
||||
"test/generated-artifacts/TestDydxBridge.json",
|
||||
"test/generated-artifacts/TestERC20Bridge.json",
|
||||
"test/generated-artifacts/TestEth2DaiBridge.json",
|
||||
"test/generated-artifacts/TestKyberBridge.json",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/contracts-asset-proxy": "^3.0.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-exchange": "^3.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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/contract-addresses": "^4.0.0",
|
||||
"@0x/contracts-utils": "^4.0.0",
|
||||
"@0x/json-schemas": "^5.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/assert": "^3.0.2",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/contract-addresses": "^4.1.0",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/json-schemas": "^5.0.2",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"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,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/assert": "^3.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@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.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "2.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,15 +52,15 @@
|
||||
},
|
||||
"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.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -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.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Do not query empty/unsigned orders. Swallow revets on DEX quotes.",
|
||||
"pr": 2365
|
||||
}
|
||||
],
|
||||
"timestamp": 1576540892
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.2 - _December 17, 2019_
|
||||
|
||||
* Do not query empty/unsigned orders. Swallow revets on DEX quotes. (#2365)
|
||||
|
||||
## v1.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _December 2, 2019_
|
||||
|
||||
* Created package. (#2344)
|
||||
|
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
|
||||
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 "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "./IEth2Dai.sol";
|
||||
import "./IKyberNetwork.sol";
|
||||
|
||||
|
||||
contract DeploymentConstants {
|
||||
|
||||
/// @dev Address of the 0x Exchange contract.
|
||||
address constant public EXCHANGE_ADDRESS = 0x080bf510FCbF18b91105470639e9561022937712;
|
||||
/// @dev Address of the Eth2Dai MatchingMarket contract.
|
||||
address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||
/// @dev Address of the UniswapExchangeFactory contract.
|
||||
address constant public UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||
/// @dev Address of the KyberNeworkProxy contract.
|
||||
address constant public KYBER_NETWORK_PROXY_ADDRESS = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
|
||||
/// @dev Address of the WETH contract.
|
||||
address constant public WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
|
||||
/// @dev An overridable way to retrieve the 0x Exchange contract.
|
||||
/// @return zeroex The 0x Exchange contract.
|
||||
function _getExchangeContract()
|
||||
internal
|
||||
view
|
||||
returns (IExchange zeroex)
|
||||
{
|
||||
return IExchange(EXCHANGE_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the Eth2Dai exchange contract.
|
||||
/// @return eth2dai The Eth2Dai exchange contract.
|
||||
function _getEth2DaiContract()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai eth2dai)
|
||||
{
|
||||
return IEth2Dai(ETH2DAI_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the Uniswap exchange factory contract.
|
||||
/// @return uniswap The UniswapExchangeFactory contract.
|
||||
function _getUniswapExchangeFactoryContract()
|
||||
internal
|
||||
view
|
||||
returns (IUniswapExchangeFactory uniswap)
|
||||
{
|
||||
return IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the Kyber network proxy contract.
|
||||
/// @return kyber The KyberNeworkProxy contract.
|
||||
function _getKyberNetworkContract()
|
||||
internal
|
||||
view
|
||||
returns (IKyberNetwork kyber)
|
||||
{
|
||||
return IKyberNetwork(KYBER_NETWORK_PROXY_ADDRESS);
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the WETH contract address.
|
||||
/// @return weth The WETH contract address.
|
||||
function _getWETHAddress()
|
||||
internal
|
||||
view
|
||||
returns (address weth)
|
||||
{
|
||||
return WETH_ADDRESS;
|
||||
}
|
||||
}
|
@@ -23,11 +23,13 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFacto
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "./IDevUtils.sol";
|
||||
import "./IERC20BridgeSampler.sol";
|
||||
import "./IEth2Dai.sol";
|
||||
import "./IKyberNetwork.sol";
|
||||
import "./IUniswapExchangeQuotes.sol";
|
||||
import "./DeploymentConstants.sol";
|
||||
|
||||
|
||||
contract ERC20BridgeSampler is
|
||||
@@ -38,26 +40,32 @@ contract ERC20BridgeSampler is
|
||||
|
||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return orderInfos `OrderInfo`s for each order in `orders`.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleSells(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo[] memory orderInfos,
|
||||
uint256[] memory orderFillableTakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
)
|
||||
{
|
||||
require(orders.length != 0, "EMPTY_ORDERS");
|
||||
orderInfos = queryOrders(orders);
|
||||
require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS");
|
||||
orderFillableTakerAssetAmounts = getOrderFillableTakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures
|
||||
);
|
||||
makerTokenAmountsBySource = sampleSells(
|
||||
sources,
|
||||
_assetDataToTokenAddress(orders[0].takerAssetData),
|
||||
@@ -68,26 +76,32 @@ contract ERC20BridgeSampler is
|
||||
|
||||
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return orderInfos `OrderInfo`s for each order in `orders`.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleBuys(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo[] memory orderInfos,
|
||||
uint256[] memory orderFillableMakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
)
|
||||
{
|
||||
require(orders.length != 0, "EMPTY_ORDERS");
|
||||
orderInfos = queryOrders(orders);
|
||||
require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS");
|
||||
orderFillableMakerAssetAmounts = getOrderFillableMakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures
|
||||
);
|
||||
makerTokenAmountsBySource = sampleBuys(
|
||||
sources,
|
||||
_assetDataToTokenAddress(orders[0].takerAssetData),
|
||||
@@ -96,18 +110,77 @@ contract ERC20BridgeSampler is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Queries the status of several native orders.
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// maker/taker asset amounts (returning 0).
|
||||
/// @param orders Native orders to query.
|
||||
/// @return orderInfos Order info for each respective order.
|
||||
function queryOrders(LibOrder.Order[] memory orders)
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableTakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (LibOrder.OrderInfo[] memory orderInfos)
|
||||
returns (uint256[] memory orderFillableTakerAssetAmounts)
|
||||
{
|
||||
uint256 numOrders = orders.length;
|
||||
orderInfos = new LibOrder.OrderInfo[](numOrders);
|
||||
for (uint256 i = 0; i < numOrders; i++) {
|
||||
orderInfos[i] = _getExchangeContract().getOrderInfo(orders[i]);
|
||||
orderFillableTakerAssetAmounts = new uint256[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// Ignore orders with no signature or empty maker/taker amounts.
|
||||
if (orderSignatures[i].length == 0 ||
|
||||
orders[i].makerAssetAmount == 0 ||
|
||||
orders[i].takerAssetAmount == 0) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
(
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
) = IDevUtils(_getDevUtilsAddress()).getOrderRelevantState(
|
||||
orders[i],
|
||||
orderSignatures[i]
|
||||
);
|
||||
// The fillable amount is zero if the order is not fillable or if the
|
||||
// signature is invalid.
|
||||
if (orderInfo.orderStatus != uint8(LibOrder.OrderStatus.FILLABLE) ||
|
||||
!isValidSignature) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
} else {
|
||||
orderFillableTakerAssetAmounts[i] = fillableTakerAssetAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableMakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts)
|
||||
{
|
||||
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures
|
||||
);
|
||||
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
|
||||
// convert them to maker asset amounts.
|
||||
for (uint256 i = 0; i < orders.length; ++i) {
|
||||
if (orderFillableMakerAssetAmounts[i] != 0) {
|
||||
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
|
||||
orderFillableMakerAssetAmounts[i],
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,18 +260,24 @@ contract ERC20BridgeSampler is
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
address _takerToken = takerToken == _getWETHAddress() ? KYBER_ETH_ADDRESS : takerToken;
|
||||
address _makerToken = makerToken == _getWETHAddress() ? KYBER_ETH_ADDRESS : makerToken;
|
||||
address _takerToken = takerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : takerToken;
|
||||
address _makerToken = makerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : makerToken;
|
||||
uint256 takerTokenDecimals = _getTokenDecimals(takerToken);
|
||||
uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(uint256 rate,) = _getKyberNetworkContract().getExpectedRate(
|
||||
_takerToken,
|
||||
_makerToken,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getKyberNetworkProxyAddress().staticcall(abi.encodeWithSelector(
|
||||
IKyberNetwork(0).getExpectedRate.selector,
|
||||
_takerToken,
|
||||
_makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 rate = 0;
|
||||
if (didSucceed) {
|
||||
rate = abi.decode(resultData, (uint256));
|
||||
}
|
||||
makerTokenAmounts[i] =
|
||||
rate *
|
||||
takerTokenAmounts[i] *
|
||||
@@ -227,11 +306,18 @@ contract ERC20BridgeSampler is
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
makerTokenAmounts[i] = _getEth2DaiContract().getBuyAmount(
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getEth2DaiAddress().staticcall(abi.encodeWithSelector(
|
||||
IEth2Dai(0).getBuyAmount.selector,
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +340,18 @@ contract ERC20BridgeSampler is
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
takerTokenAmounts[i] = _getEth2DaiContract().getPayAmount(
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getEth2DaiAddress().staticcall(abi.encodeWithSelector(
|
||||
IEth2Dai(0).getPayAmount.selector,
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerTokenAmounts[i]
|
||||
));
|
||||
uint256 sellAmount = 0;
|
||||
if (didSucceed) {
|
||||
sellAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,26 +373,38 @@ contract ERC20BridgeSampler is
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWETHAddress() ?
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWETHAddress() ?
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
if (makerToken == _getWETHAddress()) {
|
||||
makerTokenAmounts[i] = takerTokenExchange.getTokenToEthInputPrice(
|
||||
if (makerToken == _getWethAddress()) {
|
||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == _getWETHAddress()) {
|
||||
makerTokenAmounts[i] = makerTokenExchange.getEthToTokenInputPrice(
|
||||
} else if (takerToken == _getWethAddress()) {
|
||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethBought = takerTokenExchange.getTokenToEthInputPrice(
|
||||
uint256 ethBought = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
makerTokenAmounts[i] = makerTokenExchange.getEthToTokenInputPrice(
|
||||
ethBought
|
||||
);
|
||||
if (ethBought != 0) {
|
||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
ethBought
|
||||
);
|
||||
} else {
|
||||
makerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,26 +427,38 @@ contract ERC20BridgeSampler is
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWETHAddress() ?
|
||||
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWETHAddress() ?
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
if (makerToken == _getWETHAddress()) {
|
||||
takerTokenAmounts[i] = takerTokenExchange.getTokenToEthOutputPrice(
|
||||
if (makerToken == _getWethAddress()) {
|
||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == _getWETHAddress()) {
|
||||
takerTokenAmounts[i] = makerTokenExchange.getEthToTokenOutputPrice(
|
||||
} else if (takerToken == _getWethAddress()) {
|
||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethSold = makerTokenExchange.getEthToTokenOutputPrice(
|
||||
uint256 ethSold = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
takerTokenAmounts[i] = takerTokenExchange.getTokenToEthOutputPrice(
|
||||
ethSold
|
||||
);
|
||||
if (ethSold != 0) {
|
||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
ethSold
|
||||
);
|
||||
} else {
|
||||
takerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,6 +474,34 @@ contract ERC20BridgeSampler is
|
||||
return LibERC20Token.decimals(tokenAddress);
|
||||
}
|
||||
|
||||
/// @dev Gracefully calls a Uniswap pricing function.
|
||||
/// @param uniswapExchangeAddress Address of an `IUniswapExchangeQuotes` exchange.
|
||||
/// @param functionSelector Selector of the target function.
|
||||
/// @param inputAmount Quantity parameter particular to the pricing function.
|
||||
/// @return outputAmount The returned amount from the function call. Will be
|
||||
/// zero if the call fails or if `uniswapExchangeAddress` is zero.
|
||||
function _callUniswapExchangePriceFunction(
|
||||
address uniswapExchangeAddress,
|
||||
bytes4 functionSelector,
|
||||
uint256 inputAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 outputAmount)
|
||||
{
|
||||
if (uniswapExchangeAddress == address(0)) {
|
||||
return 0;
|
||||
}
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
uniswapExchangeAddress.staticcall(abi.encodeWithSelector(
|
||||
functionSelector,
|
||||
inputAmount
|
||||
));
|
||||
if (didSucceed) {
|
||||
outputAmount = abi.decode(resultData, (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Samples a supported sell source, defined by its address.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
@@ -373,16 +518,16 @@ contract ERC20BridgeSampler is
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
if (source == address(_getEth2DaiContract())) {
|
||||
if (source == _getEth2DaiAddress()) {
|
||||
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == address(_getUniswapExchangeFactoryContract())) {
|
||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
||||
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == address(_getKyberNetworkContract())) {
|
||||
if (source == _getKyberNetworkProxyAddress()) {
|
||||
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
revert("UNSUPPORTED_SOURCE");
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
}
|
||||
|
||||
/// @dev Samples a supported buy source, defined by its address.
|
||||
@@ -401,13 +546,13 @@ contract ERC20BridgeSampler is
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
if (source == address(_getEth2DaiContract())) {
|
||||
if (source == _getEth2DaiAddress()) {
|
||||
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
if (source == address(_getUniswapExchangeFactoryContract())) {
|
||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
||||
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
revert("UNSUPPORTED_SOURCE");
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
}
|
||||
|
||||
/// @dev Retrive an existing Uniswap exchange contract.
|
||||
@@ -420,9 +565,9 @@ contract ERC20BridgeSampler is
|
||||
returns (IUniswapExchangeQuotes exchange)
|
||||
{
|
||||
exchange = IUniswapExchangeQuotes(
|
||||
address(_getUniswapExchangeFactoryContract().getExchange(tokenAddress))
|
||||
address(IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
|
||||
.getExchange(tokenAddress))
|
||||
);
|
||||
require(address(exchange) != address(0), "UNSUPPORTED_UNISWAP_EXCHANGE");
|
||||
}
|
||||
|
||||
/// @dev Extract the token address from ERC20 proxy asset data.
|
||||
@@ -433,19 +578,19 @@ contract ERC20BridgeSampler is
|
||||
pure
|
||||
returns (address tokenAddress)
|
||||
{
|
||||
require(assetData.length == 36, "INVALID_ASSET_DATA");
|
||||
require(assetData.length == 36, "ERC20BridgeSampler/INVALID_ASSET_DATA");
|
||||
bytes4 selector;
|
||||
assembly {
|
||||
selector := and(mload(add(assetData, 0x20)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
|
||||
tokenAddress := mload(add(assetData, 0x24))
|
||||
}
|
||||
require(selector == ERC20_PROXY_ID, "UNSUPPORTED_ASSET_PROXY");
|
||||
require(selector == ERC20_PROXY_ID, "ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY");
|
||||
}
|
||||
|
||||
function _assertValidPair(address makerToken, address takerToken)
|
||||
private
|
||||
pure
|
||||
{
|
||||
require(makerToken != takerToken, "INVALID_TOKEN_PAIR");
|
||||
require(makerToken != takerToken, "ERC20BridgeSampler/INVALID_TOKEN_PAIR");
|
||||
}
|
||||
}
|
||||
|
45
contracts/erc20-bridge-sampler/contracts/src/IDevUtils.sol
Normal file
45
contracts/erc20-bridge-sampler/contracts/src/IDevUtils.sol
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
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 "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IDevUtils {
|
||||
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||
/// @param order The order structure.
|
||||
/// @param signature Signature provided by maker that proves the order's authenticity.
|
||||
/// `0x01` can always be provided if the signature does not need to be validated.
|
||||
/// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order),
|
||||
/// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state),
|
||||
/// and isValidSignature (validity of the provided signature).
|
||||
/// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
|
||||
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
|
||||
/// amount of each asset that can be filled.
|
||||
function getOrderRelevantState(LibOrder.Order calldata order, bytes calldata signature)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
);
|
||||
}
|
@@ -19,59 +19,82 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IERC20BridgeSampler {
|
||||
|
||||
/// @dev Query native orders and sample sell orders on multiple DEXes at once.
|
||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param sources Address of each DEX. Passing in an unknown DEX will throw.
|
||||
/// @param takerTokenAmounts Taker sell amount for each sample.
|
||||
/// @return orderInfos `OrderInfo`s for each order in `orders`.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleSells(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo[] memory orderInfos,
|
||||
uint256[] memory orderFillableTakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
);
|
||||
|
||||
/// @dev Query native orders and sample buy orders on multiple DEXes at once.
|
||||
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param sources Address of each DEX. Passing in an unknown DEX will throw.
|
||||
/// @param makerTokenAmounts Maker sell amount for each sample.
|
||||
/// @return orderInfos `OrderInfo`s for each order in `orders`.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleBuys(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo[] memory orderInfos,
|
||||
uint256[] memory orderFillableMakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
);
|
||||
|
||||
/// @dev Queries the status of several native orders.
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// @param orders Native orders to query.
|
||||
/// @return orderInfos Order info for each respective order.
|
||||
function queryOrders(LibOrder.Order[] calldata orders)
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableTakerAssetAmounts(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (LibOrder.OrderInfo[] memory orderInfos);
|
||||
returns (uint256[] memory orderFillableTakerAssetAmounts);
|
||||
|
||||
/// @dev Queries the fillable maker asset amounts of native orders.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableMakerAssetAmounts(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts);
|
||||
|
||||
/// @dev Sample sell quotes on multiple DEXes at once.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
|
@@ -23,6 +23,7 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "../src/ERC20BridgeSampler.sol";
|
||||
import "../src/IEth2Dai.sol";
|
||||
import "../src/IDevUtils.sol";
|
||||
import "../src/IKyberNetwork.sol";
|
||||
|
||||
|
||||
@@ -90,9 +91,28 @@ library LibDeterministicQuotes {
|
||||
}
|
||||
|
||||
|
||||
contract FailTrigger {
|
||||
|
||||
// Give this address a balance to force operations to fail.
|
||||
address payable constant public FAILURE_ADDRESS = 0xe9dB8717BC5DFB20aaf538b4a5a02B7791FF430C;
|
||||
|
||||
// Funds `FAILURE_ADDRESS`.
|
||||
function enableFailTrigger() external payable {
|
||||
FAILURE_ADDRESS.transfer(msg.value);
|
||||
}
|
||||
|
||||
function _revertIfShouldFail() internal view {
|
||||
if (FAILURE_ADDRESS.balance != 0) {
|
||||
revert("FAIL_TRIGGERED");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract TestERC20BridgeSamplerUniswapExchange is
|
||||
IUniswapExchangeQuotes,
|
||||
DeploymentConstants
|
||||
DeploymentConstants,
|
||||
FailTrigger
|
||||
{
|
||||
bytes32 constant private BASE_SALT = 0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab;
|
||||
|
||||
@@ -112,10 +132,11 @@ contract TestERC20BridgeSamplerUniswapExchange is
|
||||
view
|
||||
returns (uint256 tokensBought)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
||||
salt,
|
||||
tokenAddress,
|
||||
WETH_ADDRESS,
|
||||
_getWethAddress(),
|
||||
ethSold
|
||||
);
|
||||
}
|
||||
@@ -128,9 +149,10 @@ contract TestERC20BridgeSamplerUniswapExchange is
|
||||
view
|
||||
returns (uint256 ethSold)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||
salt,
|
||||
WETH_ADDRESS,
|
||||
_getWethAddress(),
|
||||
tokenAddress,
|
||||
tokensBought
|
||||
);
|
||||
@@ -144,10 +166,11 @@ contract TestERC20BridgeSamplerUniswapExchange is
|
||||
view
|
||||
returns (uint256 ethBought)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
||||
salt,
|
||||
tokenAddress,
|
||||
WETH_ADDRESS,
|
||||
_getWethAddress(),
|
||||
tokensSold
|
||||
);
|
||||
}
|
||||
@@ -160,9 +183,10 @@ contract TestERC20BridgeSamplerUniswapExchange is
|
||||
view
|
||||
returns (uint256 tokensSold)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||
salt,
|
||||
WETH_ADDRESS,
|
||||
_getWethAddress(),
|
||||
tokenAddress,
|
||||
ethBought
|
||||
);
|
||||
@@ -172,7 +196,8 @@ contract TestERC20BridgeSamplerUniswapExchange is
|
||||
|
||||
contract TestERC20BridgeSamplerKyberNetwork is
|
||||
IKyberNetwork,
|
||||
DeploymentConstants
|
||||
DeploymentConstants,
|
||||
FailTrigger
|
||||
{
|
||||
bytes32 constant private SALT = 0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7;
|
||||
address constant public ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
@@ -187,8 +212,9 @@ contract TestERC20BridgeSamplerKyberNetwork is
|
||||
view
|
||||
returns (uint256 expectedRate, uint256)
|
||||
{
|
||||
fromToken = fromToken == ETH_ADDRESS ? WETH_ADDRESS : fromToken;
|
||||
toToken = toToken == ETH_ADDRESS ? WETH_ADDRESS : toToken;
|
||||
_revertIfShouldFail();
|
||||
fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
|
||||
toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
|
||||
expectedRate = LibDeterministicQuotes.getDeterministicRate(
|
||||
SALT,
|
||||
fromToken,
|
||||
@@ -199,7 +225,8 @@ contract TestERC20BridgeSamplerKyberNetwork is
|
||||
|
||||
|
||||
contract TestERC20BridgeSamplerEth2Dai is
|
||||
IEth2Dai
|
||||
IEth2Dai,
|
||||
FailTrigger
|
||||
{
|
||||
bytes32 constant private SALT = 0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7;
|
||||
|
||||
@@ -213,6 +240,7 @@ contract TestERC20BridgeSamplerEth2Dai is
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicSellQuote(
|
||||
SALT,
|
||||
payToken,
|
||||
@@ -231,6 +259,7 @@ contract TestERC20BridgeSamplerEth2Dai is
|
||||
view
|
||||
returns (uint256 payAmount)
|
||||
{
|
||||
_revertIfShouldFail();
|
||||
return LibDeterministicQuotes.getDeterministicBuyQuote(
|
||||
SALT,
|
||||
payToken,
|
||||
@@ -269,7 +298,8 @@ contract TestERC20BridgeSamplerUniswapExchangeFactory is
|
||||
|
||||
|
||||
contract TestERC20BridgeSampler is
|
||||
ERC20BridgeSampler
|
||||
ERC20BridgeSampler,
|
||||
FailTrigger
|
||||
{
|
||||
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
|
||||
TestERC20BridgeSamplerEth2Dai public eth2Dai;
|
||||
@@ -288,18 +318,30 @@ contract TestERC20BridgeSampler is
|
||||
uniswap.createTokenExchanges(tokenAddresses);
|
||||
}
|
||||
|
||||
// `IExchange.getOrderInfo()`, overridden to return deterministic order infos.
|
||||
function getOrderInfo(LibOrder.Order memory order)
|
||||
// `IDevUtils.getOrderRelevantState()`, overridden to return deterministic
|
||||
// states.
|
||||
function getOrderRelevantState(
|
||||
LibOrder.Order memory order,
|
||||
bytes memory
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (LibOrder.OrderInfo memory orderInfo)
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
)
|
||||
{
|
||||
// The order hash is just the hash of the salt.
|
||||
bytes32 orderHash = keccak256(abi.encode(order.salt));
|
||||
// Everything else is derived from the hash.
|
||||
orderInfo.orderHash = orderHash;
|
||||
orderInfo.orderStatus = uint8(uint256(orderHash) % uint8(-1));
|
||||
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
|
||||
orderInfo.orderTakerAssetFilledAmount =
|
||||
uint256(orderHash) % order.takerAssetAmount;
|
||||
fillableTakerAssetAmount =
|
||||
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
|
||||
isValidSignature = uint256(orderHash) % 2 == 1;
|
||||
}
|
||||
|
||||
// Overriden to return deterministic decimals.
|
||||
@@ -312,38 +354,38 @@ contract TestERC20BridgeSampler is
|
||||
}
|
||||
|
||||
// Overriden to point to a this contract.
|
||||
function _getExchangeContract()
|
||||
function _getDevUtilsAddress()
|
||||
internal
|
||||
view
|
||||
returns (IExchange zeroex)
|
||||
returns (address devUtilAddress)
|
||||
{
|
||||
return IExchange(address(this));
|
||||
return address(this);
|
||||
}
|
||||
|
||||
// Overriden to point to a custom contract.
|
||||
function _getEth2DaiContract()
|
||||
function _getEth2DaiAddress()
|
||||
internal
|
||||
view
|
||||
returns (IEth2Dai eth2dai_)
|
||||
returns (address eth2daiAddress)
|
||||
{
|
||||
return eth2Dai;
|
||||
return address(eth2Dai);
|
||||
}
|
||||
|
||||
// Overriden to point to a custom contract.
|
||||
function _getUniswapExchangeFactoryContract()
|
||||
function _getUniswapExchangeFactoryAddress()
|
||||
internal
|
||||
view
|
||||
returns (IUniswapExchangeFactory uniswap_)
|
||||
returns (address uniswapAddress)
|
||||
{
|
||||
return uniswap;
|
||||
return address(uniswap);
|
||||
}
|
||||
|
||||
// Overriden to point to a custom contract.
|
||||
function _getKyberNetworkContract()
|
||||
function _getKyberNetworkProxyAddress()
|
||||
internal
|
||||
view
|
||||
returns (IKyberNetwork kyber_)
|
||||
returns (address kyberAddress)
|
||||
{
|
||||
return kyber;
|
||||
return address(kyber);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,7 +38,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(DeploymentConstants|ERC20BridgeSampler|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
||||
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -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.2",
|
||||
"@0x/contracts-asset-proxy": "^3.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-exchange": "^3.0.2",
|
||||
"@0x/contracts-exchange-libs": "^4.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -5,16 +5,16 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
|
||||
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
||||
export const artifacts = {
|
||||
DeploymentConstants: DeploymentConstants as ContractArtifact,
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
IDevUtils: IDevUtils as ContractArtifact,
|
||||
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||
|
@@ -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 { Order } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
@@ -31,16 +26,17 @@ 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';
|
||||
const UNSUPPORTED_ASSET_PROXY_ERROR = 'UNSUPPORTED_ASSET_PROXY';
|
||||
const INVALID_ASSET_DATA_ERROR = 'INVALID_ASSET_DATA';
|
||||
const UNSUPPORTED_UNISWAP_EXCHANGE_ERROR = 'UNSUPPORTED_UNISWAP_EXCHANGE';
|
||||
const UNSUPPORTED_SOURCE_ERROR = 'UNSUPPORTED_SOURCE';
|
||||
const INVALID_TOKEN_PAIR_ERROR = 'INVALID_TOKEN_PAIR';
|
||||
const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
|
||||
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
|
||||
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
|
||||
const UNSUPPORTED_SOURCE_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_SOURCE';
|
||||
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
|
||||
@@ -60,7 +56,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 {
|
||||
@@ -197,17 +193,26 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
return quotes;
|
||||
}
|
||||
|
||||
function getDeterministicOrderInfo(order: Order): OrderInfo {
|
||||
const hash = getPackedHash(toHex(order.salt, 32));
|
||||
return {
|
||||
orderHash: hash,
|
||||
orderStatus: new BigNumber(hash).mod(255).toNumber(),
|
||||
orderTakerAssetFilledAmount: new BigNumber(hash).mod(order.takerAssetAmount),
|
||||
};
|
||||
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
||||
const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
|
||||
const orderStatus = new BigNumber(hash).mod(255).toNumber();
|
||||
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
|
||||
if (orderStatus !== 3 || !isValidSignature) {
|
||||
return constants.ZERO_AMOUNT;
|
||||
}
|
||||
return order.takerAssetAmount.minus(new BigNumber(hash).mod(order.takerAssetAmount));
|
||||
}
|
||||
|
||||
function getDeterministicFillableMakerAssetAmount(order: Order): BigNumber {
|
||||
const takerAmount = getDeterministicFillableTakerAssetAmount(order);
|
||||
return order.makerAssetAmount
|
||||
.times(takerAmount)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
}
|
||||
|
||||
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 +239,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),
|
||||
};
|
||||
}
|
||||
@@ -243,57 +248,115 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
return _.times(count || _.random(1, 16), () => createOrder(makerToken, takerToken));
|
||||
}
|
||||
|
||||
describe('queryOrders()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
async function enableFailTriggerAsync(): Promise<void> {
|
||||
await testContract.enableFailTrigger().awaitTransactionSuccessAsync({ value: 1 });
|
||||
}
|
||||
|
||||
it('returns the results of `getOrderInfo()` for each order', async () => {
|
||||
describe('getOrderFillableTakerAssetAmounts()', () => {
|
||||
it('returns the expected amount for each order', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const expected = orders.map(getDeterministicOrderInfo);
|
||||
const actual = await testContract.queryOrders(orders).callAsync();
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq(expected);
|
||||
});
|
||||
|
||||
it('returns empty for no orders', async () => {
|
||||
const actual = await testContract.queryOrders([]).callAsync();
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts([], []).callAsync();
|
||||
expect(actual).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with an empty signature', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOrderFillableMakerAssetAmounts()', () => {
|
||||
it('returns the expected amount for each order', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq(expected);
|
||||
});
|
||||
|
||||
it('returns empty for no orders', async () => {
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts([], []).callAsync();
|
||||
expect(actual).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with an empty signature', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('queryOrdersAndSampleSells()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('returns the results of `getOrderInfo()` for each order', async () => {
|
||||
it('returns expected fillable amounts for each order', async () => {
|
||||
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const expectedOrderInfos = orders.map(getDeterministicOrderInfo);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleSells(orders, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedOrderInfos);
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
|
||||
it('can return quotes for all sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN),
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
sampleAmounts,
|
||||
)
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells([], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
@@ -301,7 +364,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN),
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
@@ -312,10 +376,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with non-ERC20 maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
@@ -326,10 +391,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with non-ERC20 taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
@@ -340,10 +406,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with invalid maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
@@ -354,10 +421,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with invalid taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
@@ -367,39 +435,34 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
|
||||
describe('queryOrdersAndSampleBuys()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('returns the results of `getOrderInfo()` for each order', async () => {
|
||||
it('returns expected fillable amounts for each order', async () => {
|
||||
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const expectedOrderInfos = orders.map(getDeterministicOrderInfo);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleBuys(orders, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedOrderInfos);
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
|
||||
it('can return quotes for all sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN),
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
sampleAmounts,
|
||||
)
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys([], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
@@ -407,7 +470,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN),
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
@@ -419,7 +483,8 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sources = [...BUY_SOURCES, 'Kyber'];
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN),
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
sources.map(n => allSources[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
@@ -430,10 +495,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with non-ERC20 maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
@@ -444,10 +510,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with non-ERC20 taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
@@ -458,10 +525,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with invalid maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
@@ -472,10 +540,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with invalid taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
@@ -485,9 +554,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
|
||||
describe('sampleSells()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -533,9 +599,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
|
||||
describe('sampleBuys()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -588,10 +651,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleSellsFromKyberNetwork()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
blockchainTests.resets('sampleSellsFromKyberNetwork()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -606,7 +666,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('can return many quotes', async () => {
|
||||
it('can quote token - token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
@@ -615,6 +675,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
|
||||
@@ -624,6 +694,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> ETH fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
|
||||
@@ -632,12 +712,19 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if ETH -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleSellsFromEth2Dai()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
blockchainTests.resets('sampleSellsFromEth2Dai()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -652,7 +739,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('can return many quotes', async () => {
|
||||
it('can quote token -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
@@ -661,6 +748,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromEth2Dai(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Eth2Dai'], sampleAmounts);
|
||||
@@ -670,6 +767,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> ETH fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromEth2Dai(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
|
||||
@@ -678,12 +785,19 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if ETH -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromEth2Dai(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleBuysFromEth2Dai()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
blockchainTests.resets('sampleBuysFromEth2Dai()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -698,7 +812,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('can return many quotes', async () => {
|
||||
it('can quote token -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
@@ -707,6 +821,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromEth2Dai(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Eth2Dai'], sampleAmounts);
|
||||
@@ -716,6 +840,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> ETH fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromEth2Dai(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
|
||||
@@ -724,12 +858,19 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if ETH -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromEth2Dai(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleSellsFromUniswap()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
blockchainTests.resets('sampleSellsFromUniswap()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -744,7 +885,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('can return many quotes', async () => {
|
||||
it('can quote token -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Uniswap'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
@@ -753,6 +894,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromUniswap(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Uniswap'], sampleAmounts);
|
||||
@@ -762,6 +913,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> ETH fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromUniswap(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Uniswap'], sampleAmounts);
|
||||
@@ -771,27 +932,38 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no exchange exists for the maker token', async () => {
|
||||
const nonExistantToken = randomAddress();
|
||||
const tx = testContract
|
||||
.sampleSellsFromUniswap(TAKER_TOKEN, nonExistantToken, getSampleAmounts(TAKER_TOKEN))
|
||||
it('returns zero if ETH -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromUniswap(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no exchange exists for the taker token', async () => {
|
||||
it('returns zero if no exchange exists for the maker token', async () => {
|
||||
const nonExistantToken = randomAddress();
|
||||
const tx = testContract
|
||||
.sampleSellsFromUniswap(nonExistantToken, MAKER_TOKEN, getSampleAmounts(nonExistantToken))
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromUniswap(TAKER_TOKEN, nonExistantToken, sampleAmounts)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if no exchange exists for the taker token', async () => {
|
||||
const nonExistantToken = randomAddress();
|
||||
const sampleAmounts = getSampleAmounts(nonExistantToken);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
const quotes = await testContract
|
||||
.sampleSellsFromUniswap(nonExistantToken, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleBuysFromUniswap()', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
|
||||
blockchainTests.resets('sampleBuysFromUniswap()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
@@ -806,7 +978,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('can return many quotes', async () => {
|
||||
it('can quote token -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Uniswap'], sampleAmounts);
|
||||
const quotes = await testContract
|
||||
@@ -815,6 +987,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromUniswap(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote token -> ETH', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Uniswap'], sampleAmounts);
|
||||
@@ -824,6 +1006,16 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if token -> ETH fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromUniswap(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can quote ETH -> token', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Uniswap'], sampleAmounts);
|
||||
@@ -833,20 +1025,34 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no exchange exists for the maker token', async () => {
|
||||
const nonExistantToken = randomAddress();
|
||||
const tx = testContract
|
||||
.sampleBuysFromUniswap(TAKER_TOKEN, nonExistantToken, getSampleAmounts(TAKER_TOKEN))
|
||||
it('returns zero if ETH -> token fails', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
await enableFailTriggerAsync();
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromUniswap(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no exchange exists for the taker token', async () => {
|
||||
it('returns zero if no exchange exists for the maker token', async () => {
|
||||
const nonExistantToken = randomAddress();
|
||||
const tx = testContract
|
||||
.sampleBuysFromUniswap(nonExistantToken, MAKER_TOKEN, getSampleAmounts(nonExistantToken))
|
||||
const sampleAmounts = getSampleAmounts(nonExistantToken);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromUniswap(TAKER_TOKEN, nonExistantToken, sampleAmounts)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('returns zero if no exchange exists for the taker token', async () => {
|
||||
const nonExistantToken = randomAddress();
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
|
||||
const quotes = await testContract
|
||||
.sampleBuysFromUniswap(nonExistantToken, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/deployment_constants';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/i_dev_utils';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_kyber_network';
|
||||
|
@@ -5,8 +5,8 @@
|
||||
"files": [
|
||||
"generated-artifacts/ERC20BridgeSampler.json",
|
||||
"generated-artifacts/IERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/DeploymentConstants.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/IDevUtils.json",
|
||||
"test/generated-artifacts/IERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberNetwork.json",
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -3,6 +3,9 @@ export {
|
||||
DummyMultipleReturnERC20TokenContract,
|
||||
DummyNoReturnERC20TokenContract,
|
||||
WETH9Contract,
|
||||
WETH9Events,
|
||||
WETH9DepositEventArgs,
|
||||
WETH9TransferEventArgs,
|
||||
ZRXTokenContract,
|
||||
DummyERC20TokenTransferEventArgs,
|
||||
ERC20TokenEventArgs,
|
||||
|
@@ -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,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "4.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/contracts-asset-proxy": "^3.0.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-erc721": "^3.0.2",
|
||||
"@0x/contracts-exchange": "^3.0.2",
|
||||
"@0x/contracts-exchange-libs": "^4.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@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.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -89,8 +89,8 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -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,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "4.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "4.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/subproviders": "^6.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -103,7 +103,7 @@ export function calculateFillResults(
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount,
|
||||
);
|
||||
const makerFeePaid = safeGetPartialAmountFloor(makerAssetFilledAmount, order.makerAssetAmount, order.makerFee);
|
||||
const makerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.makerFee);
|
||||
const takerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.takerFee);
|
||||
return {
|
||||
makerAssetFilledAmount,
|
||||
@@ -113,3 +113,30 @@ export function calculateFillResults(
|
||||
protocolFeePaid: safeMul(protocolFeeMultiplier, gasPrice),
|
||||
};
|
||||
}
|
||||
|
||||
export const LibFractions = {
|
||||
add: (n1: BigNumber, d1: BigNumber, n2: BigNumber, d2: BigNumber): [BigNumber, BigNumber] => {
|
||||
if (n1.isZero()) {
|
||||
return [n2, d2];
|
||||
}
|
||||
if (n2.isZero()) {
|
||||
return [n1, d1];
|
||||
}
|
||||
const numerator = safeAdd(safeMul(n1, d2), safeMul(n2, d1));
|
||||
const denominator = safeMul(d1, d2);
|
||||
return [numerator, denominator];
|
||||
},
|
||||
normalize: (
|
||||
numerator: BigNumber,
|
||||
denominator: BigNumber,
|
||||
maxValue: BigNumber = new BigNumber(2).exponentiatedBy(127),
|
||||
): [BigNumber, BigNumber] => {
|
||||
if (numerator.isGreaterThan(maxValue) || denominator.isGreaterThan(maxValue)) {
|
||||
let rescaleBase = numerator.isGreaterThanOrEqualTo(denominator) ? numerator : denominator;
|
||||
rescaleBase = safeDiv(rescaleBase, maxValue);
|
||||
return [safeDiv(numerator, rescaleBase), safeDiv(denominator, rescaleBase)];
|
||||
} else {
|
||||
return [numerator, denominator];
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@@ -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,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "3.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "3.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"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.2",
|
||||
"@0x/contracts-asset-proxy": "^3.0.2",
|
||||
"@0x/contracts-exchange-libs": "^4.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-multisig": "^4.0.2",
|
||||
"@0x/contracts-staking": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.2",
|
||||
"@0x/contracts-erc1155": "^2.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-erc721": "^3.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"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}`);
|
||||
}
|
||||
|
@@ -107,23 +107,6 @@ describe('Reference functions', () => {
|
||||
).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if `order.makerAssetAmount` is 0', () => {
|
||||
const order = makeOrder({
|
||||
makerAssetAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetAmount: ONE_ETHER,
|
||||
});
|
||||
const takerAssetFilledAmount = ONE_ETHER;
|
||||
const expectedError = new LibMathRevertErrors.DivisionByZeroError();
|
||||
return expect(() =>
|
||||
LibReferenceFunctions.calculateFillResults(
|
||||
order,
|
||||
takerAssetFilledAmount,
|
||||
DEFAULT_PROTOCOL_FEE_MULTIPLIER,
|
||||
DEFAULT_GAS_PRICE,
|
||||
),
|
||||
).to.throw(expectedError.message);
|
||||
});
|
||||
|
||||
it('reverts if `order.takerAssetAmount` is 0', () => {
|
||||
const order = makeOrder({
|
||||
makerAssetAmount: ONE_ETHER,
|
||||
|
@@ -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,23 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "5.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "5.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Export function `encodeDutchAuctionAssetData`",
|
||||
"pr": 2373
|
||||
}
|
||||
],
|
||||
"timestamp": 1575931811
|
||||
},
|
||||
{
|
||||
"version": "5.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.1.1 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.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.2",
|
||||
"@0x/contracts-asset-proxy": "^3.0.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-erc721": "^3.0.2",
|
||||
"@0x/contracts-exchange": "^3.0.2",
|
||||
"@0x/contracts-exchange-libs": "^4.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@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.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@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,8 +91,8 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.0",
|
||||
"@0x/typescript-typings": "^5.0.0",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -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,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1576540892,
|
||||
"version": "2.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "2.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.2 - _December 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## 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.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -19,6 +19,7 @@
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"test:fuzz": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/fuzz_tests/*.js' --timeout 0 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
@@ -50,25 +51,27 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.0",
|
||||
"@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/abi-gen": "^5.0.2",
|
||||
"@0x/contract-addresses": "^4.1.0",
|
||||
"@0x/contract-wrappers": "^13.2.0",
|
||||
"@0x/contracts-coordinator": "^3.0.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.2",
|
||||
"@0x/contracts-exchange-forwarder": "^4.0.2",
|
||||
"@0x/contracts-exchange-libs": "^4.0.2",
|
||||
"@0x/contracts-gen": "^2.0.2",
|
||||
"@0x/contracts-utils": "^4.0.2",
|
||||
"@0x/coordinator-server": "^1.0.5",
|
||||
"@0x/dev-utils": "^3.0.2",
|
||||
"@0x/migrations": "^5.0.2",
|
||||
"@0x/order-utils": "^10.0.1",
|
||||
"@0x/sol-compiler": "^4.0.2",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.2",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"@types/seedrandom": "^2.4.28",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
@@ -78,6 +81,7 @@
|
||||
"mocha": "^6.2.0",
|
||||
"nock": "^10.0.6",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"seedrandom": "^3.0.5",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
@@ -85,18 +89,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/typescript-typings": "^5.0.0",
|
||||
"@0x/utils": "^5.0.0",
|
||||
"@0x/base-contract": "^6.0.2",
|
||||
"@0x/contracts-asset-proxy": "^3.0.2",
|
||||
"@0x/contracts-erc1155": "^2.0.2",
|
||||
"@0x/contracts-erc20": "^3.0.2",
|
||||
"@0x/contracts-erc721": "^3.0.2",
|
||||
"@0x/contracts-exchange": "^3.0.2",
|
||||
"@0x/contracts-multisig": "^4.0.2",
|
||||
"@0x/contracts-staking": "^2.0.2",
|
||||
"@0x/contracts-test-utils": "^5.0.1",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.1",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user