Merge branch '3.0' into feat/3.0/testnet-migrations
This commit is contained in:
commit
ac1063dd68
@ -72,18 +72,6 @@ jobs:
|
|||||||
# - run: yarn wsrun test:circleci @0x/contracts-extensions
|
# - run: yarn wsrun test:circleci @0x/contracts-extensions
|
||||||
# TODO(abandeali): Re-enable after this package is complete.
|
# TODO(abandeali): Re-enable after this package is complete.
|
||||||
# - run: yarn wsrun test:circleci @0x/contracts-coordinator
|
# - run: yarn wsrun test:circleci @0x/contracts-coordinator
|
||||||
test-contracts-geth:
|
|
||||||
docker:
|
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
|
||||||
- image: 0xorg/devnet
|
|
||||||
working_directory: ~/repo
|
|
||||||
steps:
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
|
||||||
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
|
|
||||||
# initialized
|
|
||||||
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils @0x/contracts-staking
|
|
||||||
test-publish:
|
test-publish:
|
||||||
resource_class: medium+
|
resource_class: medium+
|
||||||
docker:
|
docker:
|
||||||
@ -94,7 +82,9 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn test:publish:circleci
|
- run:
|
||||||
|
command: yarn test:publish:circleci
|
||||||
|
no_output_timeout: 1800
|
||||||
test-doc-generation:
|
test-doc-generation:
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
@ -103,7 +93,9 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
- run: yarn test:generate_docs:circleci
|
- run:
|
||||||
|
command: yarn test:generate_docs:circleci
|
||||||
|
no_output_timeout: 1200
|
||||||
test-rest:
|
test-rest:
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
@ -405,22 +397,18 @@ workflows:
|
|||||||
- test-contracts-rest-ganache-3.0:
|
- test-contracts-rest-ganache-3.0:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
# Disabled until geth docker image is fixed.
|
|
||||||
# - test-contracts-geth:
|
|
||||||
# requires:
|
|
||||||
# - build
|
|
||||||
- test-rest:
|
- test-rest:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
- static-tests:
|
- static-tests:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
# - test-publish:
|
- test-publish:
|
||||||
# requires:
|
requires:
|
||||||
# - build
|
- build
|
||||||
# - test-doc-generation:
|
- test-doc-generation:
|
||||||
# requires:
|
requires:
|
||||||
# - build
|
- build
|
||||||
- submit-coverage:
|
- submit-coverage:
|
||||||
requires:
|
requires:
|
||||||
- test-contracts-rest-ganache-3.0
|
- test-contracts-rest-ganache-3.0
|
||||||
|
1
.github/autolabeler.yml
vendored
1
.github/autolabeler.yml
vendored
@ -32,6 +32,5 @@ contracts: ['contracts']
|
|||||||
@0x/json-schemas: ['packages/json-schemas']
|
@0x/json-schemas: ['packages/json-schemas']
|
||||||
@0x/ethereum-types: ['ethereum-types']
|
@0x/ethereum-types: ['ethereum-types']
|
||||||
@0x/connect: ['packages/connect']
|
@0x/connect: ['packages/connect']
|
||||||
@0x/fill-scenarios: ['packages/fill-scenarios']
|
|
||||||
@0x/testnet-faucets: ['packages/testnet-faucets']
|
@0x/testnet-faucets: ['packages/testnet-faucets']
|
||||||
@0x/monorepo-scripts: ['packages/monorepo-scripts']
|
@0x/monorepo-scripts: ['packages/monorepo-scripts']
|
||||||
|
@ -93,7 +93,6 @@ These packages are all under development. See [/contracts/README.md](/contracts/
|
|||||||
| [`@0x/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages |
|
| [`@0x/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages |
|
||||||
| [`@0x/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
|
| [`@0x/base-contract`](/packages/base-contract) | [](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
|
||||||
| [`@0x/dev-utils`](/packages/dev-utils) | [](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages |
|
| [`@0x/dev-utils`](/packages/dev-utils) | [](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages |
|
||||||
| [`@0x/fill-scenarios`](/packages/fill-scenarios) | [](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator |
|
|
||||||
|
|
||||||
#### Private Packages
|
#### Private Packages
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "3.0.0",
|
"version": "2.3.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
|
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
|
||||||
@ -17,8 +17,17 @@
|
|||||||
{
|
{
|
||||||
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
|
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
|
||||||
"pr": 1910
|
"pr": 1910
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `ERC20BridgeProxy`",
|
||||||
|
"pr": 2220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `Eth2DaiBridge`",
|
||||||
|
"pr": 2221
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.3.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
|
||||||
|
* Remove `LibAssetProxyIds` contract (#2055)
|
||||||
|
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||||
|
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
|
||||||
|
* Add `ERC20BridgeProxy` (#2220)
|
||||||
|
* Add `Eth2DaiBridge` (#2221)
|
||||||
|
|
||||||
## v2.2.8 - _September 17, 2019_
|
## v2.2.8 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
@ -58,6 +67,9 @@ CHANGELOG
|
|||||||
## v2.1.2 - _May 10, 2019_
|
## v2.1.2 - _May 10, 2019_
|
||||||
|
|
||||||
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
|
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
|
||||||
|
* Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819)
|
||||||
|
* Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819)
|
||||||
|
* Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819)
|
||||||
|
|
||||||
## v2.1.1 - _April 11, 2019_
|
## v2.1.1 - _April 11, 2019_
|
||||||
|
|
||||||
|
126
contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
Normal file
126
contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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/LibBytes.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
|
||||||
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
|
import "./interfaces/IAssetProxy.sol";
|
||||||
|
import "./interfaces/IERC20Bridge.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract ERC20BridgeProxy is
|
||||||
|
IAssetProxy,
|
||||||
|
Authorizable
|
||||||
|
{
|
||||||
|
using LibBytes for bytes;
|
||||||
|
using LibSafeMath for uint256;
|
||||||
|
|
||||||
|
// @dev Id of this proxy. Also the result of a successful bridge call.
|
||||||
|
// bytes4(keccak256("ERC20Bridge(address,address,bytes)"))
|
||||||
|
bytes4 constant private PROXY_ID = 0xdc1600f3;
|
||||||
|
|
||||||
|
/// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from`
|
||||||
|
/// to `to`. Asserts that the balance of `to` has increased by `amount`.
|
||||||
|
/// @param assetData Abi-encoded data for this asset proxy encoded as:
|
||||||
|
/// abi.encodeWithSelector(
|
||||||
|
/// bytes4 PROXY_ID,
|
||||||
|
/// address tokenAddress,
|
||||||
|
/// address bridgeAddress,
|
||||||
|
/// bytes bridgeData
|
||||||
|
/// )
|
||||||
|
/// @param from Address to transfer asset from.
|
||||||
|
/// @param to Address to transfer asset to.
|
||||||
|
/// @param amount Amount of asset to transfer.
|
||||||
|
function transferFrom(
|
||||||
|
bytes calldata assetData,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyAuthorized
|
||||||
|
{
|
||||||
|
// Extract asset data fields.
|
||||||
|
(
|
||||||
|
address tokenAddress,
|
||||||
|
address bridgeAddress,
|
||||||
|
bytes memory bridgeData
|
||||||
|
) = abi.decode(
|
||||||
|
assetData.sliceDestructive(4, assetData.length),
|
||||||
|
(address, address, bytes)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remember the balance of `to` before calling the bridge.
|
||||||
|
uint256 balanceBefore = balanceOf(tokenAddress, to);
|
||||||
|
// Call the bridge, who should transfer `amount` of `tokenAddress` to
|
||||||
|
// `to`.
|
||||||
|
bytes4 success = IERC20Bridge(bridgeAddress).withdrawTo(
|
||||||
|
tokenAddress,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
amount,
|
||||||
|
bridgeData
|
||||||
|
);
|
||||||
|
// Bridge must return the proxy ID to indicate success.
|
||||||
|
require(success == PROXY_ID, "BRIDGE_FAILED");
|
||||||
|
// Ensure that the balance of `to` has increased by at least `amount`.
|
||||||
|
require(
|
||||||
|
balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to),
|
||||||
|
"BRIDGE_UNDERPAY"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Gets the proxy id associated with this asset proxy.
|
||||||
|
/// @return proxyId The proxy id.
|
||||||
|
function getProxyId()
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
returns (bytes4 proxyId)
|
||||||
|
{
|
||||||
|
return PROXY_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Retrieves the balance of `owner` for this asset.
|
||||||
|
/// @return balance The balance of the ERC20 token being transferred by this
|
||||||
|
/// asset proxy.
|
||||||
|
function balanceOf(bytes calldata assetData, address owner)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256 balance)
|
||||||
|
{
|
||||||
|
(address tokenAddress) = abi.decode(
|
||||||
|
assetData.sliceDestructive(4, assetData.length),
|
||||||
|
(address)
|
||||||
|
);
|
||||||
|
return balanceOf(tokenAddress, owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Retrieves the balance of `owner` given an ERC20 address.
|
||||||
|
/// @return balance The balance of the ERC20 token for `owner`.
|
||||||
|
function balanceOf(address tokenAddress, address owner)
|
||||||
|
private
|
||||||
|
view
|
||||||
|
returns (uint256 balance)
|
||||||
|
{
|
||||||
|
return IERC20Token(tokenAddress).balanceOf(owner);
|
||||||
|
}
|
||||||
|
}
|
142
contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol
Normal file
142
contracts/asset-proxy/contracts/src/bridges/Eth2DaiBridge.sol
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
|
import "../interfaces/IERC20Bridge.sol";
|
||||||
|
import "../interfaces/IEth2Dai.sol";
|
||||||
|
import "../interfaces/IWallet.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable space-after-comma
|
||||||
|
contract Eth2DaiBridge is
|
||||||
|
IERC20Bridge,
|
||||||
|
IWallet
|
||||||
|
{
|
||||||
|
/* Mainnet addresses */
|
||||||
|
address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||||
|
|
||||||
|
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||||
|
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||||
|
/// (DAI or WETH) to the Eth2Dai contract, then transfers the bought
|
||||||
|
/// tokens to `to`.
|
||||||
|
/// @param toTokenAddress The token to give to `to` (either DAI or WETH).
|
||||||
|
/// @param to The recipient of the bought tokens.
|
||||||
|
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||||
|
/// @param bridgeData The abi-encoeded "from" token address.
|
||||||
|
/// @return success The magic bytes if successful.
|
||||||
|
function withdrawTo(
|
||||||
|
address toTokenAddress,
|
||||||
|
address /* from */,
|
||||||
|
address to,
|
||||||
|
uint256 amount,
|
||||||
|
bytes calldata bridgeData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (bytes4 success)
|
||||||
|
{
|
||||||
|
// Decode the bridge data to get the `fromTokenAddress`.
|
||||||
|
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||||
|
|
||||||
|
IEth2Dai exchange = _getEth2DaiContract();
|
||||||
|
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||||
|
IERC20Token(fromTokenAddress).approve(address(exchange), uint256(-1));
|
||||||
|
|
||||||
|
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||||
|
uint256 boughtAmount = _getEth2DaiContract().sellAllAmount(
|
||||||
|
address(fromTokenAddress),
|
||||||
|
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||||
|
toTokenAddress,
|
||||||
|
amount
|
||||||
|
);
|
||||||
|
// Transfer the converted `toToken`s to `to`.
|
||||||
|
_transferERC20Token(toTokenAddress, to, boughtAmount);
|
||||||
|
return BRIDGE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||||
|
/// and sign for itself in orders. Always succeeds.
|
||||||
|
/// @return magicValue Magic success bytes, always.
|
||||||
|
function isValidSignature(
|
||||||
|
bytes32,
|
||||||
|
bytes calldata
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes4 magicValue)
|
||||||
|
{
|
||||||
|
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(ETH2DAI_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Permissively transfers an ERC20 token that may not adhere to
|
||||||
|
/// specs.
|
||||||
|
/// @param tokenAddress The token contract address.
|
||||||
|
/// @param to The token recipient.
|
||||||
|
/// @param amount The amount of tokens to transfer.
|
||||||
|
function _transferERC20Token(
|
||||||
|
address tokenAddress,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
private
|
||||||
|
{
|
||||||
|
// Transfer tokens.
|
||||||
|
// We do a raw call so we can check the success separate
|
||||||
|
// from the return data.
|
||||||
|
(bool didSucceed, bytes memory returnData) = tokenAddress.call(
|
||||||
|
abi.encodeWithSelector(
|
||||||
|
IERC20Token(0).transfer.selector,
|
||||||
|
to,
|
||||||
|
amount
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (!didSucceed) {
|
||||||
|
assembly { revert(add(returnData, 0x20), mload(returnData)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check return data.
|
||||||
|
// If there is no return data, we assume the token incorrectly
|
||||||
|
// does not return a bool. In this case we expect it to revert
|
||||||
|
// on failure, which was handled above.
|
||||||
|
// If the token does return data, we require that it is a single
|
||||||
|
// value that evaluates to true.
|
||||||
|
assembly {
|
||||||
|
if returndatasize {
|
||||||
|
didSucceed := 0
|
||||||
|
if eq(returndatasize, 32) {
|
||||||
|
// First 64 bytes of memory are reserved scratch space
|
||||||
|
returndatacopy(0, 0, 32)
|
||||||
|
didSucceed := mload(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
require(didSucceed, "ERC20_TRANSFER_FAILED");
|
||||||
|
}
|
||||||
|
}
|
@ -74,4 +74,15 @@ interface IAssetData {
|
|||||||
bytes32 expectedReturnDataHash
|
bytes32 expectedReturnDataHash
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
|
/// @dev Function signature for encoding ERC20Bridge assetData.
|
||||||
|
/// @param tokenAddress Address of token to transfer.
|
||||||
|
/// @param bridgeAddress Address of the bridge contract.
|
||||||
|
/// @param bridgeData Arbitrary data to be passed to the bridge contract.
|
||||||
|
function ERC20Bridge(
|
||||||
|
address tokenAddress,
|
||||||
|
address bridgeAddress,
|
||||||
|
bytes calldata bridgeData
|
||||||
|
)
|
||||||
|
external;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
contract IERC20Bridge {
|
||||||
|
|
||||||
|
// @dev Result of a successful bridge call.
|
||||||
|
bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
|
||||||
|
|
||||||
|
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
||||||
|
/// @param tokenAddress The address of the ERC20 token to transfer.
|
||||||
|
/// @param from Address to transfer asset from.
|
||||||
|
/// @param to Address to transfer asset to.
|
||||||
|
/// @param amount Amount of asset to transfer.
|
||||||
|
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
||||||
|
/// @return success The magic bytes `0x37708e9b` if successful.
|
||||||
|
function withdrawTo(
|
||||||
|
address tokenAddress,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount,
|
||||||
|
bytes calldata bridgeData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (bytes4 success);
|
||||||
|
}
|
38
contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
Normal file
38
contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 IEth2Dai {
|
||||||
|
|
||||||
|
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||||
|
/// @param fromToken The token being sold.
|
||||||
|
/// @param sellAmount The amount of `fromToken` token being sold.
|
||||||
|
/// @param toToken The token being bought.
|
||||||
|
/// @param minFillAmount Minimum amount of `toToken` token to buy.
|
||||||
|
/// @return fillAmount Amount of `toToken` bought.
|
||||||
|
function sellAllAmount(
|
||||||
|
address fromToken,
|
||||||
|
uint256 sellAmount,
|
||||||
|
address toToken,
|
||||||
|
uint256 minFillAmount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint256 fillAmount);
|
||||||
|
}
|
38
contracts/asset-proxy/contracts/src/interfaces/IWallet.sol
Normal file
38
contracts/asset-proxy/contracts/src/interfaces/IWallet.sol
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
contract IWallet {
|
||||||
|
|
||||||
|
bytes4 internal constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381;
|
||||||
|
|
||||||
|
/// @dev Validates a hash with the `Wallet` signature type.
|
||||||
|
/// @param hash Message hash that is signed.
|
||||||
|
/// @param signature Proof of signing.
|
||||||
|
/// @return magicValue `bytes4(0xb0671381)` if the signature check succeeds.
|
||||||
|
function isValidSignature(
|
||||||
|
bytes32 hash,
|
||||||
|
bytes calldata signature
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (bytes4 magicValue);
|
||||||
|
}
|
108
contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
Normal file
108
contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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/interfaces/IERC20Bridge.sol";
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev Test bridge token
|
||||||
|
contract TestERC20BridgeToken {
|
||||||
|
mapping (address => uint256) private _balances;
|
||||||
|
|
||||||
|
function addBalance(address owner, int256 amount)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
setBalance(owner, uint256(int256(balanceOf(owner)) + amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBalance(address owner, uint256 balance)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
_balances[owner] = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
function balanceOf(address owner)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
return _balances[owner];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev Test bridge contract.
|
||||||
|
contract TestERC20Bridge is
|
||||||
|
IERC20Bridge
|
||||||
|
{
|
||||||
|
TestERC20BridgeToken public testToken;
|
||||||
|
|
||||||
|
event BridgeWithdrawTo(
|
||||||
|
address tokenAddress,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount,
|
||||||
|
bytes bridgeData
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor() public {
|
||||||
|
testToken = new TestERC20BridgeToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTestTokenBalance(address owner, uint256 balance)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
testToken.setBalance(owner, balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
function withdrawTo(
|
||||||
|
address tokenAddress,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount,
|
||||||
|
bytes calldata bridgeData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (bytes4)
|
||||||
|
{
|
||||||
|
emit BridgeWithdrawTo(
|
||||||
|
tokenAddress,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
amount,
|
||||||
|
bridgeData
|
||||||
|
);
|
||||||
|
// Unpack the bridgeData.
|
||||||
|
(
|
||||||
|
int256 transferAmount,
|
||||||
|
bytes memory revertData,
|
||||||
|
bytes memory returnData
|
||||||
|
) = abi.decode(bridgeData, (int256, bytes, bytes));
|
||||||
|
|
||||||
|
// If `revertData` is set, revert.
|
||||||
|
if (revertData.length != 0) {
|
||||||
|
assembly { revert(add(revertData, 0x20), mload(revertData)) }
|
||||||
|
}
|
||||||
|
// Increase `to`'s balance by `transferAmount`.
|
||||||
|
TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount);
|
||||||
|
// Return `returnData`.
|
||||||
|
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
||||||
|
}
|
||||||
|
}
|
202
contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
Normal file
202
contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
|
import "../src/bridges/Eth2DaiBridge.sol";
|
||||||
|
import "../src/interfaces/IEth2Dai.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable no-simple-event-func-name
|
||||||
|
contract TestEvents {
|
||||||
|
|
||||||
|
event TokenTransfer(
|
||||||
|
address token,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
);
|
||||||
|
|
||||||
|
event TokenApprove(
|
||||||
|
address token,
|
||||||
|
address spender,
|
||||||
|
uint256 allowance
|
||||||
|
);
|
||||||
|
|
||||||
|
function raiseTokenTransfer(
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
emit TokenTransfer(
|
||||||
|
msg.sender,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
amount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function raiseTokenApprove(address spender, uint256 allowance)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
emit TokenApprove(msg.sender, spender, allowance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev A minimalist ERC20 token.
|
||||||
|
contract TestToken {
|
||||||
|
|
||||||
|
mapping (address => uint256) public balances;
|
||||||
|
string private _nextTransferRevertReason;
|
||||||
|
bytes private _nextTransferReturnData;
|
||||||
|
|
||||||
|
/// @dev Just calls `raiseTokenTransfer()` on the caller.
|
||||||
|
function transfer(address to, uint256 amount)
|
||||||
|
external
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
|
||||||
|
if (bytes(_nextTransferRevertReason).length != 0) {
|
||||||
|
revert(_nextTransferRevertReason);
|
||||||
|
}
|
||||||
|
bytes memory returnData = _nextTransferReturnData;
|
||||||
|
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Set the balance for `owner`.
|
||||||
|
function setBalance(address owner, uint256 balance)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
balances[owner] = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Set the behavior of the `transfer()` call.
|
||||||
|
function setTransferBehavior(
|
||||||
|
string calldata revertReason,
|
||||||
|
bytes calldata returnData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
_nextTransferRevertReason = revertReason;
|
||||||
|
_nextTransferReturnData = returnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Just calls `raiseTokenApprove()` on the caller.
|
||||||
|
function approve(address spender, uint256 allowance)
|
||||||
|
external
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
TestEvents(msg.sender).raiseTokenApprove(spender, allowance);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Retrieve the balance for `owner`.
|
||||||
|
function balanceOf(address owner)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
return balances[owner];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev Eth2DaiBridge overridden to mock tokens and
|
||||||
|
/// implement IEth2Dai.
|
||||||
|
contract TestEth2DaiBridge is
|
||||||
|
TestEvents,
|
||||||
|
IEth2Dai,
|
||||||
|
Eth2DaiBridge
|
||||||
|
{
|
||||||
|
event SellAllAmount(
|
||||||
|
address sellToken,
|
||||||
|
uint256 sellTokenAmount,
|
||||||
|
address buyToken,
|
||||||
|
uint256 minimumFillAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
mapping (address => TestToken) public testTokens;
|
||||||
|
string private _nextRevertReason;
|
||||||
|
uint256 private _nextFillAmount;
|
||||||
|
|
||||||
|
/// @dev Create a token and set this contract's balance.
|
||||||
|
function createToken(uint256 balance)
|
||||||
|
external
|
||||||
|
returns (address tokenAddress)
|
||||||
|
{
|
||||||
|
TestToken token = new TestToken();
|
||||||
|
testTokens[address(token)] = token;
|
||||||
|
token.setBalance(address(this), balance);
|
||||||
|
return address(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Set the behavior for `IEth2Dai.sellAllAmount()`.
|
||||||
|
function setFillBehavior(string calldata revertReason, uint256 fillAmount)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
_nextRevertReason = revertReason;
|
||||||
|
_nextFillAmount = fillAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Set the behavior of a token's `transfer()`.
|
||||||
|
function setTransferBehavior(
|
||||||
|
address tokenAddress,
|
||||||
|
string calldata revertReason,
|
||||||
|
bytes calldata returnData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
testTokens[tokenAddress].setTransferBehavior(revertReason, returnData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Implementation of `IEth2Dai.sellAllAmount()`
|
||||||
|
function sellAllAmount(
|
||||||
|
address sellTokenAddress,
|
||||||
|
uint256 sellTokenAmount,
|
||||||
|
address buyTokenAddress,
|
||||||
|
uint256 minimumFillAmount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint256 fillAmount)
|
||||||
|
{
|
||||||
|
emit SellAllAmount(
|
||||||
|
sellTokenAddress,
|
||||||
|
sellTokenAmount,
|
||||||
|
buyTokenAddress,
|
||||||
|
minimumFillAmount
|
||||||
|
);
|
||||||
|
if (bytes(_nextRevertReason).length != 0) {
|
||||||
|
revert(_nextRevertReason);
|
||||||
|
}
|
||||||
|
return _nextFillAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @dev This contract will double as the Eth2Dai contract.
|
||||||
|
function _getEth2DaiContract()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (IEth2Dai)
|
||||||
|
{
|
||||||
|
return IEth2Dai(address(this));
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-asset-proxy",
|
"name": "@0x/contracts-asset-proxy",
|
||||||
"version": "2.2.8",
|
"version": "2.3.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"compile:truffle": "truffle compile"
|
"compile:truffle": "truffle compile"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestStaticCallTarget).json",
|
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IWallet|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestStaticCallTarget).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -48,11 +48,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -71,17 +71,17 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-erc1155": "^1.1.15",
|
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc721": "^2.1.15",
|
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@ -6,30 +6,44 @@
|
|||||||
import { ContractArtifact } from 'ethereum-types';
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.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';
|
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
|
||||||
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
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 IAssetData from '../generated-artifacts/IAssetData.json';
|
||||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
||||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||||
|
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||||
|
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
|
||||||
|
import * as IWallet from '../generated-artifacts/IWallet.json';
|
||||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||||
|
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
|
||||||
|
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
|
||||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||||
Ownable: Ownable as ContractArtifact,
|
Ownable: Ownable as ContractArtifact,
|
||||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||||
|
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
||||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||||
|
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||||
IAssetData: IAssetData as ContractArtifact,
|
IAssetData: IAssetData as ContractArtifact,
|
||||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||||
|
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||||
|
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||||
|
IWallet: IWallet as ContractArtifact,
|
||||||
|
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
|
||||||
|
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
|
||||||
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -4,15 +4,22 @@
|
|||||||
* -----------------------------------------------------------------------------
|
* -----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
export * from '../generated-wrappers/erc1155_proxy';
|
export * from '../generated-wrappers/erc1155_proxy';
|
||||||
|
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||||
export * from '../generated-wrappers/erc20_proxy';
|
export * from '../generated-wrappers/erc20_proxy';
|
||||||
export * from '../generated-wrappers/erc721_proxy';
|
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_data';
|
||||||
export * from '../generated-wrappers/i_asset_proxy';
|
export * from '../generated-wrappers/i_asset_proxy';
|
||||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||||
export * from '../generated-wrappers/i_authorizable';
|
export * from '../generated-wrappers/i_authorizable';
|
||||||
|
export * from '../generated-wrappers/i_erc20_bridge';
|
||||||
|
export * from '../generated-wrappers/i_eth2_dai';
|
||||||
|
export * from '../generated-wrappers/i_wallet';
|
||||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||||
export * from '../generated-wrappers/mixin_authorizable';
|
export * from '../generated-wrappers/mixin_authorizable';
|
||||||
export * from '../generated-wrappers/multi_asset_proxy';
|
export * from '../generated-wrappers/multi_asset_proxy';
|
||||||
export * from '../generated-wrappers/ownable';
|
export * from '../generated-wrappers/ownable';
|
||||||
export * from '../generated-wrappers/static_call_proxy';
|
export * from '../generated-wrappers/static_call_proxy';
|
||||||
|
export * from '../generated-wrappers/test_erc20_bridge';
|
||||||
|
export * from '../generated-wrappers/test_eth2_dai_bridge';
|
||||||
export * from '../generated-wrappers/test_static_call_target';
|
export * from '../generated-wrappers/test_static_call_target';
|
||||||
|
299
contracts/asset-proxy/test/erc20bridge_proxy.ts
Normal file
299
contracts/asset-proxy/test/erc20bridge_proxy.ts
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
import {
|
||||||
|
blockchainTests,
|
||||||
|
constants,
|
||||||
|
expect,
|
||||||
|
getRandomInteger,
|
||||||
|
hexLeftPad,
|
||||||
|
hexRightPad,
|
||||||
|
hexSlice,
|
||||||
|
Numberish,
|
||||||
|
randomAddress,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { AssetProxyId } from '@0x/types';
|
||||||
|
import { AbiEncoder, AuthorizableRevertErrors, BigNumber, StringRevertError } from '@0x/utils';
|
||||||
|
import { DecodedLogs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import {
|
||||||
|
artifacts,
|
||||||
|
ERC20BridgeProxyContract,
|
||||||
|
TestERC20BridgeBridgeWithdrawToEventArgs,
|
||||||
|
TestERC20BridgeContract,
|
||||||
|
} from '../src';
|
||||||
|
|
||||||
|
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
|
||||||
|
const PROXY_ID = AssetProxyId.ERC20Bridge;
|
||||||
|
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID);
|
||||||
|
let owner: string;
|
||||||
|
let badCaller: string;
|
||||||
|
let assetProxy: ERC20BridgeProxyContract;
|
||||||
|
let bridgeContract: TestERC20BridgeContract;
|
||||||
|
let testTokenAddress: string;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
[owner, badCaller] = await env.getAccountAddressesAsync();
|
||||||
|
assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.ERC20BridgeProxy,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
);
|
||||||
|
bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestERC20Bridge,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
);
|
||||||
|
testTokenAddress = await bridgeContract.testToken.callAsync();
|
||||||
|
await assetProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner);
|
||||||
|
});
|
||||||
|
|
||||||
|
interface AssetDataOpts {
|
||||||
|
tokenAddress: string;
|
||||||
|
bridgeAddress: string;
|
||||||
|
bridgeData: BridgeDataOpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BridgeDataOpts {
|
||||||
|
transferAmount: Numberish;
|
||||||
|
revertError?: string;
|
||||||
|
returnData: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAssetData(opts?: Partial<AssetDataOpts>): AssetDataOpts {
|
||||||
|
return _.merge(
|
||||||
|
{
|
||||||
|
tokenAddress: testTokenAddress,
|
||||||
|
bridgeAddress: bridgeContract.address,
|
||||||
|
bridgeData: createBridgeData(),
|
||||||
|
},
|
||||||
|
opts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBridgeData(opts?: Partial<BridgeDataOpts>): BridgeDataOpts {
|
||||||
|
return _.merge(
|
||||||
|
{
|
||||||
|
transferAmount: constants.ZERO_AMOUNT,
|
||||||
|
returnData: BRIDGE_SUCCESS_RETURN_DATA,
|
||||||
|
},
|
||||||
|
opts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeAssetData(opts: AssetDataOpts): string {
|
||||||
|
const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [
|
||||||
|
{ name: 'tokenAddress', type: 'address' },
|
||||||
|
{ name: 'bridgeAddress', type: 'address' },
|
||||||
|
{ name: 'bridgeData', type: 'bytes' },
|
||||||
|
]);
|
||||||
|
return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeBridgeData(opts: BridgeDataOpts): string {
|
||||||
|
const encoder = AbiEncoder.create([
|
||||||
|
{ name: 'transferAmount', type: 'int256' },
|
||||||
|
{ name: 'revertData', type: 'bytes' },
|
||||||
|
{ name: 'returnData', type: 'bytes' },
|
||||||
|
]);
|
||||||
|
const revertErrorBytes =
|
||||||
|
opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x';
|
||||||
|
return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> {
|
||||||
|
await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, new BigNumber(balance));
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('transferFrom()', () => {
|
||||||
|
interface TransferFromOpts {
|
||||||
|
assetData: AssetDataOpts;
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
amount: Numberish;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
|
||||||
|
const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber;
|
||||||
|
return _.merge(
|
||||||
|
{
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
transferAmount,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
from: randomAddress(),
|
||||||
|
to: randomAddress(),
|
||||||
|
amount: transferAmount,
|
||||||
|
},
|
||||||
|
opts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> {
|
||||||
|
const _opts = createTransferFromOpts(opts);
|
||||||
|
const { logs } = await assetProxy.transferFrom.awaitTransactionSuccessAsync(
|
||||||
|
encodeAssetData(_opts.assetData),
|
||||||
|
_opts.from,
|
||||||
|
_opts.to,
|
||||||
|
new BigNumber(_opts.amount),
|
||||||
|
{ from: caller },
|
||||||
|
);
|
||||||
|
return (logs as any) as DecodedLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
it('succeeds if the bridge succeeds and balance increases by `amount`', async () => {
|
||||||
|
const tx = transferFromAsync();
|
||||||
|
return expect(tx).to.be.fulfilled('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('succeeds if balance increases more than `amount`', async () => {
|
||||||
|
const amount = getRandomInteger(1, 100e18);
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
amount,
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
transferAmount: amount.plus(1),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return expect(tx).to.be.fulfilled('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes the correct arguments to the bridge contract', async () => {
|
||||||
|
const opts = createTransferFromOpts();
|
||||||
|
const logs = await transferFromAsync(opts);
|
||||||
|
expect(logs.length).to.eq(1);
|
||||||
|
const args = logs[0].args as TestERC20BridgeBridgeWithdrawToEventArgs;
|
||||||
|
expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
|
||||||
|
expect(args.from).to.eq(opts.from);
|
||||||
|
expect(args.to).to.eq(opts.to);
|
||||||
|
expect(args.amount).to.bignumber.eq(opts.amount);
|
||||||
|
expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if not called by an authorized address', async () => {
|
||||||
|
const tx = transferFromAsync({}, badCaller);
|
||||||
|
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if asset data is truncated', async () => {
|
||||||
|
const opts = createTransferFromOpts();
|
||||||
|
const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1);
|
||||||
|
const tx = assetProxy.transferFrom.awaitTransactionSuccessAsync(
|
||||||
|
truncatedAssetData,
|
||||||
|
opts.from,
|
||||||
|
opts.to,
|
||||||
|
new BigNumber(opts.amount),
|
||||||
|
);
|
||||||
|
return expect(tx).to.be.rejected();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if bridge returns nothing', async () => {
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
returnData: '0x',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
// This will actually revert when the AP tries to decode the return
|
||||||
|
// value.
|
||||||
|
return expect(tx).to.be.rejected();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if bridge returns true', async () => {
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
returnData: hexLeftPad('0x1'),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
// This will actually revert when the AP tries to decode the return
|
||||||
|
// value.
|
||||||
|
return expect(tx).to.be.rejected();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if bridge returns 0x1', async () => {
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
returnData: hexRightPad('0x1'),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return expect(tx).to.revertWith('BRIDGE_FAILED');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if bridge is an EOA', async () => {
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeAddress: randomAddress(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
// This will actually revert when the AP tries to decode the return
|
||||||
|
// value.
|
||||||
|
return expect(tx).to.be.rejected();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if bridge reverts', async () => {
|
||||||
|
const revertError = 'FOOBAR';
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
revertError,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return expect(tx).to.revertWith(revertError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if balance of `to` increases by less than `amount`', async () => {
|
||||||
|
const amount = getRandomInteger(1, 100e18);
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
amount,
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
transferAmount: amount.minus(1),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if balance of `to` decreases', async () => {
|
||||||
|
const toAddress = randomAddress();
|
||||||
|
await setTestTokenBalanceAsync(toAddress, 1e18);
|
||||||
|
const tx = transferFromAsync({
|
||||||
|
to: toAddress,
|
||||||
|
assetData: createAssetData({
|
||||||
|
bridgeData: createBridgeData({
|
||||||
|
transferAmount: -1,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('balanceOf()', () => {
|
||||||
|
it('retrieves the balance of the encoded token', async () => {
|
||||||
|
const _owner = randomAddress();
|
||||||
|
const balance = getRandomInteger(1, 100e18);
|
||||||
|
await bridgeContract.setTestTokenBalance.awaitTransactionSuccessAsync(_owner, balance);
|
||||||
|
const assetData = createAssetData({
|
||||||
|
tokenAddress: testTokenAddress,
|
||||||
|
});
|
||||||
|
const actualBalance = await assetProxy.balanceOf.callAsync(encodeAssetData(assetData), _owner);
|
||||||
|
expect(actualBalance).to.bignumber.eq(balance);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getProxyId()', () => {
|
||||||
|
it('returns the correct proxy ID', async () => {
|
||||||
|
const proxyId = await assetProxy.getProxyId.callAsync();
|
||||||
|
expect(proxyId).to.eq(PROXY_ID);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
192
contracts/asset-proxy/test/eth2dai_bridge.ts
Normal file
192
contracts/asset-proxy/test/eth2dai_bridge.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import {
|
||||||
|
blockchainTests,
|
||||||
|
constants,
|
||||||
|
expect,
|
||||||
|
filterLogsToArguments,
|
||||||
|
getRandomInteger,
|
||||||
|
hexLeftPad,
|
||||||
|
hexRandom,
|
||||||
|
Numberish,
|
||||||
|
randomAddress,
|
||||||
|
TransactionHelper,
|
||||||
|
} from '@0x/contracts-test-utils';
|
||||||
|
import { AssetProxyId } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { DecodedLogs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import {
|
||||||
|
artifacts,
|
||||||
|
TestEth2DaiBridgeContract,
|
||||||
|
TestEth2DaiBridgeEvents,
|
||||||
|
TestEth2DaiBridgeSellAllAmountEventArgs,
|
||||||
|
TestEth2DaiBridgeTokenApproveEventArgs,
|
||||||
|
TestEth2DaiBridgeTokenTransferEventArgs,
|
||||||
|
} from '../src';
|
||||||
|
|
||||||
|
blockchainTests.resets('Eth2DaiBridge unit tests', env => {
|
||||||
|
const txHelper = new TransactionHelper(env.web3Wrapper, artifacts);
|
||||||
|
let testContract: TestEth2DaiBridgeContract;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestEth2DaiBridge,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isValidSignature()', () => {
|
||||||
|
it('returns success bytes', async () => {
|
||||||
|
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
|
||||||
|
const result = await testContract.isValidSignature.callAsync(hexRandom(), hexRandom(_.random(0, 32)));
|
||||||
|
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('withdrawTo()', () => {
|
||||||
|
interface WithdrawToOpts {
|
||||||
|
toTokenAddress?: string;
|
||||||
|
fromTokenAddress?: string;
|
||||||
|
toAddress: string;
|
||||||
|
amount: Numberish;
|
||||||
|
fromTokenBalance: Numberish;
|
||||||
|
revertReason: string;
|
||||||
|
fillAmount: Numberish;
|
||||||
|
toTokentransferRevertReason: string;
|
||||||
|
toTokenTransferReturnData: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WithdrawToResult {
|
||||||
|
opts: WithdrawToOpts;
|
||||||
|
result: string;
|
||||||
|
logs: DecodedLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts {
|
||||||
|
return {
|
||||||
|
toAddress: randomAddress(),
|
||||||
|
amount: getRandomInteger(1, 100e18),
|
||||||
|
revertReason: '',
|
||||||
|
fillAmount: getRandomInteger(1, 100e18),
|
||||||
|
fromTokenBalance: getRandomInteger(1, 100e18),
|
||||||
|
toTokentransferRevertReason: '',
|
||||||
|
toTokenTransferReturnData: hexLeftPad(1),
|
||||||
|
...opts,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
|
||||||
|
const _opts = createWithdrawToOpts(opts);
|
||||||
|
// Set the fill behavior.
|
||||||
|
await testContract.setFillBehavior.awaitTransactionSuccessAsync(
|
||||||
|
_opts.revertReason,
|
||||||
|
new BigNumber(_opts.fillAmount),
|
||||||
|
);
|
||||||
|
// Create tokens and balances.
|
||||||
|
if (_opts.fromTokenAddress === undefined) {
|
||||||
|
[_opts.fromTokenAddress] = await txHelper.getResultAndReceiptAsync(
|
||||||
|
testContract.createToken,
|
||||||
|
new BigNumber(_opts.fromTokenBalance),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (_opts.toTokenAddress === undefined) {
|
||||||
|
[_opts.toTokenAddress] = await txHelper.getResultAndReceiptAsync(
|
||||||
|
testContract.createToken,
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Set the transfer behavior of `toTokenAddress`.
|
||||||
|
await testContract.setTransferBehavior.awaitTransactionSuccessAsync(
|
||||||
|
_opts.toTokenAddress,
|
||||||
|
_opts.toTokentransferRevertReason,
|
||||||
|
_opts.toTokenTransferReturnData,
|
||||||
|
);
|
||||||
|
// Call withdrawTo().
|
||||||
|
const [result, { logs }] = await txHelper.getResultAndReceiptAsync(
|
||||||
|
testContract.withdrawTo,
|
||||||
|
// "to" token address
|
||||||
|
_opts.toTokenAddress,
|
||||||
|
// Random from address.
|
||||||
|
randomAddress(),
|
||||||
|
// To address.
|
||||||
|
_opts.toAddress,
|
||||||
|
new BigNumber(_opts.amount),
|
||||||
|
// ABI-encode the "from" token address as the bridge data.
|
||||||
|
hexLeftPad(_opts.fromTokenAddress as string),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
opts: _opts,
|
||||||
|
result,
|
||||||
|
logs: (logs as any) as DecodedLogs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it('returns magic bytes on success', async () => {
|
||||||
|
const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
|
||||||
|
const { result } = await withdrawToAsync();
|
||||||
|
expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls `Eth2Dai.sellAllAmount()`', async () => {
|
||||||
|
const { opts, logs } = await withdrawToAsync();
|
||||||
|
const transfers = filterLogsToArguments<TestEth2DaiBridgeSellAllAmountEventArgs>(
|
||||||
|
logs,
|
||||||
|
TestEth2DaiBridgeEvents.SellAllAmount,
|
||||||
|
);
|
||||||
|
expect(transfers.length).to.eq(1);
|
||||||
|
expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress);
|
||||||
|
expect(transfers[0].buyToken).to.eq(opts.toTokenAddress);
|
||||||
|
expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance);
|
||||||
|
expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets an unlimited allowance on the `fromTokenAddress` token', async () => {
|
||||||
|
const { opts, logs } = await withdrawToAsync();
|
||||||
|
const approvals = filterLogsToArguments<TestEth2DaiBridgeTokenApproveEventArgs>(
|
||||||
|
logs,
|
||||||
|
TestEth2DaiBridgeEvents.TokenApprove,
|
||||||
|
);
|
||||||
|
expect(approvals.length).to.eq(1);
|
||||||
|
expect(approvals[0].token).to.eq(opts.fromTokenAddress);
|
||||||
|
expect(approvals[0].spender).to.eq(testContract.address);
|
||||||
|
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('transfers filled amount to `to`', async () => {
|
||||||
|
const { opts, logs } = await withdrawToAsync();
|
||||||
|
const transfers = filterLogsToArguments<TestEth2DaiBridgeTokenTransferEventArgs>(
|
||||||
|
logs,
|
||||||
|
TestEth2DaiBridgeEvents.TokenTransfer,
|
||||||
|
);
|
||||||
|
expect(transfers.length).to.eq(1);
|
||||||
|
expect(transfers[0].token).to.eq(opts.toTokenAddress);
|
||||||
|
expect(transfers[0].from).to.eq(testContract.address);
|
||||||
|
expect(transfers[0].to).to.eq(opts.toAddress);
|
||||||
|
expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => {
|
||||||
|
const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' });
|
||||||
|
const tx = withdrawToAsync(opts);
|
||||||
|
return expect(tx).to.revertWith(opts.revertReason);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if `toTokenAddress.transfer()` reverts', async () => {
|
||||||
|
const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' });
|
||||||
|
const tx = withdrawToAsync(opts);
|
||||||
|
return expect(tx).to.revertWith(opts.toTokentransferRevertReason);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails if `toTokenAddress.transfer()` returns falsey', async () => {
|
||||||
|
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) });
|
||||||
|
const tx = withdrawToAsync(opts);
|
||||||
|
return expect(tx).to.revertWith('ERC20_TRANSFER_FAILED');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('succeeds if `toTokenAddress.transfer()` returns truthy', async () => {
|
||||||
|
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(100) });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -4,17 +4,24 @@
|
|||||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
"files": [
|
"files": [
|
||||||
"generated-artifacts/ERC1155Proxy.json",
|
"generated-artifacts/ERC1155Proxy.json",
|
||||||
|
"generated-artifacts/ERC20BridgeProxy.json",
|
||||||
"generated-artifacts/ERC20Proxy.json",
|
"generated-artifacts/ERC20Proxy.json",
|
||||||
"generated-artifacts/ERC721Proxy.json",
|
"generated-artifacts/ERC721Proxy.json",
|
||||||
|
"generated-artifacts/Eth2DaiBridge.json",
|
||||||
"generated-artifacts/IAssetData.json",
|
"generated-artifacts/IAssetData.json",
|
||||||
"generated-artifacts/IAssetProxy.json",
|
"generated-artifacts/IAssetProxy.json",
|
||||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||||
"generated-artifacts/IAuthorizable.json",
|
"generated-artifacts/IAuthorizable.json",
|
||||||
|
"generated-artifacts/IERC20Bridge.json",
|
||||||
|
"generated-artifacts/IEth2Dai.json",
|
||||||
|
"generated-artifacts/IWallet.json",
|
||||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||||
"generated-artifacts/MixinAuthorizable.json",
|
"generated-artifacts/MixinAuthorizable.json",
|
||||||
"generated-artifacts/MultiAssetProxy.json",
|
"generated-artifacts/MultiAssetProxy.json",
|
||||||
"generated-artifacts/Ownable.json",
|
"generated-artifacts/Ownable.json",
|
||||||
"generated-artifacts/StaticCallProxy.json",
|
"generated-artifacts/StaticCallProxy.json",
|
||||||
|
"generated-artifacts/TestERC20Bridge.json",
|
||||||
|
"generated-artifacts/TestEth2DaiBridge.json",
|
||||||
"generated-artifacts/TestStaticCallTarget.json"
|
"generated-artifacts/TestStaticCallTarget.json"
|
||||||
],
|
],
|
||||||
"exclude": ["./deploy/solc/solc_bin"]
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "3.0.0",
|
"version": "2.1.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Add chainId to domain separator",
|
"note": "Add chainId to domain separator",
|
||||||
@ -42,7 +42,8 @@
|
|||||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
||||||
"pr": 2055
|
"pr": 2055
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Add chainId to domain separator (#1742)
|
||||||
|
* Inherit Exchange domain constants from `exchange-libs` to reduce code duplication (#1742)
|
||||||
|
* Update domain separator (#1742)
|
||||||
|
* Refactor contract to use new ITransactions interface (#1753)
|
||||||
|
* Add verifyingContractIfExists arg to LibEIP712CoordinatorDomain constructor (#1753)
|
||||||
|
* Remove LibZeroExTransaction contract (#1753)
|
||||||
|
* Update tests for arbitrary fee tokens (ZEIP-28). (#1819)
|
||||||
|
* Update for new `marketXOrders` consolidation. (#2042)
|
||||||
|
* Use built in selectors instead of hard coded constants (#2055)
|
||||||
|
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||||
|
|
||||||
## v2.0.13 - _September 17, 2019_
|
## v2.0.13 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-coordinator",
|
"name": "@0x/contracts-coordinator",
|
||||||
"version": "2.0.13",
|
"version": "2.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,11 +48,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -71,18 +71,18 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-exchange": "^2.1.14",
|
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "0.1.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Use built in selectors instead of hard coded constants",
|
"note": "Use built in selectors instead of hard coded constants",
|
||||||
@ -18,7 +18,8 @@
|
|||||||
"note": "`run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable.",
|
"note": "`run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable.",
|
||||||
"pr": 2075
|
"pr": 2075
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,13 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v0.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Use built in selectors instead of hard coded constants (#2055)
|
||||||
|
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||||
|
* Add `marketBuy/SellOrdersNoThrow` and `marketBuy/SellOrdersFillOrKill` to `LibTransactionDecoder`. (#2075)
|
||||||
|
* `run_mocha` package script runs with `UNLIMITED_CONTRACT_SIZE=true` environment variable. (#2075)
|
||||||
|
|
||||||
## v0.0.10 - _September 17, 2019_
|
## v0.0.10 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
@ -53,3 +60,5 @@ CHANGELOG
|
|||||||
* Refactor `LibAssetData` balance/allowance checks to never revert (#1848)
|
* Refactor `LibAssetData` balance/allowance checks to never revert (#1848)
|
||||||
* Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848)
|
* Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848)
|
||||||
* Add support for StaticCallProxy (#1863)
|
* Add support for StaticCallProxy (#1863)
|
||||||
|
* Add `OrderTransferSimulationUtils` contract for simulating order transfers on-chain (#1868)
|
||||||
|
* Updated to use the new rich error pattern from @0x/contracts-exchange (#1913)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-dev-utils",
|
"name": "@0x/contracts-dev-utils",
|
||||||
"version": "0.0.10",
|
"version": "0.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -49,11 +49,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -72,20 +72,20 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc1155": "^1.1.15",
|
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc721": "^2.1.15",
|
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange": "^2.1.14",
|
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1"
|
"ethereumjs-util": "^5.1.1"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -94,7 +94,7 @@ describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => {
|
|||||||
txDefaults,
|
txDefaults,
|
||||||
artifacts,
|
artifacts,
|
||||||
);
|
);
|
||||||
const exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
const exchangeWrapper = new ExchangeWrapper(exchange);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "1.1.16",
|
"version": "1.2.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.",
|
"note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.",
|
||||||
"pr": 1819
|
"pr": 1819
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.2.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819)
|
||||||
|
|
||||||
## v1.1.15 - _September 17, 2019_
|
## v1.1.15 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc1155",
|
"name": "@0x/contracts-erc1155",
|
||||||
"version": "1.1.15",
|
"version": "1.2.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,10 +48,10 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -70,14 +70,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.3.0-beta.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "2.2.14",
|
"version": "2.2.14",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.3.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v2.2.14 - _September 17, 2019_
|
## v2.2.14 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc20",
|
"name": "@0x/contracts-erc20",
|
||||||
"version": "2.2.14",
|
"version": "2.3.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -47,11 +47,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -69,13 +69,13 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "2.2.0-beta.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "2.1.15",
|
"version": "2.1.15",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.2.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v2.1.15 - _September 17, 2019_
|
## v2.1.15 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc721",
|
"name": "@0x/contracts-erc721",
|
||||||
"version": "2.1.15",
|
"version": "2.2.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,11 +48,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -71,13 +71,13 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.1.0-beta.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "3.0.12",
|
"version": "3.0.12",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v3.0.12 - _September 17, 2019_
|
## v3.0.12 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -27,10 +27,12 @@ import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
|||||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
import "./libs/LibConstants.sol";
|
import "./libs/LibConstants.sol";
|
||||||
import "./libs/LibForwarderRichErrors.sol";
|
import "./libs/LibForwarderRichErrors.sol";
|
||||||
|
import "./MixinAssets.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinExchangeWrapper is
|
contract MixinExchangeWrapper is
|
||||||
LibConstants
|
LibConstants,
|
||||||
|
MixinAssets
|
||||||
{
|
{
|
||||||
using LibSafeMath for uint256;
|
using LibSafeMath for uint256;
|
||||||
|
|
||||||
@ -57,25 +59,12 @@ contract MixinExchangeWrapper is
|
|||||||
);
|
);
|
||||||
|
|
||||||
address exchange = address(EXCHANGE);
|
address exchange = address(EXCHANGE);
|
||||||
|
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||||
// Call `fillOrder` and handle any exceptions gracefully
|
if (didSucceed) {
|
||||||
assembly {
|
assert(returnData.length == 160);
|
||||||
let success := call(
|
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||||
gas, // forward all gas
|
|
||||||
exchange, // call address of Exchange contract
|
|
||||||
0, // transfer 0 wei
|
|
||||||
add(fillOrderCalldata, 32), // pointer to start of input (skip array length in first 32 bytes)
|
|
||||||
mload(fillOrderCalldata), // length of input
|
|
||||||
fillOrderCalldata, // write output over input
|
|
||||||
128 // output size is 128 bytes
|
|
||||||
)
|
|
||||||
if success {
|
|
||||||
mstore(fillResults, mload(fillOrderCalldata))
|
|
||||||
mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32)))
|
|
||||||
mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64)))
|
|
||||||
mstore(add(fillResults, 96), mload(add(fillOrderCalldata, 96)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fillResults values will be 0 by default if call was unsuccessful
|
// fillResults values will be 0 by default if call was unsuccessful
|
||||||
return fillResults;
|
return fillResults;
|
||||||
}
|
}
|
||||||
@ -98,7 +87,7 @@ contract MixinExchangeWrapper is
|
|||||||
uint256 makerAssetAcquiredAmount
|
uint256 makerAssetAcquiredAmount
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// No fee or percentage fee
|
// No taker fee or percentage fee
|
||||||
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.makerAssetData)) {
|
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.makerAssetData)) {
|
||||||
// Attempt to sell the remaining amount of WETH
|
// Attempt to sell the remaining amount of WETH
|
||||||
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
||||||
@ -107,16 +96,17 @@ contract MixinExchangeWrapper is
|
|||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
|
||||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount;
|
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||||
|
.safeAdd(singleFillResults.protocolFeePaid);
|
||||||
|
|
||||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount.safeSub(
|
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||||
singleFillResults.takerFeePaid
|
.safeSub(singleFillResults.takerFeePaid);
|
||||||
);
|
|
||||||
// WETH fee
|
// WETH fee
|
||||||
} else if (order.takerFeeAssetData.equals(order.takerAssetData)) {
|
} else if (order.takerFeeAssetData.equals(order.takerAssetData)) {
|
||||||
|
|
||||||
// We will first sell WETH as the takerAsset, then use it to pay the takerFee.
|
// We will first sell WETH as the takerAsset, then use it to pay the takerFee.
|
||||||
// This ensures that we reserve enough to pay the fee.
|
// This ensures that we reserve enough to pay the taker and protocol fees.
|
||||||
uint256 takerAssetFillAmount = LibMath.getPartialAmountCeil(
|
uint256 takerAssetFillAmount = LibMath.getPartialAmountCeil(
|
||||||
order.takerAssetAmount,
|
order.takerAssetAmount,
|
||||||
order.takerAssetAmount.safeAdd(order.takerFee),
|
order.takerAssetAmount.safeAdd(order.takerFee),
|
||||||
@ -130,9 +120,9 @@ contract MixinExchangeWrapper is
|
|||||||
);
|
);
|
||||||
|
|
||||||
// WETH is also spent on the taker fee, so we add it here.
|
// WETH is also spent on the taker fee, so we add it here.
|
||||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount.safeAdd(
|
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||||
singleFillResults.takerFeePaid
|
.safeAdd(singleFillResults.takerFeePaid)
|
||||||
);
|
.safeAdd(singleFillResults.protocolFeePaid);
|
||||||
|
|
||||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||||
// Unsupported fee
|
// Unsupported fee
|
||||||
@ -161,22 +151,18 @@ contract MixinExchangeWrapper is
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
uint256 ordersLength = orders.length;
|
uint256 ordersLength = orders.length;
|
||||||
|
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
|
||||||
|
|
||||||
for (uint256 i = 0; i != ordersLength; i++) {
|
for (uint256 i = 0; i != ordersLength; i++) {
|
||||||
if (!orders[i].makerAssetData.equals(orders[0].makerAssetData)) {
|
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.MakerAssetMismatchError(
|
|
||||||
orders[0].makerAssetData,
|
|
||||||
orders[i].makerAssetData
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
||||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The remaining amount of WETH to sell
|
// The remaining amount of WETH to sell
|
||||||
uint256 remainingTakerAssetFillAmount = wethSellAmount.safeSub(totalWethSpentAmount);
|
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||||
|
.safeSub(totalWethSpentAmount)
|
||||||
|
.safeSub(protocolFee);
|
||||||
|
|
||||||
(
|
(
|
||||||
uint256 wethSpentAmount,
|
uint256 wethSpentAmount,
|
||||||
@ -187,8 +173,12 @@ contract MixinExchangeWrapper is
|
|||||||
remainingTakerAssetFillAmount
|
remainingTakerAssetFillAmount
|
||||||
);
|
);
|
||||||
|
|
||||||
totalWethSpentAmount = totalWethSpentAmount.safeAdd(wethSpentAmount);
|
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount.safeAdd(makerAssetAcquiredAmount);
|
|
||||||
|
totalWethSpentAmount = totalWethSpentAmount
|
||||||
|
.safeAdd(wethSpentAmount);
|
||||||
|
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||||
|
.safeAdd(makerAssetAcquiredAmount);
|
||||||
|
|
||||||
// Stop execution if the entire amount of WETH has been sold
|
// Stop execution if the entire amount of WETH has been sold
|
||||||
if (totalWethSpentAmount >= wethSellAmount) {
|
if (totalWethSpentAmount >= wethSellAmount) {
|
||||||
@ -215,7 +205,7 @@ contract MixinExchangeWrapper is
|
|||||||
uint256 makerAssetAcquiredAmount
|
uint256 makerAssetAcquiredAmount
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// No fee or WETH fee
|
// No taker fee or WETH fee
|
||||||
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.takerAssetData)) {
|
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.takerAssetData)) {
|
||||||
// Calculate the remaining amount of takerAsset to sell
|
// Calculate the remaining amount of takerAsset to sell
|
||||||
uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil(
|
uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil(
|
||||||
@ -231,10 +221,10 @@ contract MixinExchangeWrapper is
|
|||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
|
||||||
// WETH is also spent on the taker fee, so we add it here.
|
// WETH is also spent on the protocol and taker fees, so we add it here.
|
||||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount.safeAdd(
|
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||||
singleFillResults.takerFeePaid
|
.safeAdd(singleFillResults.takerFeePaid)
|
||||||
);
|
.safeAdd(singleFillResults.protocolFeePaid);
|
||||||
|
|
||||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||||
// Percentage fee
|
// Percentage fee
|
||||||
@ -253,12 +243,12 @@ contract MixinExchangeWrapper is
|
|||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
|
||||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount;
|
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||||
|
.safeAdd(singleFillResults.protocolFeePaid);
|
||||||
|
|
||||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount.safeSub(
|
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||||
singleFillResults.takerFeePaid
|
.safeSub(singleFillResults.takerFeePaid);
|
||||||
);
|
|
||||||
// Unsupported fee
|
// Unsupported fee
|
||||||
} else {
|
} else {
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
|
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
|
||||||
@ -289,19 +279,13 @@ contract MixinExchangeWrapper is
|
|||||||
{
|
{
|
||||||
uint256 ordersLength = orders.length;
|
uint256 ordersLength = orders.length;
|
||||||
for (uint256 i = 0; i != ordersLength; i++) {
|
for (uint256 i = 0; i != ordersLength; i++) {
|
||||||
if (!orders[i].makerAssetData.equals(orders[0].makerAssetData)) {
|
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.MakerAssetMismatchError(
|
|
||||||
orders[0].makerAssetData,
|
|
||||||
orders[i].makerAssetData
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preemptively skip to avoid division by zero in _marketBuySingleOrder
|
// Preemptively skip to avoid division by zero in _marketBuySingleOrder
|
||||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 remainingMakerAssetFillAmount = makerAssetBuyAmount.safeSub(totalMakerAssetAcquiredAmount);
|
uint256 remainingMakerAssetFillAmount = makerAssetBuyAmount
|
||||||
|
.safeSub(totalMakerAssetAcquiredAmount);
|
||||||
|
|
||||||
(
|
(
|
||||||
uint256 wethSpentAmount,
|
uint256 wethSpentAmount,
|
||||||
@ -312,8 +296,12 @@ contract MixinExchangeWrapper is
|
|||||||
remainingMakerAssetFillAmount
|
remainingMakerAssetFillAmount
|
||||||
);
|
);
|
||||||
|
|
||||||
totalWethSpentAmount = totalWethSpentAmount.safeAdd(wethSpentAmount);
|
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount.safeAdd(makerAssetAcquiredAmount);
|
|
||||||
|
totalWethSpentAmount = totalWethSpentAmount
|
||||||
|
.safeAdd(wethSpentAmount);
|
||||||
|
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||||
|
.safeAdd(makerAssetAcquiredAmount);
|
||||||
|
|
||||||
// Stop execution if the entire amount of makerAsset has been bought
|
// Stop execution if the entire amount of makerAsset has been bought
|
||||||
if (totalMakerAssetAcquiredAmount >= makerAssetBuyAmount) {
|
if (totalMakerAssetAcquiredAmount >= makerAssetBuyAmount) {
|
||||||
|
@ -28,7 +28,6 @@ import "./libs/LibConstants.sol";
|
|||||||
import "./libs/LibForwarderRichErrors.sol";
|
import "./libs/LibForwarderRichErrors.sol";
|
||||||
import "./interfaces/IAssets.sol";
|
import "./interfaces/IAssets.sol";
|
||||||
import "./interfaces/IForwarderCore.sol";
|
import "./interfaces/IForwarderCore.sol";
|
||||||
import "./MixinAssets.sol";
|
|
||||||
import "./MixinExchangeWrapper.sol";
|
import "./MixinExchangeWrapper.sol";
|
||||||
import "./MixinWeth.sol";
|
import "./MixinWeth.sol";
|
||||||
|
|
||||||
@ -38,7 +37,6 @@ contract MixinForwarderCore is
|
|||||||
IAssets,
|
IAssets,
|
||||||
IForwarderCore,
|
IForwarderCore,
|
||||||
MixinWeth,
|
MixinWeth,
|
||||||
MixinAssets,
|
|
||||||
MixinExchangeWrapper
|
MixinExchangeWrapper
|
||||||
{
|
{
|
||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
@ -53,6 +51,11 @@ contract MixinForwarderCore is
|
|||||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||||
}
|
}
|
||||||
ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
|
ETHER_TOKEN.approve(proxyAddress, MAX_UINT);
|
||||||
|
|
||||||
|
address protocolFeeCollector = EXCHANGE.protocolFeeCollector();
|
||||||
|
if (protocolFeeCollector != address(0)) {
|
||||||
|
ETHER_TOKEN.approve(protocolFeeCollector, MAX_UINT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
||||||
@ -88,7 +91,8 @@ contract MixinForwarderCore is
|
|||||||
msg.value
|
msg.value
|
||||||
);
|
);
|
||||||
|
|
||||||
// Spends up to wethSellAmount to fill orders and pay WETH order fees.
|
// Spends up to wethSellAmount to fill orders, transfers purchased assets to msg.sender,
|
||||||
|
// and pays WETH order fees.
|
||||||
(
|
(
|
||||||
wethSpentAmount,
|
wethSpentAmount,
|
||||||
makerAssetAcquiredAmount
|
makerAssetAcquiredAmount
|
||||||
@ -105,12 +109,6 @@ contract MixinForwarderCore is
|
|||||||
feePercentage,
|
feePercentage,
|
||||||
feeRecipient
|
feeRecipient
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transfer purchased assets to msg.sender.
|
|
||||||
_transferAssetToSender(
|
|
||||||
orders[0].makerAssetData,
|
|
||||||
makerAssetAcquiredAmount
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||||
@ -143,9 +141,7 @@ contract MixinForwarderCore is
|
|||||||
// Convert ETH to WETH.
|
// Convert ETH to WETH.
|
||||||
_convertEthToWeth();
|
_convertEthToWeth();
|
||||||
|
|
||||||
// Attempt to fill the desired amount of makerAsset. Note that makerAssetAcquiredAmount < makerAssetBuyAmount
|
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||||
// if any of the orders filled have an takerFee denominated in makerAsset, since these fees will be paid out
|
|
||||||
// from the Forwarder's temporary makerAsset balance.
|
|
||||||
(
|
(
|
||||||
wethSpentAmount,
|
wethSpentAmount,
|
||||||
makerAssetAcquiredAmount
|
makerAssetAcquiredAmount
|
||||||
@ -162,11 +158,5 @@ contract MixinForwarderCore is
|
|||||||
feePercentage,
|
feePercentage,
|
||||||
feeRecipient
|
feeRecipient
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transfer acquired assets to msg.sender.
|
|
||||||
_transferAssetToSender(
|
|
||||||
orders[0].makerAssetData,
|
|
||||||
makerAssetAcquiredAmount
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,19 +47,19 @@ contract MixinWeth is
|
|||||||
internal
|
internal
|
||||||
{
|
{
|
||||||
if (msg.value == 0) {
|
if (msg.value == 0) {
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.MsgValueCantEqualZeroError());
|
LibRichErrors.rrevert(LibForwarderRichErrors.MsgValueCannotEqualZeroError());
|
||||||
}
|
}
|
||||||
ETHER_TOKEN.deposit.value(msg.value)();
|
ETHER_TOKEN.deposit.value(msg.value)();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
|
/// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
|
||||||
/// Refunds any excess ETH to msg.sender.
|
/// Refunds any excess ETH to msg.sender.
|
||||||
/// @param wethSold Amount of WETH sold when filling primary orders.
|
/// @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 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 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.
|
/// @return ethFee Amount paid to feeRecipient as a percentage fee on the total WETH sold.
|
||||||
function _transferEthFeeAndRefund(
|
function _transferEthFeeAndRefund(
|
||||||
uint256 wethSold,
|
uint256 wethSpent,
|
||||||
uint256 feePercentage,
|
uint256 feePercentage,
|
||||||
address payable feeRecipient
|
address payable feeRecipient
|
||||||
)
|
)
|
||||||
@ -73,22 +73,22 @@ contract MixinWeth is
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that no extra WETH owned by this contract has been sold.
|
// Ensure that no extra WETH owned by this contract has been spent.
|
||||||
if (wethSold > msg.value) {
|
if (wethSpent > msg.value) {
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.OversoldWethError(
|
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||||
wethSold,
|
wethSpent,
|
||||||
msg.value
|
msg.value
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate amount of WETH that hasn't been sold.
|
// Calculate amount of WETH that hasn't been spent.
|
||||||
uint256 wethRemaining = msg.value.safeSub(wethSold);
|
uint256 wethRemaining = msg.value.safeSub(wethSpent);
|
||||||
|
|
||||||
// Calculate ETH fee to pay to feeRecipient.
|
// Calculate ETH fee to pay to feeRecipient.
|
||||||
ethFee = LibMath.getPartialAmountFloor(
|
ethFee = LibMath.getPartialAmountFloor(
|
||||||
feePercentage,
|
feePercentage,
|
||||||
PERCENTAGE_DENOMINATOR,
|
PERCENTAGE_DENOMINATOR,
|
||||||
wethSold
|
wethSpent
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure fee is less than amount of WETH remaining.
|
// Ensure fee is less than amount of WETH remaining.
|
||||||
|
@ -21,7 +21,6 @@ pragma solidity ^0.5.9;
|
|||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract LibConstants {
|
contract LibConstants {
|
||||||
|
@ -35,10 +35,6 @@ library LibForwarderRichErrors {
|
|||||||
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
||||||
0x91353a0c;
|
0x91353a0c;
|
||||||
|
|
||||||
// bytes4(keccak256("MakerAssetMismatchError(bytes,bytes)"))
|
|
||||||
bytes4 internal constant MAKER_ASSET_MISMATCH_ERROR_SELECTOR =
|
|
||||||
0x56677f2c;
|
|
||||||
|
|
||||||
// bytes4(keccak256("UnsupportedFeeError(bytes)"))
|
// bytes4(keccak256("UnsupportedFeeError(bytes)"))
|
||||||
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
||||||
0x31360af1;
|
0x31360af1;
|
||||||
@ -51,9 +47,9 @@ library LibForwarderRichErrors {
|
|||||||
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
||||||
0xecf40fd9;
|
0xecf40fd9;
|
||||||
|
|
||||||
// bytes4(keccak256("OversoldWethError(uint256,uint256)"))
|
// bytes4(keccak256("OverspentWethError(uint256,uint256)"))
|
||||||
bytes4 internal constant OVERSOLD_WETH_ERROR_SELECTOR =
|
bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR =
|
||||||
0x5cc555c8;
|
0xcdcbed5d;
|
||||||
|
|
||||||
// bytes4(keccak256("TransferFailedError(bytes)"))
|
// bytes4(keccak256("TransferFailedError(bytes)"))
|
||||||
bytes4 internal constant TRANSFER_FAILED_ERROR_SELECTOR =
|
bytes4 internal constant TRANSFER_FAILED_ERROR_SELECTOR =
|
||||||
@ -63,9 +59,9 @@ library LibForwarderRichErrors {
|
|||||||
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
|
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
|
||||||
0x08b18698;
|
0x08b18698;
|
||||||
|
|
||||||
// bytes4(keccak256("MsgValueCantEqualZeroError()"))
|
// bytes4(keccak256("MsgValueCannotEqualZeroError()"))
|
||||||
bytes4 internal constant MSG_VALUE_CANT_EQUAL_ZERO_ERROR_SELECTOR =
|
bytes4 internal constant MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR =
|
||||||
0x1213e1d6;
|
0x8c0e562b;
|
||||||
|
|
||||||
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
|
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
|
||||||
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||||
@ -108,21 +104,6 @@ library LibForwarderRichErrors {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MakerAssetMismatchError(
|
|
||||||
bytes memory firstOrderMakerAssetData,
|
|
||||||
bytes memory mismatchedMakerAssetData
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
MAKER_ASSET_MISMATCH_ERROR_SELECTOR,
|
|
||||||
firstOrderMakerAssetData,
|
|
||||||
mismatchedMakerAssetData
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function UnsupportedFeeError(
|
function UnsupportedFeeError(
|
||||||
bytes memory takerFeeAssetData
|
bytes memory takerFeeAssetData
|
||||||
)
|
)
|
||||||
@ -164,8 +145,8 @@ library LibForwarderRichErrors {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function OversoldWethError(
|
function OverspentWethError(
|
||||||
uint256 wethSold,
|
uint256 wethSpent,
|
||||||
uint256 msgValue
|
uint256 msgValue
|
||||||
)
|
)
|
||||||
internal
|
internal
|
||||||
@ -173,8 +154,8 @@ library LibForwarderRichErrors {
|
|||||||
returns (bytes memory)
|
returns (bytes memory)
|
||||||
{
|
{
|
||||||
return abi.encodeWithSelector(
|
return abi.encodeWithSelector(
|
||||||
OVERSOLD_WETH_ERROR_SELECTOR,
|
OVERSPENT_WETH_ERROR_SELECTOR,
|
||||||
wethSold,
|
wethSpent,
|
||||||
msgValue
|
msgValue
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -205,12 +186,12 @@ library LibForwarderRichErrors {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MsgValueCantEqualZeroError()
|
function MsgValueCannotEqualZeroError()
|
||||||
internal
|
internal
|
||||||
pure
|
pure
|
||||||
returns (bytes memory)
|
returns (bytes memory)
|
||||||
{
|
{
|
||||||
return abi.encodeWithSelector(MSG_VALUE_CANT_EQUAL_ZERO_ERROR_SELECTOR);
|
return abi.encodeWithSelector(MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Erc721AmountMustEqualOneError(
|
function Erc721AmountMustEqualOneError(
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable no-unused-vars
|
||||||
|
contract TestProtocolFeeCollector {
|
||||||
|
|
||||||
|
address private _wethAddress;
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
address wethAddress
|
||||||
|
)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
_wethAddress = wethAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Pays a protocol fee in WETH (Forwarder orders will always pay protocol fees in WETH).
|
||||||
|
/// @param makerAddress The address of the order's maker.
|
||||||
|
/// @param payerAddress The address of the protocol fee payer.
|
||||||
|
/// @param protocolFeePaid The protocol fee that should be paid.
|
||||||
|
function payProtocolFee(
|
||||||
|
address makerAddress,
|
||||||
|
address payerAddress,
|
||||||
|
uint256 protocolFeePaid
|
||||||
|
)
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
{
|
||||||
|
assert(msg.value == 0);
|
||||||
|
|
||||||
|
// Transfer the protocol fee to this address in WETH.
|
||||||
|
IEtherToken(_wethAddress).transferFrom(
|
||||||
|
payerAddress,
|
||||||
|
address(this),
|
||||||
|
protocolFeePaid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-exchange-forwarder",
|
"name": "@0x/contracts-exchange-forwarder",
|
||||||
"version": "3.0.12",
|
"version": "3.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn pre_build && tsc -b",
|
"build": "yarn pre_build && tsc -b",
|
||||||
|
"build:ts": "tsc -b",
|
||||||
"build:ci": "yarn build",
|
"build:ci": "yarn build",
|
||||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers",
|
"pre_build": "run-s compile contracts:gen generate_contract_wrappers",
|
||||||
"test": "yarn run_mocha",
|
"test": "yarn run_mocha",
|
||||||
@ -34,7 +35,7 @@
|
|||||||
"compile:truffle": "truffle compile"
|
"compile:truffle": "truffle compile"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"abis": "./generated-artifacts/@(Forwarder|IAssets|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinWeth).json",
|
"abis": "./generated-artifacts/@(Forwarder|IAssets|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinWeth|TestProtocolFeeCollector).json",
|
||||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -47,11 +48,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -70,19 +71,19 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc721": "^2.1.15",
|
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange": "^2.1.14",
|
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -15,6 +15,7 @@ import * as MixinAssets from '../generated-artifacts/MixinAssets.json';
|
|||||||
import * as MixinExchangeWrapper from '../generated-artifacts/MixinExchangeWrapper.json';
|
import * as MixinExchangeWrapper from '../generated-artifacts/MixinExchangeWrapper.json';
|
||||||
import * as MixinForwarderCore from '../generated-artifacts/MixinForwarderCore.json';
|
import * as MixinForwarderCore from '../generated-artifacts/MixinForwarderCore.json';
|
||||||
import * as MixinWeth from '../generated-artifacts/MixinWeth.json';
|
import * as MixinWeth from '../generated-artifacts/MixinWeth.json';
|
||||||
|
import * as TestProtocolFeeCollector from '../generated-artifacts/TestProtocolFeeCollector.json';
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
Forwarder: Forwarder as ContractArtifact,
|
Forwarder: Forwarder as ContractArtifact,
|
||||||
MixinAssets: MixinAssets as ContractArtifact,
|
MixinAssets: MixinAssets as ContractArtifact,
|
||||||
@ -26,4 +27,5 @@ export const artifacts = {
|
|||||||
IForwarderCore: IForwarderCore as ContractArtifact,
|
IForwarderCore: IForwarderCore as ContractArtifact,
|
||||||
LibConstants: LibConstants as ContractArtifact,
|
LibConstants: LibConstants as ContractArtifact,
|
||||||
LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact,
|
LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact,
|
||||||
|
TestProtocolFeeCollector: TestProtocolFeeCollector as ContractArtifact,
|
||||||
};
|
};
|
||||||
|
@ -13,3 +13,4 @@ export * from '../generated-wrappers/mixin_assets';
|
|||||||
export * from '../generated-wrappers/mixin_exchange_wrapper';
|
export * from '../generated-wrappers/mixin_exchange_wrapper';
|
||||||
export * from '../generated-wrappers/mixin_forwarder_core';
|
export * from '../generated-wrappers/mixin_forwarder_core';
|
||||||
export * from '../generated-wrappers/mixin_weth';
|
export * from '../generated-wrappers/mixin_weth';
|
||||||
|
export * from '../generated-wrappers/test_protocol_fee_collector';
|
||||||
|
@ -14,21 +14,24 @@ import {
|
|||||||
import { assetDataUtils, ForwarderRevertErrors } from '@0x/order-utils';
|
import { assetDataUtils, ForwarderRevertErrors } from '@0x/order-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
|
||||||
|
|
||||||
import { artifacts, ForwarderContract, ForwarderTestFactory, ForwarderWrapper } from '../src';
|
import {
|
||||||
|
artifacts,
|
||||||
|
ForwarderContract,
|
||||||
|
ForwarderTestFactory,
|
||||||
|
ForwarderWrapper,
|
||||||
|
TestProtocolFeeCollectorContract,
|
||||||
|
} from '../src';
|
||||||
|
|
||||||
const DECIMALS_DEFAULT = 18;
|
const DECIMALS_DEFAULT = 18;
|
||||||
|
|
||||||
blockchainTests(ContractName.Forwarder, env => {
|
blockchainTests(ContractName.Forwarder, env => {
|
||||||
let chainId: number;
|
|
||||||
let makerAddress: string;
|
|
||||||
let owner: string;
|
let owner: string;
|
||||||
|
let makerAddress: string;
|
||||||
let takerAddress: string;
|
let takerAddress: string;
|
||||||
let orderFeeRecipientAddress: string;
|
let orderFeeRecipientAddress: string;
|
||||||
let forwarderFeeRecipientAddress: string;
|
let forwarderFeeRecipientAddress: string;
|
||||||
let defaultMakerAssetAddress: string;
|
let defaultMakerAssetAddress: string;
|
||||||
let wethAssetData: string;
|
|
||||||
|
|
||||||
let weth: DummyERC20TokenContract;
|
let weth: DummyERC20TokenContract;
|
||||||
let erc20Token: DummyERC20TokenContract;
|
let erc20Token: DummyERC20TokenContract;
|
||||||
@ -36,22 +39,26 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
let erc721Token: DummyERC721TokenContract;
|
let erc721Token: DummyERC721TokenContract;
|
||||||
let forwarderContract: ForwarderContract;
|
let forwarderContract: ForwarderContract;
|
||||||
let wethContract: WETH9Contract;
|
let wethContract: WETH9Contract;
|
||||||
|
let exchangeContract: ExchangeContract;
|
||||||
|
let protocolFeeCollector: TestProtocolFeeCollectorContract;
|
||||||
|
|
||||||
let forwarderWrapper: ForwarderWrapper;
|
let forwarderWrapper: ForwarderWrapper;
|
||||||
let exchangeWrapper: ExchangeWrapper;
|
let exchangeWrapper: ExchangeWrapper;
|
||||||
|
let erc20Wrapper: ERC20Wrapper;
|
||||||
|
|
||||||
let orderFactory: OrderFactory;
|
let orderFactory: OrderFactory;
|
||||||
let forwarderTestFactory: ForwarderTestFactory;
|
let forwarderTestFactory: ForwarderTestFactory;
|
||||||
let erc20Wrapper: ERC20Wrapper;
|
|
||||||
let tx: TransactionReceiptWithDecodedLogs;
|
|
||||||
|
|
||||||
|
let chainId: number;
|
||||||
|
let wethAssetData: string;
|
||||||
let erc721MakerAssetIds: BigNumber[];
|
let erc721MakerAssetIds: BigNumber[];
|
||||||
const gasPrice = new BigNumber(constants.DEFAULT_GAS_PRICE);
|
|
||||||
|
const GAS_PRICE = new BigNumber(env.txDefaults.gasPrice || constants.DEFAULT_GAS_PRICE);
|
||||||
|
const PROTOCOL_FEE_MULTIPLIER = new BigNumber(150);
|
||||||
|
const PROTOCOL_FEE = GAS_PRICE.times(PROTOCOL_FEE_MULTIPLIER);
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await env.blockchainLifecycle.startAsync();
|
// Set up addresses
|
||||||
|
|
||||||
chainId = await env.getChainIdAsync();
|
|
||||||
|
|
||||||
const accounts = await env.getAccountAddressesAsync();
|
const accounts = await env.getAccountAddressesAsync();
|
||||||
const usedAddresses = ([
|
const usedAddresses = ([
|
||||||
owner,
|
owner,
|
||||||
@ -61,24 +68,27 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
forwarderFeeRecipientAddress,
|
forwarderFeeRecipientAddress,
|
||||||
] = accounts);
|
] = accounts);
|
||||||
|
|
||||||
const erc721Wrapper = new ERC721Wrapper(env.provider, usedAddresses, owner);
|
// Set up Exchange
|
||||||
erc20Wrapper = new ERC20Wrapper(env.provider, usedAddresses, owner);
|
chainId = await env.getChainIdAsync();
|
||||||
|
exchangeContract = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
const numDummyErc20ToDeploy = 2;
|
exchangeArtifacts.Exchange,
|
||||||
[erc20Token, secondErc20Token] = await erc20Wrapper.deployDummyTokensAsync(
|
env.provider,
|
||||||
numDummyErc20ToDeploy,
|
env.txDefaults,
|
||||||
constants.DUMMY_TOKEN_DECIMALS,
|
{},
|
||||||
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
|
exchangeWrapper = new ExchangeWrapper(exchangeContract);
|
||||||
|
|
||||||
|
// Set up ERC20
|
||||||
|
erc20Wrapper = new ERC20Wrapper(env.provider, usedAddresses, owner);
|
||||||
|
[erc20Token, secondErc20Token] = await erc20Wrapper.deployDummyTokensAsync(2, constants.DUMMY_TOKEN_DECIMALS);
|
||||||
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
|
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
|
||||||
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
from: owner,
|
||||||
const erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
});
|
||||||
await erc721Wrapper.setBalancesAndAllowancesAsync();
|
|
||||||
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
|
||||||
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
|
||||||
|
|
||||||
|
// Set up WETH
|
||||||
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(
|
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(
|
||||||
erc20Artifacts.WETH9,
|
erc20Artifacts.WETH9,
|
||||||
env.provider,
|
env.provider,
|
||||||
@ -86,59 +96,72 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
weth = new DummyERC20TokenContract(wethContract.address, env.provider);
|
weth = new DummyERC20TokenContract(wethContract.address, env.provider);
|
||||||
erc20Wrapper.addDummyTokenContract(weth);
|
|
||||||
|
|
||||||
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
||||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
erc20Wrapper.addDummyTokenContract(weth);
|
||||||
exchangeArtifacts.Exchange,
|
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||||
|
|
||||||
|
// Set up ERC721
|
||||||
|
const erc721Wrapper = new ERC721Wrapper(env.provider, usedAddresses, owner);
|
||||||
|
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
|
||||||
|
const erc721Proxy = await erc721Wrapper.deployProxyAsync();
|
||||||
|
await erc721Wrapper.setBalancesAndAllowancesAsync();
|
||||||
|
const erc721Balances = await erc721Wrapper.getBalancesAsync();
|
||||||
|
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
|
||||||
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
|
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
|
||||||
|
from: owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up Protocol Fee Collector
|
||||||
|
protocolFeeCollector = await TestProtocolFeeCollectorContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestProtocolFeeCollector,
|
||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
{},
|
{},
|
||||||
new BigNumber(chainId),
|
wethContract.address,
|
||||||
);
|
);
|
||||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance, env.provider);
|
await exchangeContract.setProtocolFeeMultiplier.awaitTransactionSuccessAsync(PROTOCOL_FEE_MULTIPLIER);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeContract.setProtocolFeeCollectorAddress.awaitTransactionSuccessAsync(
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
protocolFeeCollector.address,
|
||||||
|
);
|
||||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
erc20Wrapper.addTokenOwnerAddress(protocolFeeCollector.address);
|
||||||
from: owner,
|
|
||||||
});
|
|
||||||
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
|
||||||
from: owner,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Set defaults
|
||||||
defaultMakerAssetAddress = erc20Token.address;
|
defaultMakerAssetAddress = erc20Token.address;
|
||||||
const defaultTakerAssetAddress = wethContract.address;
|
const defaultTakerAssetAddress = wethContract.address;
|
||||||
const defaultOrderParams = {
|
const defaultOrderParams = {
|
||||||
makerAddress,
|
makerAddress,
|
||||||
feeRecipientAddress: orderFeeRecipientAddress,
|
feeRecipientAddress: orderFeeRecipientAddress,
|
||||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
|
||||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
|
||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(200, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(200, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, DECIMALS_DEFAULT),
|
||||||
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
|
||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
|
||||||
makerFee: Web3Wrapper.toBaseUnitAmount(0, DECIMALS_DEFAULT),
|
makerFee: Web3Wrapper.toBaseUnitAmount(0, DECIMALS_DEFAULT),
|
||||||
takerFee: Web3Wrapper.toBaseUnitAmount(0, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(0, DECIMALS_DEFAULT),
|
||||||
exchangeAddress: exchangeInstance.address,
|
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||||
|
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
|
exchangeAddress: exchangeContract.address,
|
||||||
chainId,
|
chainId,
|
||||||
};
|
};
|
||||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
|
||||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
|
||||||
|
|
||||||
|
// Set up Forwarder
|
||||||
forwarderContract = await ForwarderContract.deployFrom0xArtifactAsync(
|
forwarderContract = await ForwarderContract.deployFrom0xArtifactAsync(
|
||||||
artifacts.Forwarder,
|
artifacts.Forwarder,
|
||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
{},
|
{},
|
||||||
exchangeInstance.address,
|
exchangeContract.address,
|
||||||
wethAssetData,
|
wethAssetData,
|
||||||
);
|
);
|
||||||
forwarderWrapper = new ForwarderWrapper(forwarderContract, env.provider);
|
forwarderWrapper = new ForwarderWrapper(forwarderContract, env.provider);
|
||||||
|
await forwarderWrapper.approveMakerAssetProxyAsync(defaultOrderParams.makerAssetData, {
|
||||||
await forwarderWrapper.approveMakerAssetProxyAsync(defaultOrderParams.makerAssetData, { from: takerAddress });
|
from: takerAddress,
|
||||||
|
});
|
||||||
erc20Wrapper.addTokenOwnerAddress(forwarderContract.address);
|
erc20Wrapper.addTokenOwnerAddress(forwarderContract.address);
|
||||||
|
|
||||||
|
// Set up factories
|
||||||
|
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||||
|
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||||
forwarderTestFactory = new ForwarderTestFactory(
|
forwarderTestFactory = new ForwarderTestFactory(
|
||||||
exchangeWrapper,
|
exchangeWrapper,
|
||||||
forwarderWrapper,
|
forwarderWrapper,
|
||||||
@ -146,16 +169,18 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
forwarderContract.address,
|
forwarderContract.address,
|
||||||
makerAddress,
|
makerAddress,
|
||||||
takerAddress,
|
takerAddress,
|
||||||
|
protocolFeeCollector.address,
|
||||||
orderFeeRecipientAddress,
|
orderFeeRecipientAddress,
|
||||||
forwarderFeeRecipientAddress,
|
forwarderFeeRecipientAddress,
|
||||||
weth.address,
|
weth.address,
|
||||||
gasPrice,
|
GAS_PRICE,
|
||||||
|
PROTOCOL_FEE_MULTIPLIER,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
blockchainTests.resets('constructor', () => {
|
blockchainTests.resets('constructor', () => {
|
||||||
it('should revert if assetProxy is unregistered', async () => {
|
it('should revert if assetProxy is unregistered', async () => {
|
||||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
exchangeArtifacts.Exchange,
|
exchangeArtifacts.Exchange,
|
||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
@ -168,7 +193,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
env.provider,
|
env.provider,
|
||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
{},
|
{},
|
||||||
exchangeInstance.address,
|
exchange.address,
|
||||||
wethAssetData,
|
wethAssetData,
|
||||||
) as any) as sendTransactionResult;
|
) as any) as sendTransactionResult;
|
||||||
|
|
||||||
@ -178,7 +203,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
blockchainTests.resets('marketSellOrdersWithEth without extra fees', () => {
|
blockchainTests.resets('marketSellOrdersWithEth without extra fees', () => {
|
||||||
it('should fill a single order without a taker fee', async () => {
|
it('should fill a single order without a taker fee', async () => {
|
||||||
const orderWithoutFee = await orderFactory.newSignedOrderAsync();
|
const orderWithoutFee = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([orderWithoutFee], 0.78, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([orderWithoutFee], 0.78, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill multiple orders without taker fees', async () => {
|
it('should fill multiple orders without taker fees', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync();
|
const firstOrder = await orderFactory.newSignedOrderAsync();
|
||||||
@ -187,14 +212,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(21, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(21, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.51, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.51, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill a single order with a percentage fee', async () => {
|
it('should fill a single order with a percentage fee', async () => {
|
||||||
const orderWithPercentageFee = await orderFactory.newSignedOrderAsync({
|
const orderWithPercentageFee = await orderFactory.newSignedOrderAsync({
|
||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketSellTestAsync([orderWithPercentageFee], 0.58, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([orderWithPercentageFee], 0.58, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill multiple orders with percentage fees', async () => {
|
it('should fill multiple orders with percentage fees', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -208,7 +233,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.34, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.34, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fail to fill an order with a percentage fee if the asset proxy is not yet approved', async () => {
|
it('should fail to fill an order with a percentage fee if the asset proxy is not yet approved', async () => {
|
||||||
const unapprovedAsset = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
const unapprovedAsset = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||||
@ -223,7 +248,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||||
|
|
||||||
// Execute test case
|
// Execute test case
|
||||||
tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
const tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
||||||
value: ethValue,
|
value: ethValue,
|
||||||
from: takerAddress,
|
from: takerAddress,
|
||||||
});
|
});
|
||||||
@ -231,7 +256,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||||
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
||||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
const totalEthSpent = gasPrice.times(tx.gasUsed);
|
const totalEthSpent = GAS_PRICE.times(tx.gasUsed);
|
||||||
|
|
||||||
// Validate test case
|
// Validate test case
|
||||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||||
@ -255,7 +280,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketSellTestAsync([orderWithWethFee], 0.13, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([orderWithWethFee], 0.13, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should fill multiple orders with WETH fees', async () => {
|
it('should fill multiple orders with WETH fees', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -269,23 +294,23 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrderWithWethFee];
|
const orders = [firstOrder, secondOrderWithWethFee];
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.25, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.25, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => {
|
it('should refund remaining ETH if amount is greater than takerAssetAmount', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
const ethValue = order.takerAssetAmount.plus(2);
|
const ethValue = order.takerAssetAmount.plus(PROTOCOL_FEE).plus(2);
|
||||||
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||||
|
|
||||||
tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
const tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
||||||
value: ethValue,
|
value: ethValue,
|
||||||
from: takerAddress,
|
from: takerAddress,
|
||||||
});
|
});
|
||||||
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||||
const totalEthSpent = order.takerAssetAmount.plus(gasPrice.times(tx.gasUsed));
|
const totalEthSpent = order.takerAssetAmount.plus(PROTOCOL_FEE).plus(GAS_PRICE.times(tx.gasUsed));
|
||||||
|
|
||||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||||
});
|
});
|
||||||
it('should fail to fill orders with mismatched makerAssetData', async () => {
|
it('should fill orders with different makerAssetData', async () => {
|
||||||
const firstOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
const firstOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
makerAssetData: firstOrderMakerAssetData,
|
makerAssetData: firstOrderMakerAssetData,
|
||||||
@ -295,16 +320,10 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const secondOrder = await orderFactory.newSignedOrderAsync({
|
const secondOrder = await orderFactory.newSignedOrderAsync({
|
||||||
makerAssetData: secondOrderMakerAssetData,
|
makerAssetData: secondOrderMakerAssetData,
|
||||||
});
|
});
|
||||||
|
await forwarderWrapper.approveMakerAssetProxyAsync(secondOrderMakerAssetData, { from: takerAddress });
|
||||||
|
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
|
await forwarderTestFactory.marketSellTestAsync(orders, 1.5, [erc20Token, secondErc20Token]);
|
||||||
const revertError = new ForwarderRevertErrors.MakerAssetMismatchError(
|
|
||||||
firstOrderMakerAssetData,
|
|
||||||
secondOrderMakerAssetData,
|
|
||||||
);
|
|
||||||
await forwarderTestFactory.marketSellTestAsync(orders, 2, erc20Token, {
|
|
||||||
revertError,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => {
|
it('should fail to fill an order with a fee denominated in an asset other than makerAsset or WETH', async () => {
|
||||||
const makerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
const makerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
@ -317,14 +336,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketSellTestAsync([order], 0.5, [erc20Token], {
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should fill a partially-filled order without a taker fee', async () => {
|
it('should fill a partially-filled order without a taker fee', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.3, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([order], 0.3, [erc20Token]);
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.8, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([order], 0.8, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid maker asset amount', async () => {
|
it('should skip over an order with an invalid maker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -332,7 +351,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid taker asset amount', async () => {
|
it('should skip over an order with an invalid taker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -340,7 +359,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an expired order', async () => {
|
it('should skip over an expired order', async () => {
|
||||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||||
@ -349,21 +368,21 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([expiredOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a fully filled order', async () => {
|
it('should skip over a fully filled order', async () => {
|
||||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder], 1, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder], 1, [erc20Token]);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a cancelled order', async () => {
|
it('should skip over a cancelled order', async () => {
|
||||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketSellTestAsync([cancelledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
blockchainTests.resets('marketSellOrdersWithEth with extra fees', () => {
|
blockchainTests.resets('marketSellOrdersWithEth with extra fees', () => {
|
||||||
@ -372,7 +391,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(157, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(157, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(36, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(36, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.67, erc20Token, {
|
await forwarderTestFactory.marketSellTestAsync([order], 0.67, [erc20Token], {
|
||||||
forwarderFeePercentage: new BigNumber(2),
|
forwarderFeePercentage: new BigNumber(2),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -383,7 +402,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
|
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
|
||||||
);
|
);
|
||||||
|
|
||||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketSellTestAsync([order], 0.5, [erc20Token], {
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
@ -395,7 +414,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(131, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(131, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(20, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(20, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.62, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.62, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should buy the exact amount of makerAsset in multiple orders', async () => {
|
it('should buy the exact amount of makerAsset in multiple orders', async () => {
|
||||||
const firstOrder = await orderFactory.newSignedOrderAsync();
|
const firstOrder = await orderFactory.newSignedOrderAsync();
|
||||||
@ -404,14 +423,29 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
const orders = [firstOrder, secondOrder];
|
const orders = [firstOrder, secondOrder];
|
||||||
await forwarderTestFactory.marketBuyTestAsync(orders, 1.96, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync(orders, 1.96, [erc20Token]);
|
||||||
|
});
|
||||||
|
it('should buy exactly makerAssetBuyAmount in orders with different makerAssetData', async () => {
|
||||||
|
const firstOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
|
||||||
|
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: firstOrderMakerAssetData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const secondOrderMakerAssetData = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||||
|
const secondOrder = await orderFactory.newSignedOrderAsync({
|
||||||
|
makerAssetData: secondOrderMakerAssetData,
|
||||||
|
});
|
||||||
|
await forwarderWrapper.approveMakerAssetProxyAsync(secondOrderMakerAssetData, { from: takerAddress });
|
||||||
|
|
||||||
|
const orders = [firstOrder, secondOrder];
|
||||||
|
await forwarderTestFactory.marketBuyTestAsync(orders, 1.5, [erc20Token, secondErc20Token]);
|
||||||
});
|
});
|
||||||
it('should buy the exact amount of makerAsset and return excess ETH', async () => {
|
it('should buy the exact amount of makerAsset and return excess ETH', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync({
|
const order = await orderFactory.newSignedOrderAsync({
|
||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(80, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(80, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.57, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.57, [erc20Token], {
|
||||||
ethValueAdjustment: 2,
|
ethValueAdjustment: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -422,7 +456,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.38, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.38, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should buy the exact amount of makerAsset from a single order with a percentage fee', async () => {
|
it('should buy the exact amount of makerAsset from a single order with a percentage fee', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync({
|
const order = await orderFactory.newSignedOrderAsync({
|
||||||
@ -431,7 +465,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.52, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.52, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
|
it('should revert if the amount of ETH sent is too low to fill the makerAssetAmount', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
@ -440,7 +474,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
constants.ZERO_AMOUNT,
|
constants.ZERO_AMOUNT,
|
||||||
);
|
);
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
ethValueAdjustment: -2,
|
ethValueAdjustment: -2,
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
@ -452,7 +486,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([erc721Order], 1, erc721Token, {
|
await forwarderTestFactory.marketBuyTestAsync([erc721Order], 1, [erc721Token], {
|
||||||
makerAssetId,
|
makerAssetId,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -464,7 +498,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||||
takerFeeAssetData: wethAssetData,
|
takerFeeAssetData: wethAssetData,
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], 1, erc721Token, {
|
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], 1, [erc721Token], {
|
||||||
makerAssetId,
|
makerAssetId,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -479,14 +513,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should fill a partially-filled order without a taker fee', async () => {
|
it('should fill a partially-filled order without a taker fee', async () => {
|
||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.3, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.3, [erc20Token]);
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.8, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.8, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid maker asset amount', async () => {
|
it('should skip over an order with an invalid maker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -494,7 +528,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an order with an invalid taker asset amount', async () => {
|
it('should skip over an order with an invalid taker asset amount', async () => {
|
||||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||||
@ -502,7 +536,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([unfillableOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over an expired order', async () => {
|
it('should skip over an expired order', async () => {
|
||||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||||
@ -511,23 +545,23 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
|
|
||||||
await forwarderTestFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([expiredOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a fully filled order', async () => {
|
it('should skip over a fully filled order', async () => {
|
||||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder], 1, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder], 1, [erc20Token]);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('should skip over a cancelled order', async () => {
|
it('should skip over a cancelled order', async () => {
|
||||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||||
|
|
||||||
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
const fillableOrder = await orderFactory.newSignedOrderAsync();
|
||||||
await forwarderTestFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5, erc20Token);
|
await forwarderTestFactory.marketBuyTestAsync([cancelledOrder, fillableOrder], 1.5, [erc20Token]);
|
||||||
});
|
});
|
||||||
it('Should buy slightly greater MakerAsset when exchange rate is rounded', async () => {
|
it('Should buy slightly greater makerAsset when exchange rate is rounded', async () => {
|
||||||
// The 0x Protocol contracts round the exchange rate in favor of the Maker.
|
// The 0x Protocol contracts round the exchange rate in favor of the Maker.
|
||||||
// In this case, the taker must round up how much they're going to spend, which
|
// In this case, the taker must round up how much they're going to spend, which
|
||||||
// in turn increases the amount of MakerAsset being purchased.
|
// in turn increases the amount of MakerAsset being purchased.
|
||||||
@ -553,13 +587,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
});
|
});
|
||||||
const desiredMakerAssetFillAmount = new BigNumber('5');
|
const desiredMakerAssetFillAmount = new BigNumber('5');
|
||||||
const makerAssetFillAmount = new BigNumber('6');
|
const makerAssetFillAmount = new BigNumber('6');
|
||||||
const ethValue = new BigNumber('4');
|
const primaryTakerAssetFillAmount = new BigNumber('4');
|
||||||
|
const ethValue = primaryTakerAssetFillAmount.plus(PROTOCOL_FEE);
|
||||||
|
|
||||||
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
const erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||||
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||||
|
|
||||||
// Execute test case
|
// Execute test case
|
||||||
tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
const tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
||||||
value: ethValue,
|
value: ethValue,
|
||||||
from: takerAddress,
|
from: takerAddress,
|
||||||
});
|
});
|
||||||
@ -567,8 +602,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||||
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
||||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
const primaryTakerAssetFillAmount = ethValue;
|
const totalEthSpent = ethValue.plus(GAS_PRICE.times(tx.gasUsed));
|
||||||
const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
|
|
||||||
// Validate test case
|
// Validate test case
|
||||||
expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
|
expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
|
||||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||||
@ -588,6 +622,8 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
});
|
});
|
||||||
it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => {
|
it('Should buy slightly greater MakerAsset when exchange rate is rounded (Regression Test)', async () => {
|
||||||
|
// Disable protocol fees for regression test
|
||||||
|
await exchangeContract.setProtocolFeeCollectorAddress.awaitTransactionSuccessAsync(constants.NULL_ADDRESS);
|
||||||
// Order taken from a transaction on mainnet that failed due to a rounding error.
|
// Order taken from a transaction on mainnet that failed due to a rounding error.
|
||||||
const order = await orderFactory.newSignedOrderAsync({
|
const order = await orderFactory.newSignedOrderAsync({
|
||||||
makerAssetAmount: new BigNumber('268166666666666666666'),
|
makerAssetAmount: new BigNumber('268166666666666666666'),
|
||||||
@ -608,7 +644,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
.times(order.makerAssetAmount)
|
.times(order.makerAssetAmount)
|
||||||
.dividedToIntegerBy(order.takerAssetAmount);
|
.dividedToIntegerBy(order.takerAssetAmount);
|
||||||
// Execute test case
|
// Execute test case
|
||||||
tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
const tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
||||||
value: ethValue,
|
value: ethValue,
|
||||||
from: takerAddress,
|
from: takerAddress,
|
||||||
});
|
});
|
||||||
@ -617,7 +653,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
||||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||||
const primaryTakerAssetFillAmount = ethValue;
|
const primaryTakerAssetFillAmount = ethValue;
|
||||||
const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
|
const totalEthSpent = primaryTakerAssetFillAmount.plus(GAS_PRICE.times(tx.gasUsed));
|
||||||
// Validate test case
|
// Validate test case
|
||||||
expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
|
expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
|
||||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||||
@ -643,7 +679,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(125, DECIMALS_DEFAULT),
|
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(125, DECIMALS_DEFAULT),
|
||||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
||||||
});
|
});
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.33, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.33, [erc20Token], {
|
||||||
forwarderFeePercentage: new BigNumber(2),
|
forwarderFeePercentage: new BigNumber(2),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -652,7 +688,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
|
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
|
||||||
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, new BigNumber(6)),
|
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, new BigNumber(6)),
|
||||||
);
|
);
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
forwarderFeePercentage: new BigNumber(6),
|
forwarderFeePercentage: new BigNumber(6),
|
||||||
revertError,
|
revertError,
|
||||||
});
|
});
|
||||||
@ -661,14 +697,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
|||||||
const order = await orderFactory.newSignedOrderAsync();
|
const order = await orderFactory.newSignedOrderAsync();
|
||||||
const forwarderFeePercentage = new BigNumber(2);
|
const forwarderFeePercentage = new BigNumber(2);
|
||||||
const ethFee = ForwarderTestFactory.getPercentageOfValue(
|
const ethFee = ForwarderTestFactory.getPercentageOfValue(
|
||||||
order.takerAssetAmount.times(0.5),
|
order.takerAssetAmount.times(0.5).plus(PROTOCOL_FEE),
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
);
|
);
|
||||||
|
|
||||||
const revertError = new ForwarderRevertErrors.InsufficientEthForFeeError(ethFee, ethFee.minus(1));
|
const revertError = new ForwarderRevertErrors.InsufficientEthForFeeError(ethFee, ethFee.minus(1));
|
||||||
|
|
||||||
// -2 to compensate for the extra 1 wei added in ForwarderTestFactory to account for rounding
|
// -2 to compensate for the extra 1 wei added in ForwarderTestFactory to account for rounding
|
||||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||||
ethValueAdjustment: -2,
|
ethValueAdjustment: -2,
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
revertError,
|
revertError,
|
||||||
|
@ -2,118 +2,36 @@ import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
|||||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||||
import { ExchangeWrapper } from '@0x/contracts-exchange';
|
import { ExchangeWrapper } from '@0x/contracts-exchange';
|
||||||
import { chaiSetup, constants, ERC20BalancesByOwner, OrderStatus, web3Wrapper } from '@0x/contracts-test-utils';
|
import { constants, ERC20BalancesByOwner, expect, OrderStatus, web3Wrapper } from '@0x/contracts-test-utils';
|
||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
import { OrderInfo, SignedOrder } from '@0x/types';
|
import { OrderInfo, SignedOrder } from '@0x/types';
|
||||||
import { BigNumber, RevertError } from '@0x/utils';
|
import { BigNumber, RevertError } from '@0x/utils';
|
||||||
import * as chai from 'chai';
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ForwarderWrapper } from './forwarder_wrapper';
|
import { ForwarderWrapper } from './forwarder_wrapper';
|
||||||
|
|
||||||
chaiSetup.configure();
|
|
||||||
const expect = chai.expect;
|
|
||||||
|
|
||||||
// Necessary bookkeeping to validate Forwarder results
|
// Necessary bookkeeping to validate Forwarder results
|
||||||
interface ForwarderFillState {
|
interface ForwarderFillState {
|
||||||
takerAssetFillAmount: BigNumber;
|
takerAssetFillAmount: BigNumber;
|
||||||
makerAssetFillAmount: BigNumber;
|
makerAssetFillAmount: {
|
||||||
|
[makerAssetData: string]: BigNumber;
|
||||||
|
};
|
||||||
|
protocolFees: BigNumber;
|
||||||
wethFees: BigNumber;
|
wethFees: BigNumber;
|
||||||
percentageFees: BigNumber;
|
percentageFees: {
|
||||||
|
[makerAssetData: string]: BigNumber;
|
||||||
|
};
|
||||||
maxOversoldWeth: BigNumber;
|
maxOversoldWeth: BigNumber;
|
||||||
maxOverboughtMakerAsset: BigNumber;
|
maxOverboughtMakerAsset: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulates filling some orders via the Forwarder contract. For example, if
|
|
||||||
// orders = [A, B, C, D] and fractionalNumberOfOrdersToFill = 2.3, then
|
|
||||||
// we simulate A and B being completely filled, and 0.3 * C being filled.
|
|
||||||
function computeExpectedResults(
|
|
||||||
orders: SignedOrder[],
|
|
||||||
ordersInfoBefore: OrderInfo[],
|
|
||||||
fractionalNumberOfOrdersToFill: number,
|
|
||||||
): ForwarderFillState {
|
|
||||||
const currentState = {
|
|
||||||
takerAssetFillAmount: constants.ZERO_AMOUNT,
|
|
||||||
makerAssetFillAmount: constants.ZERO_AMOUNT,
|
|
||||||
wethFees: constants.ZERO_AMOUNT,
|
|
||||||
percentageFees: constants.ZERO_AMOUNT,
|
|
||||||
maxOversoldWeth: constants.ZERO_AMOUNT,
|
|
||||||
maxOverboughtMakerAsset: constants.ZERO_AMOUNT,
|
|
||||||
};
|
|
||||||
let remainingOrdersToFill = fractionalNumberOfOrdersToFill;
|
|
||||||
|
|
||||||
for (const [i, order] of orders.entries()) {
|
|
||||||
if (remainingOrdersToFill === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ordersInfoBefore[i].orderStatus !== OrderStatus.Fillable) {
|
|
||||||
// If the order is not fillable, skip over it but still count it towards fractionalNumberOfOrdersToFill
|
|
||||||
remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let makerAssetAmount;
|
|
||||||
let takerAssetAmount;
|
|
||||||
let takerFee;
|
|
||||||
if (remainingOrdersToFill < 1) {
|
|
||||||
makerAssetAmount = order.makerAssetAmount.times(remainingOrdersToFill).integerValue();
|
|
||||||
takerAssetAmount = order.takerAssetAmount.times(remainingOrdersToFill).integerValue();
|
|
||||||
takerFee = order.takerFee.times(remainingOrdersToFill).integerValue();
|
|
||||||
|
|
||||||
// Up to 1 wei worth of WETH will be oversold on the last order due to rounding
|
|
||||||
currentState.maxOversoldWeth = new BigNumber(1);
|
|
||||||
// Equivalently, up to 1 wei worth of maker asset will be overbought
|
|
||||||
currentState.maxOverboughtMakerAsset = currentState.maxOversoldWeth
|
|
||||||
.times(order.makerAssetAmount)
|
|
||||||
.dividedToIntegerBy(order.takerAssetAmount);
|
|
||||||
} else {
|
|
||||||
makerAssetAmount = order.makerAssetAmount;
|
|
||||||
takerAssetAmount = order.takerAssetAmount;
|
|
||||||
takerFee = order.takerFee;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accounting for partially filled orders
|
|
||||||
// As with unfillable orders, these still count as 1 towards fractionalNumberOfOrdersToFill
|
|
||||||
const takerAssetFilled = ordersInfoBefore[i].orderTakerAssetFilledAmount;
|
|
||||||
const makerAssetFilled = takerAssetFilled
|
|
||||||
.times(order.makerAssetAmount)
|
|
||||||
.dividedToIntegerBy(order.takerAssetAmount);
|
|
||||||
takerAssetAmount = BigNumber.max(takerAssetAmount.minus(takerAssetFilled), constants.ZERO_AMOUNT);
|
|
||||||
makerAssetAmount = BigNumber.max(makerAssetAmount.minus(makerAssetFilled), constants.ZERO_AMOUNT);
|
|
||||||
|
|
||||||
currentState.takerAssetFillAmount = currentState.takerAssetFillAmount.plus(takerAssetAmount);
|
|
||||||
currentState.makerAssetFillAmount = currentState.makerAssetFillAmount.plus(makerAssetAmount);
|
|
||||||
|
|
||||||
if (order.takerFeeAssetData === order.makerAssetData) {
|
|
||||||
currentState.percentageFees = currentState.percentageFees.plus(takerFee);
|
|
||||||
} else if (order.takerFeeAssetData === order.takerAssetData) {
|
|
||||||
currentState.wethFees = currentState.wethFees.plus(takerFee);
|
|
||||||
}
|
|
||||||
|
|
||||||
remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since bignumber is not compatible with chai's within
|
// Since bignumber is not compatible with chai's within
|
||||||
function expectBalanceWithin(balance: BigNumber, low: BigNumber, high: BigNumber): void {
|
function expectBalanceWithin(balance: BigNumber, low: BigNumber, high: BigNumber, message?: string): void {
|
||||||
expect(balance).to.be.bignumber.gte(low);
|
expect(balance, message).to.be.bignumber.gte(low);
|
||||||
expect(balance).to.be.bignumber.lte(high);
|
expect(balance, message).to.be.bignumber.lte(high);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ForwarderTestFactory {
|
export class ForwarderTestFactory {
|
||||||
private readonly _exchangeWrapper: ExchangeWrapper;
|
|
||||||
private readonly _forwarderWrapper: ForwarderWrapper;
|
|
||||||
private readonly _erc20Wrapper: ERC20Wrapper;
|
|
||||||
private readonly _forwarderAddress: string;
|
|
||||||
private readonly _makerAddress: string;
|
|
||||||
private readonly _takerAddress: string;
|
|
||||||
private readonly _orderFeeRecipientAddress: string;
|
|
||||||
private readonly _forwarderFeeRecipientAddress: string;
|
|
||||||
private readonly _wethAddress: string;
|
|
||||||
private readonly _gasPrice: BigNumber;
|
|
||||||
|
|
||||||
public static getPercentageOfValue(value: BigNumber, percentage: BigNumber): BigNumber {
|
public static getPercentageOfValue(value: BigNumber, percentage: BigNumber): BigNumber {
|
||||||
const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100);
|
const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100);
|
||||||
const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR);
|
const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR);
|
||||||
@ -121,33 +39,24 @@ export class ForwarderTestFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
exchangeWrapper: ExchangeWrapper,
|
private readonly _exchangeWrapper: ExchangeWrapper,
|
||||||
forwarderWrapper: ForwarderWrapper,
|
private readonly _forwarderWrapper: ForwarderWrapper,
|
||||||
erc20Wrapper: ERC20Wrapper,
|
private readonly _erc20Wrapper: ERC20Wrapper,
|
||||||
forwarderAddress: string,
|
private readonly _forwarderAddress: string,
|
||||||
makerAddress: string,
|
private readonly _makerAddress: string,
|
||||||
takerAddress: string,
|
private readonly _takerAddress: string,
|
||||||
orderFeeRecipientAddress: string,
|
private readonly _protocolFeeCollectorAddress: string,
|
||||||
forwarderFeeRecipientAddress: string,
|
private readonly _orderFeeRecipientAddress: string,
|
||||||
wethAddress: string,
|
private readonly _forwarderFeeRecipientAddress: string,
|
||||||
gasPrice: BigNumber,
|
private readonly _wethAddress: string,
|
||||||
) {
|
private readonly _gasPrice: BigNumber,
|
||||||
this._exchangeWrapper = exchangeWrapper;
|
private readonly _protocolFeeMultiplier: BigNumber,
|
||||||
this._forwarderWrapper = forwarderWrapper;
|
) {}
|
||||||
this._erc20Wrapper = erc20Wrapper;
|
|
||||||
this._forwarderAddress = forwarderAddress;
|
|
||||||
this._makerAddress = makerAddress;
|
|
||||||
this._takerAddress = takerAddress;
|
|
||||||
this._orderFeeRecipientAddress = orderFeeRecipientAddress;
|
|
||||||
this._forwarderFeeRecipientAddress = forwarderFeeRecipientAddress;
|
|
||||||
this._wethAddress = wethAddress;
|
|
||||||
this._gasPrice = gasPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async marketBuyTestAsync(
|
public async marketBuyTestAsync(
|
||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
||||||
fractionalNumberOfOrdersToFill: number,
|
fractionalNumberOfOrdersToFill: number,
|
||||||
makerAssetContract: DummyERC20TokenContract | DummyERC721TokenContract,
|
makerAssetContracts: Array<DummyERC20TokenContract | DummyERC721TokenContract>,
|
||||||
options: {
|
options: {
|
||||||
ethValueAdjustment?: number; // Used to provided insufficient/excess ETH
|
ethValueAdjustment?: number; // Used to provided insufficient/excess ETH
|
||||||
forwarderFeePercentage?: BigNumber;
|
forwarderFeePercentage?: BigNumber;
|
||||||
@ -167,25 +76,28 @@ export class ForwarderTestFactory {
|
|||||||
const ordersInfoBefore = await Promise.all(orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)));
|
const ordersInfoBefore = await Promise.all(orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)));
|
||||||
const orderStatusesBefore = ordersInfoBefore.map(orderInfo => orderInfo.orderStatus);
|
const orderStatusesBefore = ordersInfoBefore.map(orderInfo => orderInfo.orderStatus);
|
||||||
|
|
||||||
const expectedResults = computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
const expectedResults = this._computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
||||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
const wethSpent = expectedResults.takerAssetFillAmount
|
||||||
expectedResults.takerAssetFillAmount,
|
.plus(expectedResults.protocolFees)
|
||||||
forwarderFeePercentage,
|
.plus(expectedResults.wethFees)
|
||||||
);
|
.plus(expectedResults.maxOversoldWeth);
|
||||||
|
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(wethSpent, forwarderFeePercentage);
|
||||||
|
const ethValue = wethSpent.plus(ethSpentOnForwarderFee).plus(ethValueAdjustment);
|
||||||
|
|
||||||
const feePercentage = ForwarderTestFactory.getPercentageOfValue(
|
const feePercentage = ForwarderTestFactory.getPercentageOfValue(
|
||||||
constants.PERCENTAGE_DENOMINATOR,
|
constants.PERCENTAGE_DENOMINATOR,
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ethValue = expectedResults.takerAssetFillAmount
|
const totalMakerAssetFillAmount = Object.values(expectedResults.makerAssetFillAmount).reduce((prev, current) =>
|
||||||
.plus(expectedResults.wethFees)
|
prev.plus(current),
|
||||||
.plus(expectedResults.maxOversoldWeth)
|
);
|
||||||
.plus(ethSpentOnForwarderFee)
|
const totalPercentageFees = Object.values(expectedResults.percentageFees).reduce((prev, current) =>
|
||||||
.plus(ethValueAdjustment);
|
prev.plus(current),
|
||||||
|
);
|
||||||
const tx = this._forwarderWrapper.marketBuyOrdersWithEthAsync(
|
const tx = this._forwarderWrapper.marketBuyOrdersWithEthAsync(
|
||||||
orders,
|
orders,
|
||||||
expectedResults.makerAssetFillAmount.minus(expectedResults.percentageFees),
|
totalMakerAssetFillAmount.minus(totalPercentageFees),
|
||||||
{
|
{
|
||||||
value: ethValue,
|
value: ethValue,
|
||||||
from: this._takerAddress,
|
from: this._takerAddress,
|
||||||
@ -210,7 +122,7 @@ export class ForwarderTestFactory {
|
|||||||
expectedResults,
|
expectedResults,
|
||||||
takerEthBalanceBefore,
|
takerEthBalanceBefore,
|
||||||
erc20Balances,
|
erc20Balances,
|
||||||
makerAssetContract,
|
makerAssetContracts,
|
||||||
{
|
{
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
forwarderFeeRecipientEthBalanceBefore,
|
forwarderFeeRecipientEthBalanceBefore,
|
||||||
@ -223,7 +135,7 @@ export class ForwarderTestFactory {
|
|||||||
public async marketSellTestAsync(
|
public async marketSellTestAsync(
|
||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
||||||
fractionalNumberOfOrdersToFill: number,
|
fractionalNumberOfOrdersToFill: number,
|
||||||
makerAssetContract: DummyERC20TokenContract,
|
makerAssetContracts: DummyERC20TokenContract[],
|
||||||
options: {
|
options: {
|
||||||
forwarderFeePercentage?: BigNumber;
|
forwarderFeePercentage?: BigNumber;
|
||||||
revertError?: RevertError;
|
revertError?: RevertError;
|
||||||
@ -240,21 +152,20 @@ export class ForwarderTestFactory {
|
|||||||
const ordersInfoBefore = await Promise.all(orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)));
|
const ordersInfoBefore = await Promise.all(orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)));
|
||||||
const orderStatusesBefore = ordersInfoBefore.map(orderInfo => orderInfo.orderStatus);
|
const orderStatusesBefore = ordersInfoBefore.map(orderInfo => orderInfo.orderStatus);
|
||||||
|
|
||||||
const expectedResults = computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
const expectedResults = this._computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
||||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
const wethSpent = expectedResults.takerAssetFillAmount
|
||||||
expectedResults.takerAssetFillAmount,
|
.plus(expectedResults.protocolFees)
|
||||||
forwarderFeePercentage,
|
.plus(expectedResults.wethFees)
|
||||||
);
|
.plus(expectedResults.maxOversoldWeth);
|
||||||
|
|
||||||
|
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(wethSpent, forwarderFeePercentage);
|
||||||
|
const ethValue = wethSpent.plus(ethSpentOnForwarderFee);
|
||||||
|
|
||||||
const feePercentage = ForwarderTestFactory.getPercentageOfValue(
|
const feePercentage = ForwarderTestFactory.getPercentageOfValue(
|
||||||
constants.PERCENTAGE_DENOMINATOR,
|
constants.PERCENTAGE_DENOMINATOR,
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ethValue = expectedResults.takerAssetFillAmount
|
|
||||||
.plus(expectedResults.wethFees)
|
|
||||||
.plus(expectedResults.maxOversoldWeth)
|
|
||||||
.plus(ethSpentOnForwarderFee);
|
|
||||||
|
|
||||||
const tx = this._forwarderWrapper.marketSellOrdersWithEthAsync(
|
const tx = this._forwarderWrapper.marketSellOrdersWithEthAsync(
|
||||||
orders,
|
orders,
|
||||||
{
|
{
|
||||||
@ -268,10 +179,9 @@ export class ForwarderTestFactory {
|
|||||||
await expect(tx).to.revertWith(options.revertError);
|
await expect(tx).to.revertWith(options.revertError);
|
||||||
} else {
|
} else {
|
||||||
const gasUsed = (await tx).gasUsed;
|
const gasUsed = (await tx).gasUsed;
|
||||||
const ordersInfoAfter = await Promise.all(
|
const orderStatusesAfter = await Promise.all(
|
||||||
orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)),
|
orders.map(async order => (await this._exchangeWrapper.getOrderInfoAsync(order)).orderStatus),
|
||||||
);
|
);
|
||||||
const orderStatusesAfter = ordersInfoAfter.map(orderInfo => orderInfo.orderStatus);
|
|
||||||
|
|
||||||
await this._checkResultsAsync(
|
await this._checkResultsAsync(
|
||||||
fractionalNumberOfOrdersToFill,
|
fractionalNumberOfOrdersToFill,
|
||||||
@ -281,7 +191,7 @@ export class ForwarderTestFactory {
|
|||||||
expectedResults,
|
expectedResults,
|
||||||
takerEthBalanceBefore,
|
takerEthBalanceBefore,
|
||||||
erc20Balances,
|
erc20Balances,
|
||||||
makerAssetContract,
|
makerAssetContracts,
|
||||||
{
|
{
|
||||||
forwarderFeePercentage,
|
forwarderFeePercentage,
|
||||||
forwarderFeeRecipientEthBalanceBefore,
|
forwarderFeeRecipientEthBalanceBefore,
|
||||||
@ -297,27 +207,39 @@ export class ForwarderTestFactory {
|
|||||||
makerAssetContract: DummyERC20TokenContract,
|
makerAssetContract: DummyERC20TokenContract,
|
||||||
): void {
|
): void {
|
||||||
const makerAssetAddress = makerAssetContract.address;
|
const makerAssetAddress = makerAssetContract.address;
|
||||||
|
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerAssetAddress);
|
||||||
|
|
||||||
|
const {
|
||||||
|
maxOverboughtMakerAsset,
|
||||||
|
makerAssetFillAmount: { [makerAssetData]: makerAssetFillAmount },
|
||||||
|
percentageFees: { [makerAssetData]: percentageFees },
|
||||||
|
} = expectedResults;
|
||||||
|
|
||||||
expectBalanceWithin(
|
expectBalanceWithin(
|
||||||
newBalances[this._makerAddress][makerAssetAddress],
|
newBalances[this._makerAddress][makerAssetAddress],
|
||||||
oldBalances[this._makerAddress][makerAssetAddress]
|
oldBalances[this._makerAddress][makerAssetAddress]
|
||||||
.minus(expectedResults.makerAssetFillAmount)
|
.minus(makerAssetFillAmount)
|
||||||
.minus(expectedResults.maxOverboughtMakerAsset),
|
.minus(maxOverboughtMakerAsset),
|
||||||
oldBalances[this._makerAddress][makerAssetAddress].minus(expectedResults.makerAssetFillAmount),
|
oldBalances[this._makerAddress][makerAssetAddress].minus(makerAssetFillAmount),
|
||||||
|
'Maker makerAsset balance',
|
||||||
);
|
);
|
||||||
expectBalanceWithin(
|
expectBalanceWithin(
|
||||||
newBalances[this._takerAddress][makerAssetAddress],
|
newBalances[this._takerAddress][makerAssetAddress],
|
||||||
|
oldBalances[this._takerAddress][makerAssetAddress].plus(makerAssetFillAmount).minus(percentageFees),
|
||||||
oldBalances[this._takerAddress][makerAssetAddress]
|
oldBalances[this._takerAddress][makerAssetAddress]
|
||||||
.plus(expectedResults.makerAssetFillAmount)
|
.plus(makerAssetFillAmount)
|
||||||
.minus(expectedResults.percentageFees),
|
.minus(percentageFees)
|
||||||
oldBalances[this._takerAddress][makerAssetAddress]
|
.plus(maxOverboughtMakerAsset),
|
||||||
.plus(expectedResults.makerAssetFillAmount)
|
'Taker makerAsset balance',
|
||||||
.minus(expectedResults.percentageFees)
|
|
||||||
.plus(expectedResults.maxOverboughtMakerAsset),
|
|
||||||
);
|
);
|
||||||
expect(newBalances[this._orderFeeRecipientAddress][makerAssetAddress]).to.be.bignumber.equal(
|
expect(
|
||||||
oldBalances[this._orderFeeRecipientAddress][makerAssetAddress].plus(expectedResults.percentageFees),
|
newBalances[this._orderFeeRecipientAddress][makerAssetAddress],
|
||||||
);
|
'Order fee recipient makerAsset balance',
|
||||||
expect(newBalances[this._forwarderAddress][makerAssetAddress]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
).to.be.bignumber.equal(oldBalances[this._orderFeeRecipientAddress][makerAssetAddress].plus(percentageFees));
|
||||||
|
expect(
|
||||||
|
newBalances[this._forwarderAddress][makerAssetAddress],
|
||||||
|
'Forwarder contract makerAsset balance',
|
||||||
|
).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _checkResultsAsync(
|
private async _checkResultsAsync(
|
||||||
@ -328,7 +250,7 @@ export class ForwarderTestFactory {
|
|||||||
expectedResults: ForwarderFillState,
|
expectedResults: ForwarderFillState,
|
||||||
takerEthBalanceBefore: BigNumber,
|
takerEthBalanceBefore: BigNumber,
|
||||||
erc20Balances: ERC20BalancesByOwner,
|
erc20Balances: ERC20BalancesByOwner,
|
||||||
makerAssetContract: DummyERC20TokenContract | DummyERC721TokenContract,
|
makerAssetContracts: Array<DummyERC20TokenContract | DummyERC721TokenContract>,
|
||||||
options: {
|
options: {
|
||||||
forwarderFeePercentage?: BigNumber;
|
forwarderFeePercentage?: BigNumber;
|
||||||
forwarderFeeRecipientEthBalanceBefore?: BigNumber;
|
forwarderFeeRecipientEthBalanceBefore?: BigNumber;
|
||||||
@ -340,18 +262,17 @@ export class ForwarderTestFactory {
|
|||||||
if (fractionalNumberOfOrdersToFill >= i + 1 && orderStatusesBefore[i] === OrderStatus.Fillable) {
|
if (fractionalNumberOfOrdersToFill >= i + 1 && orderStatusesBefore[i] === OrderStatus.Fillable) {
|
||||||
expectedOrderStatus = OrderStatus.FullyFilled;
|
expectedOrderStatus = OrderStatus.FullyFilled;
|
||||||
}
|
}
|
||||||
|
expect(orderStatus, ` Order ${i} status`).to.equal(expectedOrderStatus);
|
||||||
expect(orderStatus).to.equal(expectedOrderStatus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wethSpent = expectedResults.takerAssetFillAmount
|
||||||
|
.plus(expectedResults.protocolFees)
|
||||||
|
.plus(expectedResults.wethFees);
|
||||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
||||||
expectedResults.takerAssetFillAmount,
|
wethSpent,
|
||||||
options.forwarderFeePercentage || constants.ZERO_AMOUNT,
|
options.forwarderFeePercentage || constants.ZERO_AMOUNT,
|
||||||
);
|
);
|
||||||
const totalEthSpent = expectedResults.takerAssetFillAmount
|
const totalEthSpent = wethSpent.plus(ethSpentOnForwarderFee).plus(this._gasPrice.times(gasUsed));
|
||||||
.plus(expectedResults.wethFees)
|
|
||||||
.plus(ethSpentOnForwarderFee)
|
|
||||||
.plus(this._gasPrice.times(gasUsed));
|
|
||||||
|
|
||||||
const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(this._takerAddress);
|
const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(this._takerAddress);
|
||||||
const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(this._forwarderAddress);
|
const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(this._forwarderAddress);
|
||||||
@ -361,21 +282,24 @@ export class ForwarderTestFactory {
|
|||||||
takerEthBalanceAfter,
|
takerEthBalanceAfter,
|
||||||
takerEthBalanceBefore.minus(totalEthSpent).minus(expectedResults.maxOversoldWeth),
|
takerEthBalanceBefore.minus(totalEthSpent).minus(expectedResults.maxOversoldWeth),
|
||||||
takerEthBalanceBefore.minus(totalEthSpent),
|
takerEthBalanceBefore.minus(totalEthSpent),
|
||||||
|
'Taker ETH balance',
|
||||||
);
|
);
|
||||||
if (options.forwarderFeeRecipientEthBalanceBefore !== undefined) {
|
if (options.forwarderFeeRecipientEthBalanceBefore !== undefined) {
|
||||||
const fowarderFeeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(
|
const fowarderFeeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(
|
||||||
this._forwarderFeeRecipientAddress,
|
this._forwarderFeeRecipientAddress,
|
||||||
);
|
);
|
||||||
expect(fowarderFeeRecipientEthBalanceAfter).to.be.bignumber.equal(
|
expect(fowarderFeeRecipientEthBalanceAfter, 'Forwarder fee recipient ETH balance').to.be.bignumber.equal(
|
||||||
options.forwarderFeeRecipientEthBalanceBefore.plus(ethSpentOnForwarderFee),
|
options.forwarderFeeRecipientEthBalanceBefore.plus(ethSpentOnForwarderFee),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (makerAssetContract instanceof DummyERC20TokenContract) {
|
for (const makerAssetContract of makerAssetContracts) {
|
||||||
this._checkErc20Balances(erc20Balances, newBalances, expectedResults, makerAssetContract);
|
if (makerAssetContract instanceof DummyERC20TokenContract) {
|
||||||
} else if (options.makerAssetId !== undefined) {
|
this._checkErc20Balances(erc20Balances, newBalances, expectedResults, makerAssetContract);
|
||||||
const newOwner = await makerAssetContract.ownerOf.callAsync(options.makerAssetId);
|
} else if (options.makerAssetId !== undefined) {
|
||||||
expect(newOwner).to.be.bignumber.equal(this._takerAddress);
|
const newOwner = await makerAssetContract.ownerOf.callAsync(options.makerAssetId);
|
||||||
|
expect(newOwner, 'New ERC721 owner').to.be.bignumber.equal(this._takerAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expectBalanceWithin(
|
expectBalanceWithin(
|
||||||
@ -384,12 +308,108 @@ export class ForwarderTestFactory {
|
|||||||
erc20Balances[this._makerAddress][this._wethAddress]
|
erc20Balances[this._makerAddress][this._wethAddress]
|
||||||
.plus(expectedResults.takerAssetFillAmount)
|
.plus(expectedResults.takerAssetFillAmount)
|
||||||
.plus(expectedResults.maxOversoldWeth),
|
.plus(expectedResults.maxOversoldWeth),
|
||||||
|
'Maker WETH balance',
|
||||||
);
|
);
|
||||||
expect(newBalances[this._orderFeeRecipientAddress][this._wethAddress]).to.be.bignumber.equal(
|
expect(
|
||||||
|
newBalances[this._orderFeeRecipientAddress][this._wethAddress],
|
||||||
|
'Order fee recipient WETH balance',
|
||||||
|
).to.be.bignumber.equal(
|
||||||
erc20Balances[this._orderFeeRecipientAddress][this._wethAddress].plus(expectedResults.wethFees),
|
erc20Balances[this._orderFeeRecipientAddress][this._wethAddress].plus(expectedResults.wethFees),
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
expect(newBalances[this._forwarderAddress][this._wethAddress]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
newBalances[this._forwarderAddress][this._wethAddress],
|
||||||
|
'Forwarder contract WETH balance',
|
||||||
|
).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
expect(forwarderEthBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simulates filling some orders via the Forwarder contract. For example, if
|
||||||
|
// orders = [A, B, C, D] and fractionalNumberOfOrdersToFill = 2.3, then
|
||||||
|
// we simulate A and B being completely filled, and 0.3 * C being filled.
|
||||||
|
private _computeExpectedResults(
|
||||||
|
orders: SignedOrder[],
|
||||||
|
ordersInfoBefore: OrderInfo[],
|
||||||
|
fractionalNumberOfOrdersToFill: number,
|
||||||
|
): ForwarderFillState {
|
||||||
|
const currentState: ForwarderFillState = {
|
||||||
|
takerAssetFillAmount: constants.ZERO_AMOUNT,
|
||||||
|
makerAssetFillAmount: {},
|
||||||
|
protocolFees: constants.ZERO_AMOUNT,
|
||||||
|
wethFees: constants.ZERO_AMOUNT,
|
||||||
|
percentageFees: {},
|
||||||
|
maxOversoldWeth: constants.ZERO_AMOUNT,
|
||||||
|
maxOverboughtMakerAsset: constants.ZERO_AMOUNT,
|
||||||
|
};
|
||||||
|
let remainingOrdersToFill = fractionalNumberOfOrdersToFill;
|
||||||
|
|
||||||
|
for (const [i, order] of orders.entries()) {
|
||||||
|
if (currentState.makerAssetFillAmount[order.makerAssetData] === undefined) {
|
||||||
|
currentState.makerAssetFillAmount[order.makerAssetData] = new BigNumber(0);
|
||||||
|
}
|
||||||
|
if (currentState.percentageFees[order.makerAssetData] === undefined) {
|
||||||
|
currentState.percentageFees[order.makerAssetData] = new BigNumber(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingOrdersToFill === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ordersInfoBefore[i].orderStatus !== OrderStatus.Fillable) {
|
||||||
|
// If the order is not fillable, skip over it but still count it towards fractionalNumberOfOrdersToFill
|
||||||
|
remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let makerAssetAmount;
|
||||||
|
let takerAssetAmount;
|
||||||
|
let takerFee;
|
||||||
|
if (remainingOrdersToFill < 1) {
|
||||||
|
makerAssetAmount = order.makerAssetAmount.times(remainingOrdersToFill).integerValue();
|
||||||
|
takerAssetAmount = order.takerAssetAmount.times(remainingOrdersToFill).integerValue();
|
||||||
|
takerFee = order.takerFee.times(remainingOrdersToFill).integerValue();
|
||||||
|
|
||||||
|
// Up to 1 wei worth of WETH will be oversold on the last order due to rounding
|
||||||
|
currentState.maxOversoldWeth = new BigNumber(1);
|
||||||
|
// Equivalently, up to 1 wei worth of maker asset will be overbought
|
||||||
|
currentState.maxOverboughtMakerAsset = currentState.maxOversoldWeth
|
||||||
|
.times(order.makerAssetAmount)
|
||||||
|
.dividedToIntegerBy(order.takerAssetAmount);
|
||||||
|
} else {
|
||||||
|
makerAssetAmount = order.makerAssetAmount;
|
||||||
|
takerAssetAmount = order.takerAssetAmount;
|
||||||
|
takerFee = order.takerFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accounting for partially filled orders
|
||||||
|
// As with unfillable orders, these still count as 1 towards fractionalNumberOfOrdersToFill
|
||||||
|
const takerAssetFilled = ordersInfoBefore[i].orderTakerAssetFilledAmount;
|
||||||
|
const makerAssetFilled = takerAssetFilled
|
||||||
|
.times(order.makerAssetAmount)
|
||||||
|
.dividedToIntegerBy(order.takerAssetAmount);
|
||||||
|
takerAssetAmount = BigNumber.max(takerAssetAmount.minus(takerAssetFilled), constants.ZERO_AMOUNT);
|
||||||
|
makerAssetAmount = BigNumber.max(makerAssetAmount.minus(makerAssetFilled), constants.ZERO_AMOUNT);
|
||||||
|
|
||||||
|
currentState.takerAssetFillAmount = currentState.takerAssetFillAmount.plus(takerAssetAmount);
|
||||||
|
currentState.makerAssetFillAmount[order.makerAssetData] = currentState.makerAssetFillAmount[
|
||||||
|
order.makerAssetData
|
||||||
|
].plus(makerAssetAmount);
|
||||||
|
|
||||||
|
if (this._protocolFeeCollectorAddress !== constants.NULL_ADDRESS) {
|
||||||
|
currentState.protocolFees = currentState.protocolFees.plus(
|
||||||
|
this._gasPrice.times(this._protocolFeeMultiplier),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (order.takerFeeAssetData === order.makerAssetData) {
|
||||||
|
currentState.percentageFees[order.makerAssetData] = currentState.percentageFees[
|
||||||
|
order.makerAssetData
|
||||||
|
].plus(takerFee);
|
||||||
|
} else if (order.takerFeeAssetData === order.takerAssetData) {
|
||||||
|
currentState.wethFees = currentState.wethFees.plus(takerFee);
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingOrdersToFill = Math.max(remainingOrdersToFill - 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
"generated-artifacts/MixinAssets.json",
|
"generated-artifacts/MixinAssets.json",
|
||||||
"generated-artifacts/MixinExchangeWrapper.json",
|
"generated-artifacts/MixinExchangeWrapper.json",
|
||||||
"generated-artifacts/MixinForwarderCore.json",
|
"generated-artifacts/MixinForwarderCore.json",
|
||||||
"generated-artifacts/MixinWeth.json"
|
"generated-artifacts/MixinWeth.json",
|
||||||
|
"generated-artifacts/TestProtocolFeeCollector.json"
|
||||||
],
|
],
|
||||||
"exclude": ["./deploy/solc/solc_bin"]
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "3.1.0",
|
"version": "3.1.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Break up `LibEIP712` into reusable components",
|
"note": "Break up `LibEIP712` into reusable components",
|
||||||
@ -106,7 +106,8 @@
|
|||||||
"note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.",
|
"note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.",
|
||||||
"pr": 2075
|
"pr": 2075
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,35 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Break up `LibEIP712` into reusable components (#1742)
|
||||||
|
* Add `chainId` to EIP712 domain schema (#1742)
|
||||||
|
* Rename `verifyingContract` to `verifyingContractAddress` in domain schema (#1742)
|
||||||
|
* Add LibZeroExTransaction contract (#1753)
|
||||||
|
* Add verifyingContractIfExists arg to LibEIP712ExchangeDomain constructor (#1753)
|
||||||
|
* Remove LibEIP712ExchangeDomainConstants and LibEIP712 contracts (#1753)
|
||||||
|
* Add `LibExchangeRichErrorDecoder` contract. (#1790)
|
||||||
|
* Break out types/interaces from `MExchangeRichErrors` into `MExchangeRichErrorTypes`. (#1790)
|
||||||
|
* Reorder some revert error parameters for consistency (#1790)
|
||||||
|
* Add new `Order` fields for arbitrary fee tokens (ZEIP-28). (#1819)
|
||||||
|
* Remove `LibAbiEncoder` and `LibConstants`. (#1819)
|
||||||
|
* Add `generate-exchange-selectors` package script. (#1819)
|
||||||
|
* Add `expirationTimeSeconds` to `ZeroExTransaction` struct (#1823)
|
||||||
|
* Add reference functions for `LibMath` and `LibFillResults` (#2031)
|
||||||
|
* Move in revamped `LibMath` tests from the `contracts-exchange` package. (#2031)
|
||||||
|
* Move in revamped `LibFillResults` tests from the `contracts-exchange` package. (#2031)
|
||||||
|
* Remove unecessary zero-denominator checks in `LibMath`. (#2031)
|
||||||
|
* Fix coverage hooks. (#2031)
|
||||||
|
* Regenerate selectors. (#2042)
|
||||||
|
* Convert `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries (#2055)
|
||||||
|
* Remove `LibExchangeSelectors` (#2055)
|
||||||
|
* Add `LibExchangeRichErrors` (#2055)
|
||||||
|
* Add `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` (#2055)
|
||||||
|
* Remove `_hashEIP712ExchangeMessage` from `LibEIP712ExchangeDomain` (#2055)
|
||||||
|
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||||
|
* Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields. (#2075)
|
||||||
|
|
||||||
## v3.0.8 - _September 17, 2019_
|
## v3.0.8 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-exchange-libs",
|
"name": "@0x/contracts-exchange-libs",
|
||||||
"version": "3.0.8",
|
"version": "3.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,12 +48,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/subproviders": "^5.0.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/subproviders": "^5.1.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -73,14 +73,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "3.0.0",
|
"version": "2.2.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Use new/cheaper reentrancy guard/mutex",
|
"note": "Use new/cheaper reentrancy guard/mutex",
|
||||||
@ -190,7 +190,8 @@
|
|||||||
"note": "Overridden functions in `ReentrancyTester` now return sane values.",
|
"note": "Overridden functions in `ReentrancyTester` now return sane values.",
|
||||||
"pr": 2075
|
"pr": 2075
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,56 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v2.2.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Use new/cheaper reentrancy guard/mutex (#1699)
|
||||||
|
* Update domain separator (#1742)
|
||||||
|
* Refactor `executeTransaction` to take `ZeroExTransaction` struct as input (#1753)
|
||||||
|
* Refactor example contracts that use `executeTransaction` (#1753)
|
||||||
|
* Upgrade all string reverts to rich reverts (#1761)
|
||||||
|
* Add support for `SignatureType.OrderValidator` for orders (#1774)
|
||||||
|
* Add support for `SignatureType.WalletOrderValidator` for orders (#1774)
|
||||||
|
* Add a `bytes` return value to `executeTransaction`, which is equal to the encoded return data of the underlying Exchange function call (#1793)
|
||||||
|
* Implement `batchExecuteTransactions` (#1793)
|
||||||
|
* Refactor preSign to be compatible with `executeTransaction` (#1793)
|
||||||
|
* Remove ZRX fees in lieu of arbitrary maker and taker fee tokens. (#1819)
|
||||||
|
* Incorporate Multi-asset and ERC1155 tests into `fillOrder` and `matchOrders` tests (#1819)
|
||||||
|
* Swap fill order from maker -> taker to taker -> maker (#1819)
|
||||||
|
* Avoid redundant transfer in `fillOrder()` and `matchOrders()` when maker/taker is the same as feeRecipient and assets are the same (#1819)
|
||||||
|
* Implement `cancelOrderNoThrow` and `batchCancelOrdersNoThrow` functions (#1827)
|
||||||
|
* `executeTransaction` will now revert if the input transaction is expired (#1832)
|
||||||
|
* Log an `TransactionExecuted` event when an `executeTransaction` call is successful (#1832)
|
||||||
|
* Return a FillResults array for batch fill variants (#1834)
|
||||||
|
* Add `MixinTransferSimulator` contract for simulating multiple transfers on-chain (#1868)
|
||||||
|
* Add `EIP1271Wallet` signature type (#1885)
|
||||||
|
* Remove `WalletOrderValidator` and `OrderValidator` signature types (#1885)
|
||||||
|
* Make the regular `Validator` signature type have EIP1271 behavior (#1885)
|
||||||
|
* Always check signature types that are validated via contract (not just on first fill). (#1885)
|
||||||
|
* Remove unecessary rich revert error types. (#1885)
|
||||||
|
* Add `IEIP1271Wallet` interface (#1885)
|
||||||
|
* Add `validatorAddress` field to `SignatureValidatorError` rich reverts (#1885)
|
||||||
|
* Make `calculateMatchedFillResults` public (#1885)
|
||||||
|
* Updated RichErrors to the library pattern (#1913)
|
||||||
|
* Rewrote _dispatchTransferFrom in Solidity (#2020)
|
||||||
|
* Add `TestIsolatedExchange` contract and `IsolatedExchangeWrapper` test class (#2031)
|
||||||
|
* Add `ReferenceFunctions` as package export. (#2031)
|
||||||
|
* Remove `TestExchangeMath.sol`. Exchange math functions are now tested in the `exchange-libs` package and reference implementations are available there as well. (#2031)
|
||||||
|
* Remove functions from `TestExchangeInternals.sol` that are no longer tested in this package. (#2031)
|
||||||
|
* Remove `_assertValidFill()` (#2031)
|
||||||
|
* Add `wrapper_unit_tests` tests and `TestWrapperFunctions` contract (#2042)
|
||||||
|
* Disallow `signerAddress == 0` in signature validation functions. (#2042)
|
||||||
|
* Update `Wallet` signature type behavior to be in line with v2.1. (#2042)
|
||||||
|
* Add (semi) automated reentrancy tests and remove manual ones (#2042)
|
||||||
|
* Refactor to use new `LibFillResults`, `LibOrder`, `LibZeroExTransaction`, and `LibMath` to libraries (#2055)
|
||||||
|
* Remove `LibExchangeRichErrors` and `IExchangeRichErrors` (#2055)
|
||||||
|
* Use built in selectors instead of `LibExchangeSelectors` constants (#2055)
|
||||||
|
* Move `calculateFillResults` and `calculateMatchedFillResults` to `LibFillResults` in `exchange-libs` package (#2055)
|
||||||
|
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||||
|
* Rename `marketSellOrders` and `marketBuyOrders` back to `marketSellOrdersNoThrow` and `marketBuyOrdersNoThrow`. (#2075)
|
||||||
|
* Introduce new `marketSellOrdersFillOrKill` and `marketBuyOrdersFillOrKill` functions. (#2075)
|
||||||
|
* Use `abi.decode()` in `LibExchangeRichErrorDecoder` over `LibBytes`. (#2075)
|
||||||
|
* Overridden functions in `ReentrancyTester` now return sane values. (#2075)
|
||||||
|
|
||||||
## v2.1.14 - _September 17, 2019_
|
## v2.1.14 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-exchange",
|
"name": "@0x/contracts-exchange",
|
||||||
"version": "2.1.14",
|
"version": "2.2.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,11 +48,13 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-multisig": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/contracts-staking": "^1.1.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -71,19 +73,19 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc1155": "^1.1.15",
|
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc721": "^2.1.15",
|
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export * from './artifacts';
|
export * from './artifacts';
|
||||||
export * from './wrappers';
|
export * from './wrappers';
|
||||||
export * from '../test/utils';
|
export * from '../test/utils';
|
||||||
|
export * from './wrapper_interfaces';
|
||||||
|
53
contracts/exchange/src/wrapper_interfaces.ts
Normal file
53
contracts/exchange/src/wrapper_interfaces.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { PromiseWithTransactionHash } from '@0x/base-contract';
|
||||||
|
import { BlockParam, CallData, TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types';
|
||||||
|
|
||||||
|
// Generated Wrapper Interfaces
|
||||||
|
export interface AssetProxyDispatcher {
|
||||||
|
registerAssetProxy: {
|
||||||
|
awaitTransactionSuccessAsync: (
|
||||||
|
assetProxy: string,
|
||||||
|
txData?: Partial<TxData>,
|
||||||
|
pollingIntervalMs?: number,
|
||||||
|
timeoutMs?: number,
|
||||||
|
) => PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>;
|
||||||
|
};
|
||||||
|
getAssetProxy: {
|
||||||
|
callAsync(assetProxyId: string, callData?: Partial<CallData>, defaultBlock?: BlockParam): Promise<string>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Authorizable extends Ownable {
|
||||||
|
addAuthorizedAddress: {
|
||||||
|
awaitTransactionSuccessAsync: (
|
||||||
|
target: string,
|
||||||
|
txData?: Partial<TxData>,
|
||||||
|
pollingIntervalMs?: number,
|
||||||
|
timeoutMs?: number,
|
||||||
|
) => PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>;
|
||||||
|
};
|
||||||
|
removeAuthorizedAddress: {
|
||||||
|
awaitTransactionSuccessAsync: (
|
||||||
|
target: string,
|
||||||
|
txData?: Partial<TxData>,
|
||||||
|
pollingIntervalMs?: number,
|
||||||
|
timeoutMs?: number,
|
||||||
|
) => PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>;
|
||||||
|
};
|
||||||
|
authorized: {
|
||||||
|
callAsync(authority: string, callData?: Partial<CallData>, defaultBlock?: BlockParam): Promise<boolean>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Ownable {
|
||||||
|
transferOwnership: {
|
||||||
|
awaitTransactionSuccessAsync: (
|
||||||
|
newOwner: string,
|
||||||
|
txData?: Partial<TxData>,
|
||||||
|
pollingIntervalMs?: number,
|
||||||
|
timeoutMs?: number,
|
||||||
|
) => PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>;
|
||||||
|
};
|
||||||
|
owner: {
|
||||||
|
callAsync(callData?: Partial<CallData>, defaultBlock?: BlockParam): Promise<string>;
|
||||||
|
};
|
||||||
|
}
|
@ -172,7 +172,7 @@ blockchainTests.resets('Exchange core', () => {
|
|||||||
await multiAssetProxy.registerAssetProxy.awaitTransactionSuccessAsync(staticCallProxy.address, { from: owner });
|
await multiAssetProxy.registerAssetProxy.awaitTransactionSuccessAsync(staticCallProxy.address, { from: owner });
|
||||||
|
|
||||||
// Configure Exchange
|
// Configure Exchange
|
||||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, owner);
|
||||||
|
439
contracts/exchange/test/end-to-end/deployment.ts
Normal file
439
contracts/exchange/test/end-to-end/deployment.ts
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
import {
|
||||||
|
artifacts as assetProxyArtifacts,
|
||||||
|
ERC1155ProxyContract,
|
||||||
|
ERC20ProxyContract,
|
||||||
|
ERC721ProxyContract,
|
||||||
|
MultiAssetProxyContract,
|
||||||
|
StaticCallProxyContract,
|
||||||
|
} from '@0x/contracts-asset-proxy';
|
||||||
|
import { artifacts as multisigArtifacts, AssetProxyOwnerContract } from '@0x/contracts-multisig';
|
||||||
|
import {
|
||||||
|
artifacts as stakingArtifacts,
|
||||||
|
ReadOnlyProxyContract,
|
||||||
|
StakingContract,
|
||||||
|
StakingEvents,
|
||||||
|
StakingExchangeAddedEventArgs,
|
||||||
|
StakingProxyContract,
|
||||||
|
} from '@0x/contracts-staking';
|
||||||
|
import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils';
|
||||||
|
import {
|
||||||
|
AuthorizableAuthorizedAddressAddedEventArgs,
|
||||||
|
AuthorizableAuthorizedAddressRemovedEventArgs,
|
||||||
|
AuthorizableEvents,
|
||||||
|
} from '@0x/contracts-utils';
|
||||||
|
import { AssetProxyId } from '@0x/types';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { TxData } from 'ethereum-types';
|
||||||
|
|
||||||
|
import {
|
||||||
|
artifacts as exchangeArtifacts,
|
||||||
|
AssetProxyDispatcher,
|
||||||
|
Authorizable,
|
||||||
|
ExchangeAssetProxyRegisteredEventArgs,
|
||||||
|
ExchangeContract,
|
||||||
|
ExchangeEvents,
|
||||||
|
ExchangeProtocolFeeCollectorAddressEventArgs,
|
||||||
|
ExchangeProtocolFeeMultiplierEventArgs,
|
||||||
|
Ownable,
|
||||||
|
} from '../../src';
|
||||||
|
|
||||||
|
// tslint:disable:no-unnecessary-type-assertion
|
||||||
|
blockchainTests('Deployment and Configuration End to End Tests', env => {
|
||||||
|
// Available Addresses
|
||||||
|
let owner: string;
|
||||||
|
|
||||||
|
// Contract Instances
|
||||||
|
let assetProxyOwner: AssetProxyOwnerContract;
|
||||||
|
let erc20Proxy: ERC20ProxyContract;
|
||||||
|
let erc721Proxy: ERC721ProxyContract;
|
||||||
|
let erc1155Proxy: ERC1155ProxyContract;
|
||||||
|
let exchange: ExchangeContract;
|
||||||
|
let multiAssetProxy: MultiAssetProxyContract;
|
||||||
|
let readOnlyProxy: ReadOnlyProxyContract;
|
||||||
|
let staking: StakingContract;
|
||||||
|
let staticCallProxy: StaticCallProxyContract;
|
||||||
|
let stakingProxy: StakingProxyContract;
|
||||||
|
let stakingWrapper: StakingContract;
|
||||||
|
|
||||||
|
// TxDefaults
|
||||||
|
let txDefaults: Partial<TxData>;
|
||||||
|
|
||||||
|
// ChainId of the Exchange
|
||||||
|
let chainId: number;
|
||||||
|
|
||||||
|
// Protocol Fees
|
||||||
|
const protocolFeeMultiplier = new BigNumber(150000);
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
// Get the chain ID.
|
||||||
|
chainId = await env.getChainIdAsync();
|
||||||
|
|
||||||
|
// Create accounts and tx defaults
|
||||||
|
[owner] = await env.getAccountAddressesAsync();
|
||||||
|
txDefaults = {
|
||||||
|
...env.txDefaults,
|
||||||
|
from: owner,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deploy AssetProxyOwner. For the purposes of this test, we will assume that
|
||||||
|
// the AssetProxyOwner does not know what destinations will be needed during
|
||||||
|
// construction.
|
||||||
|
assetProxyOwner = await AssetProxyOwnerContract.deployFrom0xArtifactAsync(
|
||||||
|
multisigArtifacts.AssetProxyOwner,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
multisigArtifacts,
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[owner],
|
||||||
|
new BigNumber(1),
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy Exchange.
|
||||||
|
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||||
|
exchangeArtifacts.Exchange,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
exchangeArtifacts,
|
||||||
|
new BigNumber(chainId),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy ReadOnlyProxy.
|
||||||
|
readOnlyProxy = await ReadOnlyProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
stakingArtifacts.ReadOnlyProxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
stakingArtifacts,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy Staking.
|
||||||
|
staking = await StakingContract.deployFrom0xArtifactAsync(
|
||||||
|
stakingArtifacts.Staking,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
stakingArtifacts,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy the staking proxy.
|
||||||
|
stakingProxy = await StakingProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
stakingArtifacts.StakingProxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
stakingArtifacts,
|
||||||
|
staking.address,
|
||||||
|
readOnlyProxy.address,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Authorize owner in the staking proxy.
|
||||||
|
await stakingProxy.addAuthorizedAddress.awaitTransactionSuccessAsync(owner);
|
||||||
|
|
||||||
|
// Deploy the asset proxy contracts.
|
||||||
|
erc20Proxy = await ERC20ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
assetProxyArtifacts.ERC20Proxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
assetProxyArtifacts,
|
||||||
|
);
|
||||||
|
erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
assetProxyArtifacts.ERC721Proxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
assetProxyArtifacts,
|
||||||
|
);
|
||||||
|
erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
assetProxyArtifacts.ERC1155Proxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
assetProxyArtifacts,
|
||||||
|
);
|
||||||
|
multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
assetProxyArtifacts.MultiAssetProxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
assetProxyArtifacts,
|
||||||
|
);
|
||||||
|
staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync(
|
||||||
|
assetProxyArtifacts.StaticCallProxy,
|
||||||
|
env.provider,
|
||||||
|
txDefaults,
|
||||||
|
assetProxyArtifacts,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set up the staking wrapper so that the entire staking interface can be accessed
|
||||||
|
// easily through the proxy.
|
||||||
|
stakingWrapper = new StakingContract(stakingProxy.address, env.provider);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deployment and configuration', () => {
|
||||||
|
describe('exchange specific', () => {
|
||||||
|
// Registers an asset proxy in the exchange contract and ensure that the correct state changes occurred.
|
||||||
|
async function registerAssetProxyAndAssertSuccessAsync(
|
||||||
|
registrationContract: AssetProxyDispatcher,
|
||||||
|
assetProxyAddress: string,
|
||||||
|
assetProxyId: string,
|
||||||
|
): Promise<void> {
|
||||||
|
// Register the asset proxy.
|
||||||
|
const receipt = await registrationContract.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
|
assetProxyAddress,
|
||||||
|
{
|
||||||
|
from: owner,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that the correct event was logged.
|
||||||
|
const logs = filterLogsToArguments<ExchangeAssetProxyRegisteredEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
ExchangeEvents.AssetProxyRegistered,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([{ id: assetProxyId, assetProxy: assetProxyAddress }]);
|
||||||
|
|
||||||
|
// Ensure that the asset proxy was actually registered.
|
||||||
|
const proxyAddress = await registrationContract.getAssetProxy.callAsync(assetProxyId);
|
||||||
|
expect(proxyAddress).to.be.eq(assetProxyAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorizes an address for a given asset proxy using the owner address.
|
||||||
|
async function authorizeAddressAndAssertSuccessAsync(
|
||||||
|
authorizable: Authorizable,
|
||||||
|
newAuthorityAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
|
// Authorize the address.
|
||||||
|
const receipt = await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||||
|
newAuthorityAddress,
|
||||||
|
{ from: owner },
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that the correct log was emitted.
|
||||||
|
const logs = filterLogsToArguments<AuthorizableAuthorizedAddressAddedEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
AuthorizableEvents.AuthorizedAddressAdded,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([{ target: newAuthorityAddress, caller: owner }]);
|
||||||
|
|
||||||
|
// Ensure that the address was actually authorized.
|
||||||
|
const wasAuthorized = await authorizable.authorized.callAsync(newAuthorityAddress);
|
||||||
|
expect(wasAuthorized).to.be.true();
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should successfully register the asset proxies in the exchange', async () => {
|
||||||
|
// Register the asset proxies in the exchange.
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(exchange, erc20Proxy.address, AssetProxyId.ERC20);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(exchange, erc721Proxy.address, AssetProxyId.ERC721);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(exchange, erc1155Proxy.address, AssetProxyId.ERC1155);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(
|
||||||
|
exchange,
|
||||||
|
multiAssetProxy.address,
|
||||||
|
AssetProxyId.MultiAsset,
|
||||||
|
);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(
|
||||||
|
exchange,
|
||||||
|
staticCallProxy.address,
|
||||||
|
AssetProxyId.StaticCall,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully register the asset proxies in the multi-asset proxy', async () => {
|
||||||
|
// Register the asset proxies in the multi-asset proxy.
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(multiAssetProxy, erc20Proxy.address, AssetProxyId.ERC20);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(
|
||||||
|
multiAssetProxy,
|
||||||
|
erc721Proxy.address,
|
||||||
|
AssetProxyId.ERC721,
|
||||||
|
);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(
|
||||||
|
multiAssetProxy,
|
||||||
|
erc1155Proxy.address,
|
||||||
|
AssetProxyId.ERC1155,
|
||||||
|
);
|
||||||
|
await registerAssetProxyAndAssertSuccessAsync(
|
||||||
|
multiAssetProxy,
|
||||||
|
staticCallProxy.address,
|
||||||
|
AssetProxyId.StaticCall,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully add the exchange as an authority in the appropriate asset proxies', async () => {
|
||||||
|
// Authorize the exchange in all of the asset proxies, except for the static call proxy.
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(erc20Proxy, exchange.address);
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(erc721Proxy, exchange.address);
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(erc1155Proxy, exchange.address);
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(multiAssetProxy, exchange.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully add the multi asset proxy as an authority in the appropriate asset proxies', async () => {
|
||||||
|
// Authorize the multi-asset proxy in the token asset proxies.
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(erc20Proxy, multiAssetProxy.address);
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(erc721Proxy, multiAssetProxy.address);
|
||||||
|
await authorizeAddressAndAssertSuccessAsync(erc1155Proxy, multiAssetProxy.address);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('staking specific', () => {
|
||||||
|
it('should have properly configured the staking proxy with the logic contract and read-only proxy', async () => {
|
||||||
|
// Ensure that the registered read-only proxy is correct.
|
||||||
|
const readOnlyProxyAddress = await stakingProxy.readOnlyProxy.callAsync();
|
||||||
|
expect(readOnlyProxyAddress).to.be.eq(readOnlyProxy.address);
|
||||||
|
|
||||||
|
// Ensure that the registered read-only proxy callee is correct.
|
||||||
|
const readOnlyProxyCalleeAddress = await stakingProxy.readOnlyProxyCallee.callAsync();
|
||||||
|
expect(readOnlyProxyCalleeAddress).to.be.eq(staking.address);
|
||||||
|
|
||||||
|
// Ensure that the registered staking contract is correct.
|
||||||
|
const stakingAddress = await stakingProxy.stakingContract.callAsync();
|
||||||
|
expect(stakingAddress).to.be.eq(staking.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have initialized the correct parameters in the staking proxy', async () => {
|
||||||
|
// Ensure that the correct parameters were set.
|
||||||
|
const params = await stakingWrapper.getParams.callAsync();
|
||||||
|
expect(params).to.be.deep.eq(
|
||||||
|
[
|
||||||
|
864000, // epochDurationInSeconds
|
||||||
|
900000, // rewardDelegatedStakeWeight
|
||||||
|
100000000000000000000, // minimumPoolStake
|
||||||
|
10, // maximumMakerInPool
|
||||||
|
1, // cobbDouglasAlphaNumerator
|
||||||
|
2, // cobbDouglasAlphaDenominator
|
||||||
|
].map(value => new BigNumber(value)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('exchange and staking integration', () => {
|
||||||
|
it('should successfully register the exchange in the staking contract', async () => {
|
||||||
|
// Register the exchange.
|
||||||
|
const receipt = await stakingWrapper.addExchangeAddress.awaitTransactionSuccessAsync(exchange.address, {
|
||||||
|
from: owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure that the correct events were logged.
|
||||||
|
const logs = filterLogsToArguments<StakingExchangeAddedEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
StakingEvents.ExchangeAdded,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([{ exchangeAddress: exchange.address }]);
|
||||||
|
|
||||||
|
// Ensure that the exchange was registered.
|
||||||
|
const wasRegistered = await stakingWrapper.validExchanges.callAsync(exchange.address);
|
||||||
|
expect(wasRegistered).to.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully register the staking contract in the exchange', async () => {
|
||||||
|
// Register the staking contract.
|
||||||
|
const receipt = await exchange.setProtocolFeeCollectorAddress.awaitTransactionSuccessAsync(
|
||||||
|
stakingProxy.address,
|
||||||
|
{
|
||||||
|
from: owner,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that the correct events were logged.
|
||||||
|
const logs = filterLogsToArguments<ExchangeProtocolFeeCollectorAddressEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
ExchangeEvents.ProtocolFeeCollectorAddress,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([
|
||||||
|
{
|
||||||
|
oldProtocolFeeCollector: constants.NULL_ADDRESS,
|
||||||
|
updatedProtocolFeeCollector: stakingProxy.address,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ensure that the staking contract was registered.
|
||||||
|
const feeCollector = await exchange.protocolFeeCollector.callAsync();
|
||||||
|
expect(feeCollector).to.be.eq(stakingProxy.address);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully update the protocol fee multiplier in the staking contract', async () => {
|
||||||
|
// Update the protocol fee multiplier.
|
||||||
|
const receipt = await exchange.setProtocolFeeMultiplier.awaitTransactionSuccessAsync(
|
||||||
|
protocolFeeMultiplier,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that the correct events were logged.
|
||||||
|
const logs = filterLogsToArguments<ExchangeProtocolFeeMultiplierEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
ExchangeEvents.ProtocolFeeMultiplier,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([
|
||||||
|
{
|
||||||
|
oldProtocolFeeMultiplier: constants.ZERO_AMOUNT,
|
||||||
|
updatedProtocolFeeMultiplier: protocolFeeMultiplier,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ensure that the protocol fee multiplier was set correctly.
|
||||||
|
const multiplier = await exchange.protocolFeeMultiplier.callAsync();
|
||||||
|
expect(multiplier).bignumber.to.be.eq(protocolFeeMultiplier);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('transferring ownership', () => {
|
||||||
|
// Removes authorization of the "externally owned address" owner and transfers the authorization
|
||||||
|
// to the asset proxy owner.
|
||||||
|
async function transferAuthorizationAndAssertSuccessAsync(contract: Authorizable): Promise<void> {
|
||||||
|
// Remove authorization from the old owner.
|
||||||
|
let receipt = await contract.removeAuthorizedAddress.awaitTransactionSuccessAsync(owner, { from: owner });
|
||||||
|
|
||||||
|
// Ensure that the correct log was recorded.
|
||||||
|
let logs = filterLogsToArguments<AuthorizableAuthorizedAddressRemovedEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
AuthorizableEvents.AuthorizedAddressRemoved,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([{ target: owner, caller: owner }]);
|
||||||
|
|
||||||
|
// Ensure that the owner was actually removed.
|
||||||
|
let isAuthorized = await contract.authorized.callAsync(owner);
|
||||||
|
expect(isAuthorized).to.be.false();
|
||||||
|
|
||||||
|
// Authorize the asset-proxy owner.
|
||||||
|
receipt = await contract.addAuthorizedAddress.awaitTransactionSuccessAsync(assetProxyOwner.address, {
|
||||||
|
from: owner,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure that the correct log was recorded.
|
||||||
|
logs = filterLogsToArguments<AuthorizableAuthorizedAddressAddedEventArgs>(
|
||||||
|
receipt.logs,
|
||||||
|
AuthorizableEvents.AuthorizedAddressAdded,
|
||||||
|
);
|
||||||
|
expect(logs).to.be.deep.eq([{ target: assetProxyOwner.address, caller: owner }]);
|
||||||
|
|
||||||
|
// Ensure that the asset-proxy owner was actually authorized.
|
||||||
|
isAuthorized = await contract.authorized.callAsync(assetProxyOwner.address);
|
||||||
|
expect(isAuthorized).to.be.true();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfers ownership of a contract to the asset-proxy owner, and ensures that the change was actually made.
|
||||||
|
async function transferOwnershipAndAssertSuccessAsync(contract: Ownable): Promise<void> {
|
||||||
|
// Transfer ownership to the new owner.
|
||||||
|
await contract.transferOwnership.awaitTransactionSuccessAsync(assetProxyOwner.address, { from: owner });
|
||||||
|
|
||||||
|
// Ensure that the owner address has been updated.
|
||||||
|
const ownerAddress = await contract.owner.callAsync();
|
||||||
|
expect(ownerAddress).to.be.eq(assetProxyOwner.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should transfer authorization of the owner to the asset-proxy owner in the staking contracts', async () => {
|
||||||
|
// Transfer authorization of the staking system. We intentionally neglect
|
||||||
|
// to add the asset-proxy owner as an authorized address in the asset proxies
|
||||||
|
// as a security precaution.
|
||||||
|
await transferAuthorizationAndAssertSuccessAsync(stakingProxy);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should transfer ownership of all appropriate contracts to the asset-proxy owner', async () => {
|
||||||
|
// Transfer ownership of most contracts (we exclude contracts that are not ownable).
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(exchange);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(readOnlyProxy);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(staking);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(stakingProxy);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(erc20Proxy);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(erc721Proxy);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(erc1155Proxy);
|
||||||
|
await transferOwnershipAndAssertSuccessAsync(multiAssetProxy);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// tslint:enable:no-unnecessary-type-assertion
|
@ -135,7 +135,7 @@ describe('matchOrders', () => {
|
|||||||
{},
|
{},
|
||||||
new BigNumber(chainId),
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, owner);
|
||||||
|
@ -96,7 +96,7 @@ blockchainTests.resets('Exchange transactions', env => {
|
|||||||
{},
|
{},
|
||||||
new BigNumber(chainId),
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance, env.provider);
|
exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
|
|
||||||
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchangeInstance.address, { from: owner });
|
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchangeInstance.address, { from: owner });
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { BatchMatchOrder, orderUtils, Web3ProviderEngine } from '@0x/contracts-test-utils';
|
import { BatchMatchOrder, orderUtils } from '@0x/contracts-test-utils';
|
||||||
import {
|
import {
|
||||||
BatchMatchedFillResults,
|
BatchMatchedFillResults,
|
||||||
FillResults,
|
FillResults,
|
||||||
@ -8,7 +8,7 @@ import {
|
|||||||
SignedZeroExTransaction,
|
SignedZeroExTransaction,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||||
import { MethodAbi, TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
|
import { MethodAbi, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ExchangeContract } from '../../src';
|
import { ExchangeContract } from '../../src';
|
||||||
@ -16,18 +16,15 @@ import { ExchangeContract } from '../../src';
|
|||||||
import { AbiDecodedFillOrderData } from './types';
|
import { AbiDecodedFillOrderData } from './types';
|
||||||
|
|
||||||
export class ExchangeWrapper {
|
export class ExchangeWrapper {
|
||||||
private readonly _exchange: ExchangeContract;
|
constructor(public readonly exchangeContract: ExchangeContract) {}
|
||||||
// tslint:disable no-unused-variable
|
|
||||||
constructor(exchangeContract: ExchangeContract, provider: Web3ProviderEngine | ZeroExProvider) {
|
|
||||||
this._exchange = exchangeContract;
|
|
||||||
}
|
|
||||||
public async fillOrderAsync(
|
public async fillOrderAsync(
|
||||||
signedOrder: SignedOrder,
|
signedOrder: SignedOrder,
|
||||||
from: string,
|
from: string,
|
||||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
const txReceipt = await this._exchange.fillOrder.awaitTransactionSuccessAsync(
|
const txReceipt = await this.exchangeContract.fillOrder.awaitTransactionSuccessAsync(
|
||||||
params.order,
|
params.order,
|
||||||
params.takerAssetFillAmount,
|
params.takerAssetFillAmount,
|
||||||
params.signature,
|
params.signature,
|
||||||
@ -37,7 +34,7 @@ export class ExchangeWrapper {
|
|||||||
}
|
}
|
||||||
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createCancel(signedOrder);
|
const params = orderUtils.createCancel(signedOrder);
|
||||||
const txReceipt = await this._exchange.cancelOrder.awaitTransactionSuccessAsync(params.order, { from });
|
const txReceipt = await this.exchangeContract.cancelOrder.awaitTransactionSuccessAsync(params.order, { from });
|
||||||
return txReceipt;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
public async fillOrKillOrderAsync(
|
public async fillOrKillOrderAsync(
|
||||||
@ -46,7 +43,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
const txReceipt = await this._exchange.fillOrKillOrder.awaitTransactionSuccessAsync(
|
const txReceipt = await this.exchangeContract.fillOrKillOrder.awaitTransactionSuccessAsync(
|
||||||
params.order,
|
params.order,
|
||||||
params.takerAssetFillAmount,
|
params.takerAssetFillAmount,
|
||||||
params.signature,
|
params.signature,
|
||||||
@ -59,7 +56,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.batchFillOrders.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchFillOrders.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.takerAssetFillAmounts === undefined
|
opts.takerAssetFillAmounts === undefined
|
||||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||||
@ -73,7 +70,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.batchFillOrKillOrders.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchFillOrKillOrders.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.takerAssetFillAmounts === undefined
|
opts.takerAssetFillAmounts === undefined
|
||||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||||
@ -87,7 +84,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number; gasPrice?: BigNumber } = {},
|
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number; gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.batchFillOrdersNoThrow.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchFillOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.takerAssetFillAmounts === undefined
|
opts.takerAssetFillAmounts === undefined
|
||||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||||
@ -101,7 +98,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { takerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
opts: { takerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.marketSellOrdersNoThrow.awaitTransactionSuccessAsync(
|
return this.exchangeContract.marketSellOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.takerAssetFillAmount,
|
opts.takerAssetFillAmount,
|
||||||
orders.map(signedOrder => signedOrder.signature),
|
orders.map(signedOrder => signedOrder.signature),
|
||||||
@ -113,7 +110,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync(
|
return this.exchangeContract.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.makerAssetFillAmount,
|
opts.makerAssetFillAmount,
|
||||||
orders.map(signedOrder => signedOrder.signature),
|
orders.map(signedOrder => signedOrder.signature),
|
||||||
@ -125,7 +122,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.marketSellOrdersFillOrKill.awaitTransactionSuccessAsync(
|
return this.exchangeContract.marketSellOrdersFillOrKill.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.takerAssetFillAmount,
|
opts.takerAssetFillAmount,
|
||||||
orders.map(signedOrder => signedOrder.signature),
|
orders.map(signedOrder => signedOrder.signature),
|
||||||
@ -137,7 +134,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.marketBuyOrdersFillOrKill.awaitTransactionSuccessAsync(
|
return this.exchangeContract.marketBuyOrdersFillOrKill.awaitTransactionSuccessAsync(
|
||||||
orders,
|
orders,
|
||||||
opts.makerAssetFillAmount,
|
opts.makerAssetFillAmount,
|
||||||
orders.map(signedOrder => signedOrder.signature),
|
orders.map(signedOrder => signedOrder.signature),
|
||||||
@ -148,19 +145,22 @@ export class ExchangeWrapper {
|
|||||||
orders: SignedOrder[],
|
orders: SignedOrder[],
|
||||||
from: string,
|
from: string,
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.batchCancelOrders.awaitTransactionSuccessAsync(orders, { from });
|
return this.exchangeContract.batchCancelOrders.awaitTransactionSuccessAsync(orders, { from });
|
||||||
}
|
}
|
||||||
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const txReceipt = await this._exchange.cancelOrdersUpTo.awaitTransactionSuccessAsync(salt, { from });
|
const txReceipt = await this.exchangeContract.cancelOrdersUpTo.awaitTransactionSuccessAsync(salt, { from });
|
||||||
return txReceipt;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
public async registerAssetProxyAsync(
|
public async registerAssetProxyAsync(
|
||||||
assetProxyAddress: string,
|
assetProxyAddress: string,
|
||||||
from: string,
|
from: string,
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const txReceipt = await this._exchange.registerAssetProxy.awaitTransactionSuccessAsync(assetProxyAddress, {
|
const txReceipt = await this.exchangeContract.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||||
from,
|
assetProxyAddress,
|
||||||
});
|
{
|
||||||
|
from,
|
||||||
|
},
|
||||||
|
);
|
||||||
return txReceipt;
|
return txReceipt;
|
||||||
}
|
}
|
||||||
public async executeTransactionAsync(
|
public async executeTransactionAsync(
|
||||||
@ -168,7 +168,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.executeTransaction.awaitTransactionSuccessAsync(
|
return this.exchangeContract.executeTransaction.awaitTransactionSuccessAsync(
|
||||||
signedTransaction,
|
signedTransaction,
|
||||||
signedTransaction.signature,
|
signedTransaction.signature,
|
||||||
{ from, gasPrice: opts.gasPrice },
|
{ from, gasPrice: opts.gasPrice },
|
||||||
@ -180,25 +180,29 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const signatures = signedTransactions.map(signedTransaction => signedTransaction.signature);
|
const signatures = signedTransactions.map(signedTransaction => signedTransaction.signature);
|
||||||
return this._exchange.batchExecuteTransactions.awaitTransactionSuccessAsync(signedTransactions, signatures, {
|
return this.exchangeContract.batchExecuteTransactions.awaitTransactionSuccessAsync(
|
||||||
from,
|
signedTransactions,
|
||||||
gasPrice: opts.gasPrice,
|
signatures,
|
||||||
});
|
{
|
||||||
|
from,
|
||||||
|
gasPrice: opts.gasPrice,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
|
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
|
||||||
const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
|
const filledAmount = await this.exchangeContract.filled.callAsync(orderHashHex);
|
||||||
return filledAmount;
|
return filledAmount;
|
||||||
}
|
}
|
||||||
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
|
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
|
||||||
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
|
const isCancelled = await this.exchangeContract.cancelled.callAsync(orderHashHex);
|
||||||
return isCancelled;
|
return isCancelled;
|
||||||
}
|
}
|
||||||
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
|
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
|
||||||
const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
|
const orderEpoch = await this.exchangeContract.orderEpoch.callAsync(makerAddress, senderAddress);
|
||||||
return orderEpoch;
|
return orderEpoch;
|
||||||
}
|
}
|
||||||
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
|
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
|
||||||
const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
|
const orderInfo = await this.exchangeContract.getOrderInfo.callAsync(signedOrder);
|
||||||
return orderInfo;
|
return orderInfo;
|
||||||
}
|
}
|
||||||
public async batchMatchOrdersAsync(
|
public async batchMatchOrdersAsync(
|
||||||
@ -208,7 +212,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||||
return this._exchange.batchMatchOrders.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||||
params.leftOrders,
|
params.leftOrders,
|
||||||
params.rightOrders,
|
params.rightOrders,
|
||||||
params.leftSignatures,
|
params.leftSignatures,
|
||||||
@ -221,7 +225,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.batchMatchOrders.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||||
params.leftOrders,
|
params.leftOrders,
|
||||||
params.rightOrders,
|
params.rightOrders,
|
||||||
params.leftSignatures,
|
params.leftSignatures,
|
||||||
@ -236,7 +240,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<BatchMatchedFillResults> {
|
): Promise<BatchMatchedFillResults> {
|
||||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||||
const batchMatchedFillResults = await this._exchange.batchMatchOrders.callAsync(
|
const batchMatchedFillResults = await this.exchangeContract.batchMatchOrders.callAsync(
|
||||||
params.leftOrders,
|
params.leftOrders,
|
||||||
params.rightOrders,
|
params.rightOrders,
|
||||||
params.leftSignatures,
|
params.leftSignatures,
|
||||||
@ -252,7 +256,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||||
return this._exchange.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||||
params.leftOrders,
|
params.leftOrders,
|
||||||
params.rightOrders,
|
params.rightOrders,
|
||||||
params.leftSignatures,
|
params.leftSignatures,
|
||||||
@ -265,7 +269,7 @@ export class ExchangeWrapper {
|
|||||||
from: string,
|
from: string,
|
||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
return this._exchange.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
return this.exchangeContract.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||||
params.leftOrders,
|
params.leftOrders,
|
||||||
params.rightOrders,
|
params.rightOrders,
|
||||||
params.leftSignatures,
|
params.leftSignatures,
|
||||||
@ -280,7 +284,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<BatchMatchedFillResults> {
|
): Promise<BatchMatchedFillResults> {
|
||||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||||
const batchMatchedFillResults = await this._exchange.batchMatchOrdersWithMaximalFill.callAsync(
|
const batchMatchedFillResults = await this.exchangeContract.batchMatchOrdersWithMaximalFill.callAsync(
|
||||||
params.leftOrders,
|
params.leftOrders,
|
||||||
params.rightOrders,
|
params.rightOrders,
|
||||||
params.leftSignatures,
|
params.leftSignatures,
|
||||||
@ -296,7 +300,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
const txReceipt = await this._exchange.matchOrders.awaitTransactionSuccessAsync(
|
const txReceipt = await this.exchangeContract.matchOrders.awaitTransactionSuccessAsync(
|
||||||
params.left,
|
params.left,
|
||||||
params.right,
|
params.right,
|
||||||
params.leftSignature,
|
params.leftSignature,
|
||||||
@ -312,7 +316,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<MatchedFillResults> {
|
): Promise<MatchedFillResults> {
|
||||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
const matchedFillResults = await this._exchange.matchOrders.callAsync(
|
const matchedFillResults = await this.exchangeContract.matchOrders.callAsync(
|
||||||
params.left,
|
params.left,
|
||||||
params.right,
|
params.right,
|
||||||
params.leftSignature,
|
params.leftSignature,
|
||||||
@ -328,7 +332,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber } = {},
|
opts: { gasPrice?: BigNumber } = {},
|
||||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
return this._exchange.matchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
return this.exchangeContract.matchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||||
params.left,
|
params.left,
|
||||||
params.right,
|
params.right,
|
||||||
params.leftSignature,
|
params.leftSignature,
|
||||||
@ -343,7 +347,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { gasPrice?: BigNumber },
|
opts: { gasPrice?: BigNumber },
|
||||||
): Promise<MatchedFillResults> {
|
): Promise<MatchedFillResults> {
|
||||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||||
const matchedFillResults = await this._exchange.matchOrdersWithMaximalFill.callAsync(
|
const matchedFillResults = await this.exchangeContract.matchOrdersWithMaximalFill.callAsync(
|
||||||
params.left,
|
params.left,
|
||||||
params.right,
|
params.right,
|
||||||
params.leftSignature,
|
params.leftSignature,
|
||||||
@ -358,7 +362,7 @@ export class ExchangeWrapper {
|
|||||||
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
||||||
): Promise<FillResults> {
|
): Promise<FillResults> {
|
||||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
const fillResults = await this._exchange.fillOrder.callAsync(
|
const fillResults = await this.exchangeContract.fillOrder.callAsync(
|
||||||
params.order,
|
params.order,
|
||||||
params.takerAssetFillAmount,
|
params.takerAssetFillAmount,
|
||||||
params.signature,
|
params.signature,
|
||||||
@ -368,7 +372,7 @@ export class ExchangeWrapper {
|
|||||||
}
|
}
|
||||||
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
|
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
|
||||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||||
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
const data = this.exchangeContract.fillOrder.getABIEncodedTransactionData(
|
||||||
params.order,
|
params.order,
|
||||||
params.takerAssetFillAmount,
|
params.takerAssetFillAmount,
|
||||||
params.signature,
|
params.signature,
|
||||||
@ -377,13 +381,10 @@ export class ExchangeWrapper {
|
|||||||
}
|
}
|
||||||
public abiDecodeFillOrder(data: string): AbiDecodedFillOrderData {
|
public abiDecodeFillOrder(data: string): AbiDecodedFillOrderData {
|
||||||
// Lookup fillOrder ABI in exchange abi
|
// Lookup fillOrder ABI in exchange abi
|
||||||
const fillOrderAbi = _.find(this._exchange.abi, { name: 'fillOrder' }) as MethodAbi;
|
const fillOrderAbi = _.find(this.exchangeContract.abi, { name: 'fillOrder' }) as MethodAbi;
|
||||||
// Decode input data
|
// Decode input data
|
||||||
const abiEncoder = new AbiEncoder.Method(fillOrderAbi);
|
const abiEncoder = new AbiEncoder.Method(fillOrderAbi);
|
||||||
const decodedData = abiEncoder.decode(data) as AbiDecodedFillOrderData;
|
const decodedData = abiEncoder.decode(data) as AbiDecodedFillOrderData;
|
||||||
return decodedData;
|
return decodedData;
|
||||||
}
|
}
|
||||||
public getExchangeAddress(): string {
|
|
||||||
return this._exchange.address;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const logDecoder = new LogDecoder(web3Wrapper, artifacts);
|
const logDecoder = new LogDecoder(web3Wrapper, artifacts);
|
||||||
const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider);
|
const exchangeWrapper = new ExchangeWrapper(exchangeContract);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, ownerAddress);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, ownerAddress);
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, ownerAddress);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, ownerAddress);
|
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, ownerAddress);
|
||||||
@ -646,7 +646,7 @@ export class FillOrderCombinatorialUtils {
|
|||||||
|
|
||||||
const exchangeLogs = _.filter(
|
const exchangeLogs = _.filter(
|
||||||
txReceipt.logs,
|
txReceipt.logs,
|
||||||
txLog => txLog.address === this.exchangeWrapper.getExchangeAddress(),
|
txLog => txLog.address === this.exchangeWrapper.exchangeContract.address,
|
||||||
);
|
);
|
||||||
expect(exchangeLogs.length).to.be.equal(1, 'logs length');
|
expect(exchangeLogs.length).to.be.equal(1, 'logs length');
|
||||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||||
|
@ -78,7 +78,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
|||||||
from: owner,
|
from: owner,
|
||||||
});
|
});
|
||||||
|
|
||||||
exchangeWrapper = new ExchangeWrapper(exchange, env.provider);
|
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
|
|
||||||
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, {
|
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "4.1.0-beta.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v4.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v4.0.8 - _September 17, 2019_
|
## v4.0.8 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
@ -40,6 +44,9 @@ CHANGELOG
|
|||||||
## v4.0.0 - _July 13, 2019_
|
## v4.0.0 - _July 13, 2019_
|
||||||
|
|
||||||
* Move `OrderValidator` to contracts/dev-utils package as `OrderValidationUtils` (#1848)
|
* Move `OrderValidator` to contracts/dev-utils package as `OrderValidationUtils` (#1848)
|
||||||
|
* Remove unused `LibOrder` inheritance (#1742)
|
||||||
|
* Refactor BalanceThresholdFilter to use new ITransactions interface (#1753)
|
||||||
|
* Update tests for rich reverts (#1761)
|
||||||
|
|
||||||
## v3.1.5 - _May 24, 2019_
|
## v3.1.5 - _May 24, 2019_
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-extensions",
|
"name": "@0x/contracts-extensions",
|
||||||
"version": "4.0.8",
|
"version": "4.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,11 +48,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -71,19 +71,19 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc721": "^2.1.15",
|
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange": "^2.1.14",
|
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -136,7 +136,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
|
|||||||
zrxAssetData,
|
zrxAssetData,
|
||||||
new BigNumber(chainId),
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
|
exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||||
// Register proxies
|
// Register proxies
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
||||||
|
@ -95,7 +95,7 @@ describe(ContractName.DutchAuction, () => {
|
|||||||
zrxAssetData,
|
zrxAssetData,
|
||||||
new BigNumber(chainId),
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
|
const exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ describe('OrderMatcher', () => {
|
|||||||
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
||||||
new BigNumber(chainId),
|
new BigNumber(chainId),
|
||||||
);
|
);
|
||||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||||
// Authorize ERC20 trades by exchange
|
// Authorize ERC20 trades by exchange
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.2.0-beta.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "3.1.14",
|
"version": "3.1.14",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.2.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
## v3.1.14 - _September 17, 2019_
|
## v3.1.14 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-multisig",
|
"name": "@0x/contracts-multisig",
|
||||||
"version": "3.1.14",
|
"version": "3.2.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -47,11 +47,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
@ -69,15 +69,15 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.14",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.4",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.1.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Created package",
|
"note": "Created package",
|
||||||
@ -70,6 +70,7 @@
|
|||||||
"note": "Removed explicit dependency on epoch+1 when delegating.",
|
"note": "Removed explicit dependency on epoch+1 when delegating.",
|
||||||
"pr": 2188
|
"pr": 2188
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4,3 +4,23 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Created package (#1821)
|
||||||
|
* First implementation (#1910)
|
||||||
|
* Replace `LibFeeMath` with `LibFixedMath`. (#2109)
|
||||||
|
* Use a more precise cobb-douglas implementation. (#2109)
|
||||||
|
* Change the way operator stake is computed. (#2109)
|
||||||
|
* Denominate pool operator shares in parts-per-million. (#2109)
|
||||||
|
* New stake management mechanics. Delay before delegation. Nixed shadow rewards. (#2118)
|
||||||
|
* Tests for new stake management mechanics. (#2126)
|
||||||
|
* Add `init()` pattern to contracts. (#2131)
|
||||||
|
* Replace `MixinDeploymentConstants` with `MixinParams`. (#2131)
|
||||||
|
* Reference counting for cumulative rewards. (#2154)
|
||||||
|
* Refactored Staking Reward Vault. Moved pool management logic into staking contract. (#2156)
|
||||||
|
* Removed MixinStakingPoolRewardVault.sol (#2156)
|
||||||
|
* Refactored out `_cobbDouglas()` into its own library (#2179)
|
||||||
|
* Introduce multi-block finalization. (#2155)
|
||||||
|
* Removed reference counting for cumulative rewards. (#2188)
|
||||||
|
* Removed explicit dependency on epoch+1 when delegating. (#2188)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-staking",
|
"name": "@0x/contracts-staking",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -49,13 +49,13 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.1.0",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.13",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.2",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.2.1",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.6",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@0x/utils": "^4.3.1",
|
"@0x/utils": "^4.5.2",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
@ -74,16 +74,16 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.1.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contracts-asset-proxy": "^2.2.5",
|
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-erc20": "^2.2.0",
|
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||||
"@0x/contracts-utils": "^3.2.1",
|
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||||
"@0x/order-utils": "^8.1.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.2.2",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.2.2",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.3.1",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.6",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.2",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "4.0.0",
|
"version": "3.2.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Add `chainId` to `TransactionFactory` constructor",
|
"note": "Add `chainId` to `TransactionFactory` constructor",
|
||||||
@ -93,8 +93,13 @@
|
|||||||
{
|
{
|
||||||
"note": "Add `shortZip()` to `lang_utils.ts`",
|
"note": "Add `shortZip()` to `lang_utils.ts`",
|
||||||
"pr": 2155
|
"pr": 2155
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add `number_utils.ts` and `hexSize()`",
|
||||||
|
"pr": 2220
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,33 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.2.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Add `chainId` to `TransactionFactory` constructor (#1742)
|
||||||
|
* Use new `Order` structure with `domain` field (#1742)
|
||||||
|
* Inherit `chaiSetup` from `@0x/dev-utils` (#1761)
|
||||||
|
* Add `generatePseudoRandomOrderHash()` to `orderUtils` (#1761)
|
||||||
|
* Inherit `OrderStatus` from `@0x/types` (#1761)
|
||||||
|
* Update types for arbitrary fee tokens (#1819)
|
||||||
|
* Remove formatters (#1834)
|
||||||
|
* Add `hexConcat()` in `hex_utils.ts` (#1885)
|
||||||
|
* Introduce Mocha blockchain extensions (#2007)
|
||||||
|
* Move `*FillResults`, `OrderInfo` types to `@0x/types` (#2031)
|
||||||
|
* Add `log_utils.ts` (#2031)
|
||||||
|
* Add `haxRandom()` to `hex_utils.ts` (#2031)
|
||||||
|
* Add the constants: `MAX_UINT256`, `ADDRESS_LENGTH`, `MAX_UINT256_ROOT`, `ONE_ETHER` (#2031)
|
||||||
|
* Make `testCombinatoriallyWithReferenceFuncAsync` non-async (#2031)
|
||||||
|
* Update `testWithReferenceFuncAsync` to work with `RevertErrors` (#2031)
|
||||||
|
* `web3Wrapper` is created with `shouldAllowUnlimitedContractSize` if `UNLIMITED_CONTRACT_SIZE` environment variable is set. (#2075)
|
||||||
|
* Add `toHex()`, `hexLeftPad()`, `hexRightPad()`, and 'hexInvert()' hex utils (#2109)
|
||||||
|
* Add `PPM_DENOMINATOR` and `PPM_100_PERCENT` constants. (#2109)
|
||||||
|
* Increase the number of ganache accounts to 20 (#2109)
|
||||||
|
* Add `Numberish` type. (#2131)
|
||||||
|
* Tweaks/Upgrades to `hex_utils`, most notably `hexSlice()` (#2155)
|
||||||
|
* Add `hexHash()` to `hex_utils` (#2155)
|
||||||
|
* Add `shortZip()` to `lang_utils.ts` (#2155)
|
||||||
|
* Add `number_utils.ts` and `hexSize()` (#2220)
|
||||||
|
|
||||||
## v3.1.16 - _September 17, 2019_
|
## v3.1.16 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-test-utils",
|
"name": "@0x/contracts-test-utils",
|
||||||
"version": "3.1.16",
|
"version": "3.2.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -34,41 +34,41 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/test-utils/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/test-utils/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^5.2.7",
|
|
||||||
"mocha": "^6.2.0",
|
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/sol-coverage": "^3.0.12",
|
"@0x/sol-coverage": "^3.1.0-beta.0",
|
||||||
"@0x/sol-profiler": "^3.1.14",
|
"@0x/sol-profiler": "^3.2.0-beta.0",
|
||||||
"@0x/sol-trace": "^2.0.20",
|
"@0x/sol-trace": "^2.1.0-beta.0",
|
||||||
"@0x/subproviders": "^5.0.4",
|
"@0x/subproviders": "^5.1.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"@types/bn.js": "^4.11.0",
|
"@types/bn.js": "^4.11.0",
|
||||||
"@types/js-combinatorics": "^0.5.29",
|
"@types/js-combinatorics": "^0.5.29",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"bn.js": "^4.11.8",
|
"bn.js": "^4.11.8",
|
||||||
"chai": "^4.0.1",
|
"chai": "^4.0.1",
|
||||||
"chai-as-promised": "^7.1.0",
|
"chai-as-promised": "^7.1.0",
|
||||||
"chai-bignumber": "^3.0.0",
|
"chai-bignumber": "^3.0.0",
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"js-combinatorics": "^0.5.3",
|
"js-combinatorics": "^0.5.3",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"make-promises-safe": "^1.1.0"
|
"make-promises-safe": "^1.1.0",
|
||||||
|
"mocha": "^6.2.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@ -65,6 +65,13 @@ export function hexHash(n: Numberish): string {
|
|||||||
return ethUtil.bufferToHex(ethUtil.sha3(ethUtil.toBuffer(toHex(n))));
|
return ethUtil.bufferToHex(ethUtil.sha3(ethUtil.toBuffer(toHex(n))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the length, in bytes, of a hex string.
|
||||||
|
*/
|
||||||
|
export function hexSize(hex: string): number {
|
||||||
|
return Math.ceil((hex.length - 2) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a string, a number, or a BigNumber into a hex string.
|
* Convert a string, a number, or a BigNumber into a hex string.
|
||||||
* Works with negative numbers, as well.
|
* Works with negative numbers, as well.
|
||||||
|
@ -28,7 +28,17 @@ export { bytes32Values, testCombinatoriallyWithReferenceFunc, uint256Values } fr
|
|||||||
export { TransactionFactory } from './transaction_factory';
|
export { TransactionFactory } from './transaction_factory';
|
||||||
export { MutatorContractFunction, TransactionHelper } from './transaction_helper';
|
export { MutatorContractFunction, TransactionHelper } from './transaction_helper';
|
||||||
export { testWithReferenceFuncAsync } from './test_with_reference';
|
export { testWithReferenceFuncAsync } from './test_with_reference';
|
||||||
export { hexConcat, hexHash, hexLeftPad, hexInvert, hexSlice, hexRandom, hexRightPad, toHex } from './hex_utils';
|
export {
|
||||||
|
hexConcat,
|
||||||
|
hexHash,
|
||||||
|
hexLeftPad,
|
||||||
|
hexInvert,
|
||||||
|
hexSlice,
|
||||||
|
hexRandom,
|
||||||
|
hexRightPad,
|
||||||
|
hexSize,
|
||||||
|
toHex,
|
||||||
|
} from './hex_utils';
|
||||||
export {
|
export {
|
||||||
BatchMatchOrder,
|
BatchMatchOrder,
|
||||||
ContractName,
|
ContractName,
|
||||||
@ -51,3 +61,12 @@ export { blockchainTests, BlockchainTestsEnvironment, describe } from './mocha_b
|
|||||||
export { chaiSetup, expect } from './chai_setup';
|
export { chaiSetup, expect } from './chai_setup';
|
||||||
export { getCodesizeFromArtifact } from './codesize';
|
export { getCodesizeFromArtifact } from './codesize';
|
||||||
export { shortZip } from './lang_utils';
|
export { shortZip } from './lang_utils';
|
||||||
|
export {
|
||||||
|
assertIntegerRoughlyEquals,
|
||||||
|
assertRoughlyEquals,
|
||||||
|
getRandomFloat,
|
||||||
|
getRandomInteger,
|
||||||
|
getRandomPortion,
|
||||||
|
getNumericalDivergence,
|
||||||
|
toBaseUnitAmount,
|
||||||
|
} from './number_utils';
|
||||||
|
@ -3,21 +3,20 @@ import { Web3ProviderEngine } from '@0x/subproviders';
|
|||||||
import { providerUtils } from '@0x/utils';
|
import { providerUtils } from '@0x/utils';
|
||||||
import { TxData, Web3Wrapper } from '@0x/web3-wrapper';
|
import { TxData, Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
// Import ambient declarations (and clobber Jest).
|
import * as mocha from 'mocha';
|
||||||
import 'mocha';
|
|
||||||
import * as process from 'process';
|
import * as process from 'process';
|
||||||
|
|
||||||
import { provider, txDefaults, web3Wrapper } from './web3_wrapper';
|
import { provider, txDefaults, web3Wrapper } from './web3_wrapper';
|
||||||
|
|
||||||
// tslint:disable: no-namespace only-arrow-functions no-unbound-method
|
// tslint:disable: no-namespace only-arrow-functions no-unbound-method
|
||||||
|
|
||||||
export type ISuite = Mocha.ISuite;
|
export type ISuite = mocha.ISuite;
|
||||||
export type ISuiteCallbackContext = Mocha.ISuiteCallbackContext;
|
export type ISuiteCallbackContext = mocha.ISuiteCallbackContext;
|
||||||
export type SuiteCallback = (this: ISuiteCallbackContext) => void;
|
export type SuiteCallback = (this: ISuiteCallbackContext) => void;
|
||||||
export type ContextDefinitionCallback<T> = (description: string, callback: SuiteCallback) => T;
|
export type ContextDefinitionCallback<T> = (description: string, callback: SuiteCallback) => T;
|
||||||
export type BlockchainSuiteCallback = (this: ISuiteCallbackContext, env: BlockchainTestsEnvironment) => void;
|
export type BlockchainSuiteCallback = (this: ISuiteCallbackContext, env: BlockchainTestsEnvironment) => void;
|
||||||
export type BlockchainContextDefinitionCallback<T> = (description: string, callback: BlockchainSuiteCallback) => T;
|
export type BlockchainContextDefinitionCallback<T> = (description: string, callback: BlockchainSuiteCallback) => T;
|
||||||
export interface ContextDefinition extends Mocha.IContextDefinition {
|
export interface ContextDefinition extends mocha.IContextDefinition {
|
||||||
optional: ContextDefinitionCallback<ISuite | void>;
|
optional: ContextDefinitionCallback<ISuite | void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,10 +87,10 @@ export class BlockchainTestsEnvironmentSingleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The original `describe()` global provided by mocha.
|
// The original `describe()` global provided by mocha.
|
||||||
const mochaDescribe = (global as any).describe as Mocha.IContextDefinition;
|
const mochaDescribe = (global as any).describe as mocha.IContextDefinition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An augmented version of Mocha's `describe()`.
|
* An augmented version of mocha's `describe()`.
|
||||||
*/
|
*/
|
||||||
export const describe = _.assign(mochaDescribe, {
|
export const describe = _.assign(mochaDescribe, {
|
||||||
optional(description: string, callback: SuiteCallback): ISuite | void {
|
optional(description: string, callback: SuiteCallback): ISuite | void {
|
||||||
|
88
contracts/test-utils/src/number_utils.ts
Normal file
88
contracts/test-utils/src/number_utils.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
|
||||||
|
import { expect } from './chai_setup';
|
||||||
|
import { Numberish } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random integer between `min` and `max`, inclusive.
|
||||||
|
*/
|
||||||
|
export function getRandomInteger(min: Numberish, max: Numberish): BigNumber {
|
||||||
|
const range = new BigNumber(max).minus(min);
|
||||||
|
return getRandomPortion(range).plus(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random integer between `0` and `total`, inclusive.
|
||||||
|
*/
|
||||||
|
export function getRandomPortion(total: Numberish): BigNumber {
|
||||||
|
return new BigNumber(total).times(getRandomFloat(0, 1)).integerValue(BigNumber.ROUND_HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random, high-precision decimal between `min` and `max`, inclusive.
|
||||||
|
*/
|
||||||
|
export function getRandomFloat(min: Numberish, max: Numberish): BigNumber {
|
||||||
|
// Generate a really high precision number between [0, 1]
|
||||||
|
const r = new BigNumber(crypto.randomBytes(32).toString('hex'), 16).dividedBy(new BigNumber(2).pow(256).minus(1));
|
||||||
|
return new BigNumber(max)
|
||||||
|
.minus(min)
|
||||||
|
.times(r)
|
||||||
|
.plus(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts two decimal numbers to integers with `precision` digits, then returns
|
||||||
|
* the absolute difference.
|
||||||
|
*/
|
||||||
|
export function getNumericalDivergence(a: Numberish, b: Numberish, precision: number = 18): number {
|
||||||
|
const _a = new BigNumber(a);
|
||||||
|
const _b = new BigNumber(b);
|
||||||
|
const maxIntegerDigits = Math.max(
|
||||||
|
_a.integerValue(BigNumber.ROUND_DOWN).sd(true),
|
||||||
|
_b.integerValue(BigNumber.ROUND_DOWN).sd(true),
|
||||||
|
);
|
||||||
|
const _toInteger = (n: BigNumber) => {
|
||||||
|
const base = 10 ** (precision - maxIntegerDigits);
|
||||||
|
return n.times(base).integerValue(BigNumber.ROUND_DOWN);
|
||||||
|
};
|
||||||
|
return _toInteger(_a)
|
||||||
|
.minus(_toInteger(_b))
|
||||||
|
.abs()
|
||||||
|
.toNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that two numbers are equal up to `precision` digits.
|
||||||
|
*/
|
||||||
|
export function assertRoughlyEquals(actual: Numberish, expected: Numberish, precision: number = 18): void {
|
||||||
|
if (getNumericalDivergence(actual, expected, precision) <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect(actual).to.bignumber.eq(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that two numbers are equal with up to `maxError` difference between them.
|
||||||
|
*/
|
||||||
|
export function assertIntegerRoughlyEquals(actual: Numberish, expected: Numberish, maxError: number = 1): void {
|
||||||
|
const diff = new BigNumber(actual)
|
||||||
|
.minus(expected)
|
||||||
|
.abs()
|
||||||
|
.toNumber();
|
||||||
|
if (diff <= maxError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect(actual).to.bignumber.eq(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts `amount` into a base unit amount with 18 digits.
|
||||||
|
*/
|
||||||
|
export function toBaseUnitAmount(amount: Numberish): BigNumber {
|
||||||
|
const decimals = 18;
|
||||||
|
const amountAsBigNumber = new BigNumber(amount);
|
||||||
|
const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amountAsBigNumber, decimals);
|
||||||
|
return baseUnitAmount;
|
||||||
|
}
|
@ -20,10 +20,10 @@ export class OrderFactory {
|
|||||||
const tenMinutesInSeconds = 10 * 60;
|
const tenMinutesInSeconds = 10 * 60;
|
||||||
const currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
const currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
||||||
const order = ({
|
const order = ({
|
||||||
|
takerAddress: constants.NULL_ADDRESS,
|
||||||
senderAddress: constants.NULL_ADDRESS,
|
senderAddress: constants.NULL_ADDRESS,
|
||||||
expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds),
|
expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds),
|
||||||
salt: generatePseudoRandomSalt(),
|
salt: generatePseudoRandomSalt(),
|
||||||
takerAddress: constants.NULL_ADDRESS,
|
|
||||||
...this._defaultOrderParams,
|
...this._defaultOrderParams,
|
||||||
...customOrderParams,
|
...customOrderParams,
|
||||||
} as any) as Order;
|
} as any) as Order;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "3.2.5",
|
"version": "3.3.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Change ReentrancyGuard implementation to cheaper one",
|
"note": "Change ReentrancyGuard implementation to cheaper one",
|
||||||
@ -62,7 +62,8 @@
|
|||||||
"note": "Introduce automatic normalization and some zero-value shortcuts in `LibFractions`.",
|
"note": "Introduce automatic normalization and some zero-value shortcuts in `LibFractions`.",
|
||||||
"pr": 2155
|
"pr": 2155
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
|
@ -5,6 +5,24 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v3.3.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Change ReentrancyGuard implementation to cheaper one (#1699)
|
||||||
|
* Add LibEIP712 contract (#1753)
|
||||||
|
* Add `RichErrors` and `mixins/MRichErrors` (#1761)
|
||||||
|
* Break out types/interaces from `MRichErrors` into `MRichErrorTypes`. (#1790)
|
||||||
|
* Add LibEIP1271.sol (#1885)
|
||||||
|
* Updated RichErrors to the library pattern, and implemented RichErrors for all remaining reverts and requires (#1913)
|
||||||
|
* Added unit tests for all of the internal functions in the package (#2014)
|
||||||
|
* Updated Ownable to revert when the owner attempts to transfer ownership to the zero address (#2019)
|
||||||
|
* Add reference functions for `SafeMath` functions. (#2031)
|
||||||
|
* Throw a `SafeMathError` in `SafeMath._safeDiv()` when denominator is zero. (#2031)
|
||||||
|
* Create `LibSafeMath` (#2055)
|
||||||
|
* Rename `_rrevert` to `rrevert` in `LibRichErrors` contract (#2055)
|
||||||
|
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
|
||||||
|
* Added LibFractions (#2118)
|
||||||
|
* Introduce automatic normalization and some zero-value shortcuts in `LibFractions`. (#2155)
|
||||||
|
|
||||||
## v3.2.4 - _September 17, 2019_
|
## v3.2.4 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-utils",
|
"name": "@0x/contracts-utils",
|
||||||
"version": "3.2.4",
|
"version": "3.3.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -48,11 +48,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/utils/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/utils/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/contracts-gen": "^1.0.15",
|
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||||
"@0x/contracts-test-utils": "^3.1.16",
|
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/sol-compiler": "^3.1.15",
|
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/bn.js": "^4.11.0",
|
"@types/bn.js": "^4.11.0",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
@ -72,14 +72,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"bn.js": "^4.11.8",
|
"bn.js": "^4.11.8",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
"run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish",
|
"run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish",
|
||||||
"run:publish:local": "IS_LOCAL_PUBLISH=true yarn run:publish",
|
"run:publish:local": "IS_LOCAL_PUBLISH=true yarn run:publish",
|
||||||
"script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js",
|
"script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js",
|
||||||
"script:publish": "node ./packages/monorepo-scripts/lib/publish.js",
|
"script:publish": "DIST_TAG=protocolV3 node ./packages/monorepo-scripts/lib/publish.js",
|
||||||
"install:all": "yarn install",
|
"install:all": "yarn install",
|
||||||
"wsrun": "wsrun",
|
"wsrun": "wsrun",
|
||||||
"lerna": "lerna",
|
"lerna": "lerna",
|
||||||
"build": "lerna link && wsrun build $PKG -r --stages --fast-exit --exclude-missing",
|
"build": "lerna link && wsrun build $PKG -r --stages --fast-exit --exclude-missing --exclude @0x/contracts-extensions --exclude @0x/contracts-coordinator",
|
||||||
"build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing --exclude @0x/contracts-extensions --exclude @0x/contracts-coordinator",
|
"build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing --exclude @0x/contracts-extensions --exclude @0x/contracts-coordinator",
|
||||||
"build:contracts": "lerna link && wsrun build -p ${npm_package_config_contractsPackages} -c --fast-exit -r --stages --exclude-missing",
|
"build:contracts": "lerna link && wsrun build -p ${npm_package_config_contractsPackages} -c --fast-exit -r --stages --exclude-missing",
|
||||||
"build:monorepo_scripts": "PKG=@0x/monorepo-scripts yarn build",
|
"build:monorepo_scripts": "PKG=@0x/monorepo-scripts yarn build",
|
||||||
@ -65,7 +65,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "packages/instant/umd/instant.js",
|
"path": "packages/instant/umd/instant.js",
|
||||||
"maxSize": "1460kB"
|
"maxSize": "1960kB"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ci": {
|
"ci": {
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "7.1.0-beta.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Updated to work with 0x v3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1568744790,
|
"timestamp": 1568744790,
|
||||||
"version": "7.0.2",
|
"version": "7.0.2",
|
||||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v7.1.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Updated to work with 0x v3
|
||||||
|
|
||||||
## v7.0.2 - _September 17, 2019_
|
## v7.0.2 - _September 17, 2019_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "0x.js",
|
"name": "0x.js",
|
||||||
"version": "7.0.2",
|
"version": "7.1.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -46,9 +46,9 @@
|
|||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/contract-addresses": "^3.2.0",
|
"@0x/contract-addresses": "^3.3.0-beta.0",
|
||||||
"@0x/dev-utils": "^2.3.3",
|
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||||
"@0x/migrations": "^4.3.2",
|
"@0x/migrations": "^4.4.0-beta.0",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
@ -77,19 +77,19 @@
|
|||||||
"webpack": "^4.20.2"
|
"webpack": "^4.20.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/abi-gen-wrappers": "^5.3.2",
|
"@0x/abi-gen-wrappers": "^5.4.0-beta.0",
|
||||||
"@0x/assert": "^2.1.6",
|
"@0x/assert": "^2.2.0-beta.0",
|
||||||
"@0x/asset-swapper": "^2.0.0",
|
"@0x/asset-swapper": "^2.1.0-beta.0",
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contract-wrappers": "^12.1.0",
|
"@0x/contract-wrappers": "^12.2.0-beta.0",
|
||||||
"@0x/order-utils": "^8.4.0",
|
"@0x/order-utils": "^8.5.0-beta.0",
|
||||||
"@0x/subproviders": "^5.0.4",
|
"@0x/subproviders": "^5.1.0-beta.0",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/typescript-typings": "^4.3.0",
|
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"@types/web3-provider-engine": "^14.0.0",
|
"@types/web3-provider-engine": "^14.0.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"web3-provider-engine": "14.0.6"
|
"web3-provider-engine": "14.0.6"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export { ContractAddresses } from '@0x/contract-addresses';
|
export { getContractAddressesForNetworkOrThrow, NetworkId, ContractAddresses } from '@0x/contract-addresses';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
assetDataUtils,
|
assetDataUtils,
|
||||||
@ -8,21 +8,6 @@ export {
|
|||||||
transactionHashUtils,
|
transactionHashUtils,
|
||||||
} from '@0x/order-utils';
|
} from '@0x/order-utils';
|
||||||
|
|
||||||
export {
|
|
||||||
ContractWrappers,
|
|
||||||
CoordinatorWrapper,
|
|
||||||
CoordinatorServerCancellationResponse,
|
|
||||||
CoordinatorServerError,
|
|
||||||
IndexedFilterValues,
|
|
||||||
ContractWrappersConfig,
|
|
||||||
OrderTransactionOpts,
|
|
||||||
TransactionOpts,
|
|
||||||
OrderInfo,
|
|
||||||
EventCallback,
|
|
||||||
DecodedLogEvent,
|
|
||||||
OrderStatus,
|
|
||||||
} from '@0x/contract-wrappers';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
ExchangeEventArgs,
|
ExchangeEventArgs,
|
||||||
ExchangeEvents,
|
ExchangeEvents,
|
||||||
@ -33,13 +18,6 @@ export {
|
|||||||
ExchangeAssetProxyRegisteredEventArgs,
|
ExchangeAssetProxyRegisteredEventArgs,
|
||||||
ExchangeContract,
|
ExchangeContract,
|
||||||
DevUtilsContract,
|
DevUtilsContract,
|
||||||
ForwarderContract,
|
|
||||||
DutchAuctionContract,
|
|
||||||
CoordinatorContract,
|
|
||||||
CoordinatorRegistryEventArgs,
|
|
||||||
CoordinatorRegistryEvents,
|
|
||||||
CoordinatorRegistryCoordinatorEndpointSetEventArgs,
|
|
||||||
CoordinatorRegistryContract,
|
|
||||||
IValidatorContract,
|
IValidatorContract,
|
||||||
IWalletContract,
|
IWalletContract,
|
||||||
WETH9EventArgs,
|
WETH9EventArgs,
|
||||||
@ -60,38 +38,14 @@ export {
|
|||||||
ERC721TokenApprovalEventArgs,
|
ERC721TokenApprovalEventArgs,
|
||||||
ERC721TokenApprovalForAllEventArgs,
|
ERC721TokenApprovalForAllEventArgs,
|
||||||
ERC721TokenContract,
|
ERC721TokenContract,
|
||||||
ERC1155ProxyEventArgs,
|
|
||||||
ERC1155ProxyEvents,
|
|
||||||
ERC1155ProxyAuthorizedAddressAddedEventArgs,
|
|
||||||
ERC1155ProxyAuthorizedAddressRemovedEventArgs,
|
|
||||||
ERC1155ProxyContract,
|
|
||||||
ZRXTokenEventArgs,
|
ZRXTokenEventArgs,
|
||||||
ZRXTokenEvents,
|
ZRXTokenEvents,
|
||||||
ZRXTokenTransferEventArgs,
|
ZRXTokenTransferEventArgs,
|
||||||
ZRXTokenApprovalEventArgs,
|
ZRXTokenApprovalEventArgs,
|
||||||
ZRXTokenContract,
|
ZRXTokenContract,
|
||||||
DummyERC20TokenEventArgs,
|
ExchangeProtocolFeeCollectorAddressEventArgs,
|
||||||
DummyERC20TokenEvents,
|
ExchangeProtocolFeeMultiplierEventArgs,
|
||||||
DummyERC20TokenTransferEventArgs,
|
ExchangeTransactionExecutionEventArgs,
|
||||||
DummyERC20TokenApprovalEventArgs,
|
|
||||||
DummyERC20TokenContract,
|
|
||||||
DummyERC721TokenEventArgs,
|
|
||||||
DummyERC721TokenEvents,
|
|
||||||
DummyERC721TokenTransferEventArgs,
|
|
||||||
DummyERC721TokenApprovalEventArgs,
|
|
||||||
DummyERC721TokenApprovalForAllEventArgs,
|
|
||||||
DummyERC721TokenContract,
|
|
||||||
ERC20ProxyEventArgs,
|
|
||||||
ERC20ProxyEvents,
|
|
||||||
ERC20ProxyContract,
|
|
||||||
ERC20ProxyAuthorizedAddressAddedEventArgs,
|
|
||||||
ERC20ProxyAuthorizedAddressRemovedEventArgs,
|
|
||||||
ERC721ProxyEventArgs,
|
|
||||||
ERC721ProxyEvents,
|
|
||||||
ERC721ProxyAuthorizedAddressAddedEventArgs,
|
|
||||||
ERC721ProxyAuthorizedAddressRemovedEventArgs,
|
|
||||||
ERC721ProxyContract,
|
|
||||||
OrderValidatorContract,
|
|
||||||
} from '@0x/abi-gen-wrappers';
|
} from '@0x/abi-gen-wrappers';
|
||||||
|
|
||||||
export import Web3ProviderEngine = require('web3-provider-engine');
|
export import Web3ProviderEngine = require('web3-provider-engine');
|
||||||
@ -104,7 +58,7 @@ export {
|
|||||||
MetamaskSubprovider,
|
MetamaskSubprovider,
|
||||||
} from '@0x/subproviders';
|
} from '@0x/subproviders';
|
||||||
|
|
||||||
export { AbiDecoder, DecodedCalldata, BigNumber } from '@0x/utils';
|
export { DecodedCalldata, BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Order,
|
Order,
|
||||||
@ -128,23 +82,20 @@ export {
|
|||||||
SimpleStandardContractOutput,
|
SimpleStandardContractOutput,
|
||||||
SimpleEvmOutput,
|
SimpleEvmOutput,
|
||||||
SimpleEvmBytecodeOutput,
|
SimpleEvmBytecodeOutput,
|
||||||
|
EIP712DomainWithDefaultSchema,
|
||||||
|
EventCallback,
|
||||||
|
IndexedFilterValues,
|
||||||
|
DecodedLogEvent,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
BlockRange,
|
BlockRange,
|
||||||
ContractAbi,
|
ContractAbi,
|
||||||
LogWithDecodedArgs,
|
|
||||||
ContractEventArg,
|
ContractEventArg,
|
||||||
SupportedProvider,
|
SupportedProvider,
|
||||||
JSONRPCRequestPayload,
|
JSONRPCRequestPayload,
|
||||||
JSONRPCResponsePayload,
|
JSONRPCResponsePayload,
|
||||||
JSONRPCResponseError,
|
JSONRPCResponseError,
|
||||||
LogEntry,
|
|
||||||
DecodedLogArgs,
|
|
||||||
LogEntryEvent,
|
|
||||||
DecodedLogEntry,
|
|
||||||
DecodedLogEntryEvent,
|
|
||||||
RawLog,
|
|
||||||
AbiDefinition,
|
AbiDefinition,
|
||||||
FunctionAbi,
|
FunctionAbi,
|
||||||
EventAbi,
|
EventAbi,
|
||||||
@ -183,4 +134,7 @@ export {
|
|||||||
OutputField,
|
OutputField,
|
||||||
ParamDescription,
|
ParamDescription,
|
||||||
EvmBytecodeOutput,
|
EvmBytecodeOutput,
|
||||||
|
RevertErrorAbi,
|
||||||
|
DecodedLogArgs,
|
||||||
|
LogWithDecodedArgs,
|
||||||
} from 'ethereum-types';
|
} from 'ethereum-types';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"version": "6.0.0",
|
"version": "5.4.0-beta.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"note": "Use V3 contracts",
|
"note": "Use V3 contracts",
|
||||||
@ -10,7 +10,8 @@
|
|||||||
"note": "Hardcode bytecode for local EVM execution",
|
"note": "Hardcode bytecode for local EVM execution",
|
||||||
"pr": 2198
|
"pr": 2198
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"timestamp": 1570135330
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
|
@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## v5.4.0-beta.0 - _October 3, 2019_
|
||||||
|
|
||||||
|
* Use V3 contracts (#2181)
|
||||||
|
* Hardcode bytecode for local EVM execution (#2198)
|
||||||
|
|
||||||
## v5.3.2 - _September 17, 2019_
|
## v5.3.2 - _September 17, 2019_
|
||||||
|
|
||||||
* Redirect `callAsync` to use local EVM instead of eth_call for pure functions (#2108)
|
* Redirect `callAsync` to use local EVM instead of eth_call for pure functions (#2108)
|
||||||
@ -47,7 +52,9 @@ CHANGELOG
|
|||||||
|
|
||||||
## v4.3.0 - _May 10, 2019_
|
## v4.3.0 - _May 10, 2019_
|
||||||
|
|
||||||
|
* Update Coordinator and Exchange wrappers (#1742)
|
||||||
* Update wrapper functions to expose `awaitTransactionSuccessAsync()` methods (#1797)
|
* Update wrapper functions to expose `awaitTransactionSuccessAsync()` methods (#1797)
|
||||||
|
* Update wrappers to automatically throw `RevertError` types when possible. (#1819)
|
||||||
|
|
||||||
## v4.2.0 - _April 11, 2019_
|
## v4.2.0 - _April 11, 2019_
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/abi-gen-wrappers",
|
"name": "@0x/abi-gen-wrappers",
|
||||||
"version": "5.3.2",
|
"version": "5.4.0-beta.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@ -33,22 +33,22 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^4.2.1",
|
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||||
"@0x/assert": "^2.1.6",
|
"@0x/assert": "^2.2.0-beta.0",
|
||||||
"@0x/json-schemas": "^4.0.2",
|
"@0x/json-schemas": "^4.1.0-beta.0",
|
||||||
"@0x/tslint-config": "^3.0.1",
|
"@0x/tslint-config": "^3.0.1",
|
||||||
"@0x/types": "^2.4.3",
|
"@0x/types": "^2.5.0-beta.0",
|
||||||
"@0x/utils": "^4.5.2",
|
"@0x/utils": "^4.6.0-beta.0",
|
||||||
"@0x/web3-wrapper": "^6.0.13",
|
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||||
"ethereum-types": "^2.1.6",
|
"ethereum-types": "^2.2.0-beta.0",
|
||||||
"ethers": "~4.0.4",
|
"ethers": "~4.0.4",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"shx": "^0.2.2"
|
"shx": "^0.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^5.4.0",
|
"@0x/base-contract": "^5.5.0-beta.0",
|
||||||
"@0x/contract-addresses": "^3.2.0",
|
"@0x/contract-addresses": "^3.3.0-beta.0",
|
||||||
"@0x/contract-artifacts": "^2.2.2"
|
"@0x/contract-artifacts": "^2.3.0-beta.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
File diff suppressed because one or more lines are too long
@ -18,7 +18,7 @@ import {
|
|||||||
SupportedProvider,
|
SupportedProvider,
|
||||||
} from 'ethereum-types';
|
} from 'ethereum-types';
|
||||||
import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils';
|
import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils';
|
||||||
import { SimpleContractArtifact } from '@0x/types';
|
import { SimpleContractArtifact, EventCallback, IndexedFilterValues } from '@0x/types';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { assert } from '@0x/assert';
|
import { assert } from '@0x/assert';
|
||||||
import * as ethers from 'ethers';
|
import * as ethers from 'ethers';
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma
|
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma
|
||||||
// tslint:disable:whitespace no-unbound-method no-trailing-whitespace
|
// tslint:disable:whitespace no-unbound-method no-trailing-whitespace
|
||||||
// tslint:disable:no-unused-variable
|
// tslint:disable:no-unused-variable
|
||||||
import {
|
import { BaseContract, SubscriptionManager, PromiseWithTransactionHash } from '@0x/base-contract';
|
||||||
BaseContract,
|
|
||||||
EventCallback,
|
|
||||||
IndexedFilterValues,
|
|
||||||
SubscriptionManager,
|
|
||||||
PromiseWithTransactionHash,
|
|
||||||
} from '@0x/base-contract';
|
|
||||||
import { schemas } from '@0x/json-schemas';
|
import { schemas } from '@0x/json-schemas';
|
||||||
import {
|
import {
|
||||||
BlockParam,
|
BlockParam,
|
||||||
@ -25,7 +19,7 @@ import {
|
|||||||
SupportedProvider,
|
SupportedProvider,
|
||||||
} from 'ethereum-types';
|
} from 'ethereum-types';
|
||||||
import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils';
|
import { BigNumber, classUtils, logUtils, providerUtils } from '@0x/utils';
|
||||||
import { SimpleContractArtifact } from '@0x/types';
|
import { SimpleContractArtifact, EventCallback, IndexedFilterValues } from '@0x/types';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { assert } from '@0x/assert';
|
import { assert } from '@0x/assert';
|
||||||
import * as ethers from 'ethers';
|
import * as ethers from 'ethers';
|
||||||
|
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user