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
|
||||
# TODO(abandeali): Re-enable after this package is complete.
|
||||
# - 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:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
@ -94,7 +82,9 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn test:publish:circleci
|
||||
- run:
|
||||
command: yarn test:publish:circleci
|
||||
no_output_timeout: 1800
|
||||
test-doc-generation:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
@ -103,7 +93,9 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn test:generate_docs:circleci
|
||||
- run:
|
||||
command: yarn test:generate_docs:circleci
|
||||
no_output_timeout: 1200
|
||||
test-rest:
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
@ -405,22 +397,18 @@ workflows:
|
||||
- test-contracts-rest-ganache-3.0:
|
||||
requires:
|
||||
- build
|
||||
# Disabled until geth docker image is fixed.
|
||||
# - test-contracts-geth:
|
||||
# requires:
|
||||
# - build
|
||||
- test-rest:
|
||||
requires:
|
||||
- build
|
||||
- static-tests:
|
||||
requires:
|
||||
- build
|
||||
# - test-publish:
|
||||
# requires:
|
||||
# - build
|
||||
# - test-doc-generation:
|
||||
# requires:
|
||||
# - build
|
||||
- test-publish:
|
||||
requires:
|
||||
- build
|
||||
- test-doc-generation:
|
||||
requires:
|
||||
- build
|
||||
- submit-coverage:
|
||||
requires:
|
||||
- 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/ethereum-types: ['ethereum-types']
|
||||
@0x/connect: ['packages/connect']
|
||||
@0x/fill-scenarios: ['packages/fill-scenarios']
|
||||
@0x/testnet-faucets: ['packages/testnet-faucets']
|
||||
@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/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/fill-scenarios`](/packages/fill-scenarios) | [](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator |
|
||||
|
||||
#### Private Packages
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"version": "2.3.0-beta.0",
|
||||
"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",
|
||||
@ -17,8 +17,17 @@
|
||||
{
|
||||
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
|
||||
"pr": 1910
|
||||
},
|
||||
{
|
||||
"note": "Add `ERC20BridgeProxy`",
|
||||
"pr": 2220
|
||||
},
|
||||
{
|
||||
"note": "Add `Eth2DaiBridge`",
|
||||
"pr": 2221
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
@ -58,6 +67,9 @@ CHANGELOG
|
||||
## v2.1.2 - _May 10, 2019_
|
||||
|
||||
* 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_
|
||||
|
||||
|
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
|
||||
)
|
||||
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",
|
||||
"version": "2.2.8",
|
||||
"version": "2.3.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -35,7 +35,7 @@
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"repository": {
|
||||
@ -48,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -71,17 +71,17 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-erc1155": "^1.1.15",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-erc721": "^2.1.15",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@ -6,30 +6,44 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
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 ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
|
||||
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
|
||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
|
||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||
import * as 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 MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
|
||||
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
|
||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
|
||||
export const artifacts = {
|
||||
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
|
||||
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
|
||||
Ownable: Ownable as ContractArtifact,
|
||||
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
|
||||
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
|
||||
ERC20Proxy: ERC20Proxy as ContractArtifact,
|
||||
ERC721Proxy: ERC721Proxy as ContractArtifact,
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
IAssetData: IAssetData as ContractArtifact,
|
||||
IAssetProxy: IAssetProxy as ContractArtifact,
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher 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,
|
||||
};
|
||||
|
@ -4,15 +4,22 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
export * from '../generated-wrappers/erc20_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_proxy';
|
||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||
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_authorizable';
|
||||
export * from '../generated-wrappers/multi_asset_proxy';
|
||||
export * from '../generated-wrappers/ownable';
|
||||
export * from '../generated-wrappers/static_call_proxy';
|
||||
export * from '../generated-wrappers/test_erc20_bridge';
|
||||
export * from '../generated-wrappers/test_eth2_dai_bridge';
|
||||
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/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
"generated-artifacts/ERC20Proxy.json",
|
||||
"generated-artifacts/ERC721Proxy.json",
|
||||
"generated-artifacts/Eth2DaiBridge.json",
|
||||
"generated-artifacts/IAssetData.json",
|
||||
"generated-artifacts/IAssetProxy.json",
|
||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/IERC20Bridge.json",
|
||||
"generated-artifacts/IEth2Dai.json",
|
||||
"generated-artifacts/IWallet.json",
|
||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MultiAssetProxy.json",
|
||||
"generated-artifacts/Ownable.json",
|
||||
"generated-artifacts/StaticCallProxy.json",
|
||||
"generated-artifacts/TestERC20Bridge.json",
|
||||
"generated-artifacts/TestEth2DaiBridge.json",
|
||||
"generated-artifacts/TestStaticCallTarget.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"version": "2.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add chainId to domain separator",
|
||||
@ -42,7 +42,8 @@
|
||||
"note": "Compile and export all contracts, artifacts, and wrappers by default",
|
||||
"pr": 2055
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "2.0.13",
|
||||
"version": "2.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -71,18 +71,18 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-exchange": "^2.1.14",
|
||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"version": "0.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"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.",
|
||||
"pr": 2075
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,13 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
@ -53,3 +60,5 @@ CHANGELOG
|
||||
* Refactor `LibAssetData` balance/allowance checks to never revert (#1848)
|
||||
* Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848)
|
||||
* 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",
|
||||
"version": "0.0.10",
|
||||
"version": "0.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -49,11 +49,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -72,20 +72,20 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
||||
"@0x/contracts-erc1155": "^1.1.15",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-erc721": "^2.1.15",
|
||||
"@0x/contracts-exchange": "^2.1.14",
|
||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -94,7 +94,7 @@ describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchange);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(multiAssetProxy.address, owner);
|
||||
|
@ -1,12 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "1.1.16",
|
||||
"version": "1.2.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.",
|
||||
"pr": 1819
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.2.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`. (#1819)
|
||||
|
||||
## v1.1.15 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "1.1.15",
|
||||
"version": "1.2.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,10 +48,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -70,14 +70,14 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-test-utils": "^3.2.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "2.3.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "2.2.14",
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.3.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.2.14 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "2.2.14",
|
||||
"version": "2.3.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -47,11 +47,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -69,13 +69,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "2.2.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "2.1.15",
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.2.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.15 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "2.1.15",
|
||||
"version": "2.2.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -71,13 +71,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "3.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "3.0.12",
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.12 - _September 17, 2019_
|
||||
|
||||
* 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 "./libs/LibConstants.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./MixinAssets.sol";
|
||||
|
||||
|
||||
contract MixinExchangeWrapper is
|
||||
LibConstants
|
||||
LibConstants,
|
||||
MixinAssets
|
||||
{
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
@ -57,25 +59,12 @@ contract MixinExchangeWrapper is
|
||||
);
|
||||
|
||||
address exchange = address(EXCHANGE);
|
||||
|
||||
// Call `fillOrder` and handle any exceptions gracefully
|
||||
assembly {
|
||||
let success := call(
|
||||
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)))
|
||||
}
|
||||
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||
if (didSucceed) {
|
||||
assert(returnData.length == 160);
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||
}
|
||||
|
||||
// fillResults values will be 0 by default if call was unsuccessful
|
||||
return fillResults;
|
||||
}
|
||||
@ -98,7 +87,7 @@ contract MixinExchangeWrapper is
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// No fee or percentage fee
|
||||
// No taker fee or percentage fee
|
||||
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.makerAssetData)) {
|
||||
// Attempt to sell the remaining amount of WETH
|
||||
LibFillResults.FillResults memory singleFillResults = _fillOrderNoThrow(
|
||||
@ -107,16 +96,17 @@ contract MixinExchangeWrapper is
|
||||
signature
|
||||
);
|
||||
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount;
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount.safeSub(
|
||||
singleFillResults.takerFeePaid
|
||||
);
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||
.safeSub(singleFillResults.takerFeePaid);
|
||||
// WETH fee
|
||||
} else if (order.takerFeeAssetData.equals(order.takerAssetData)) {
|
||||
|
||||
// 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(
|
||||
order.takerAssetAmount,
|
||||
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.
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount.safeAdd(
|
||||
singleFillResults.takerFeePaid
|
||||
);
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.takerFeePaid)
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
// Unsupported fee
|
||||
@ -161,22 +151,18 @@ contract MixinExchangeWrapper is
|
||||
)
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
|
||||
|
||||
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
|
||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The remaining amount of WETH to sell
|
||||
uint256 remainingTakerAssetFillAmount = wethSellAmount.safeSub(totalWethSpentAmount);
|
||||
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||
.safeSub(totalWethSpentAmount)
|
||||
.safeSub(protocolFee);
|
||||
|
||||
(
|
||||
uint256 wethSpentAmount,
|
||||
@ -187,8 +173,12 @@ contract MixinExchangeWrapper is
|
||||
remainingTakerAssetFillAmount
|
||||
);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount.safeAdd(wethSpentAmount);
|
||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount.safeAdd(makerAssetAcquiredAmount);
|
||||
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount
|
||||
.safeAdd(wethSpentAmount);
|
||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||
.safeAdd(makerAssetAcquiredAmount);
|
||||
|
||||
// Stop execution if the entire amount of WETH has been sold
|
||||
if (totalWethSpentAmount >= wethSellAmount) {
|
||||
@ -215,7 +205,7 @@ contract MixinExchangeWrapper is
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// No fee or WETH fee
|
||||
// No taker fee or WETH fee
|
||||
if (order.takerFee == 0 || order.takerFeeAssetData.equals(order.takerAssetData)) {
|
||||
// Calculate the remaining amount of takerAsset to sell
|
||||
uint256 remainingTakerAssetFillAmount = LibMath.getPartialAmountCeil(
|
||||
@ -231,10 +221,10 @@ contract MixinExchangeWrapper is
|
||||
signature
|
||||
);
|
||||
|
||||
// WETH is also spent on the taker fee, so we add it here.
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount.safeAdd(
|
||||
singleFillResults.takerFeePaid
|
||||
);
|
||||
// WETH is also spent on the protocol and taker fees, so we add it here.
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.takerFeePaid)
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
|
||||
// Percentage fee
|
||||
@ -253,12 +243,12 @@ contract MixinExchangeWrapper is
|
||||
signature
|
||||
);
|
||||
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount;
|
||||
wethSpentAmount = singleFillResults.takerAssetFilledAmount
|
||||
.safeAdd(singleFillResults.protocolFeePaid);
|
||||
|
||||
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount.safeSub(
|
||||
singleFillResults.takerFeePaid
|
||||
);
|
||||
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
|
||||
.safeSub(singleFillResults.takerFeePaid);
|
||||
// Unsupported fee
|
||||
} else {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
|
||||
@ -289,19 +279,13 @@ contract MixinExchangeWrapper is
|
||||
{
|
||||
uint256 ordersLength = orders.length;
|
||||
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
|
||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint256 remainingMakerAssetFillAmount = makerAssetBuyAmount.safeSub(totalMakerAssetAcquiredAmount);
|
||||
uint256 remainingMakerAssetFillAmount = makerAssetBuyAmount
|
||||
.safeSub(totalMakerAssetAcquiredAmount);
|
||||
|
||||
(
|
||||
uint256 wethSpentAmount,
|
||||
@ -312,8 +296,12 @@ contract MixinExchangeWrapper is
|
||||
remainingMakerAssetFillAmount
|
||||
);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount.safeAdd(wethSpentAmount);
|
||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount.safeAdd(makerAssetAcquiredAmount);
|
||||
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount
|
||||
.safeAdd(wethSpentAmount);
|
||||
totalMakerAssetAcquiredAmount = totalMakerAssetAcquiredAmount
|
||||
.safeAdd(makerAssetAcquiredAmount);
|
||||
|
||||
// Stop execution if the entire amount of makerAsset has been bought
|
||||
if (totalMakerAssetAcquiredAmount >= makerAssetBuyAmount) {
|
||||
|
@ -28,7 +28,6 @@ import "./libs/LibConstants.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./interfaces/IAssets.sol";
|
||||
import "./interfaces/IForwarderCore.sol";
|
||||
import "./MixinAssets.sol";
|
||||
import "./MixinExchangeWrapper.sol";
|
||||
import "./MixinWeth.sol";
|
||||
|
||||
@ -38,7 +37,6 @@ contract MixinForwarderCore is
|
||||
IAssets,
|
||||
IForwarderCore,
|
||||
MixinWeth,
|
||||
MixinAssets,
|
||||
MixinExchangeWrapper
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
@ -53,6 +51,11 @@ contract MixinForwarderCore is
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||
}
|
||||
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
|
||||
@ -88,7 +91,8 @@ contract MixinForwarderCore is
|
||||
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,
|
||||
makerAssetAcquiredAmount
|
||||
@ -105,12 +109,6 @@ contract MixinForwarderCore is
|
||||
feePercentage,
|
||||
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.
|
||||
@ -143,9 +141,7 @@ contract MixinForwarderCore is
|
||||
// Convert ETH to WETH.
|
||||
_convertEthToWeth();
|
||||
|
||||
// Attempt to fill the desired amount of makerAsset. Note that makerAssetAcquiredAmount < makerAssetBuyAmount
|
||||
// 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.
|
||||
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
@ -162,11 +158,5 @@ contract MixinForwarderCore is
|
||||
feePercentage,
|
||||
feeRecipient
|
||||
);
|
||||
|
||||
// Transfer acquired assets to msg.sender.
|
||||
_transferAssetToSender(
|
||||
orders[0].makerAssetData,
|
||||
makerAssetAcquiredAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -47,19 +47,19 @@ contract MixinWeth is
|
||||
internal
|
||||
{
|
||||
if (msg.value == 0) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.MsgValueCantEqualZeroError());
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.MsgValueCannotEqualZeroError());
|
||||
}
|
||||
ETHER_TOKEN.deposit.value(msg.value)();
|
||||
}
|
||||
|
||||
/// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
|
||||
/// Refunds any excess ETH to msg.sender.
|
||||
/// @param 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 feeRecipient Address that will receive ETH when orders are filled.
|
||||
/// @return ethFee Amount paid to feeRecipient as a percentage fee on the total WETH sold.
|
||||
function _transferEthFeeAndRefund(
|
||||
uint256 wethSold,
|
||||
uint256 wethSpent,
|
||||
uint256 feePercentage,
|
||||
address payable feeRecipient
|
||||
)
|
||||
@ -73,22 +73,22 @@ contract MixinWeth is
|
||||
));
|
||||
}
|
||||
|
||||
// Ensure that no extra WETH owned by this contract has been sold.
|
||||
if (wethSold > msg.value) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OversoldWethError(
|
||||
wethSold,
|
||||
// Ensure that no extra WETH owned by this contract has been spent.
|
||||
if (wethSpent > msg.value) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||
wethSpent,
|
||||
msg.value
|
||||
));
|
||||
}
|
||||
|
||||
// Calculate amount of WETH that hasn't been sold.
|
||||
uint256 wethRemaining = msg.value.safeSub(wethSold);
|
||||
// Calculate amount of WETH that hasn't been spent.
|
||||
uint256 wethRemaining = msg.value.safeSub(wethSpent);
|
||||
|
||||
// Calculate ETH fee to pay to feeRecipient.
|
||||
ethFee = LibMath.getPartialAmountFloor(
|
||||
feePercentage,
|
||||
PERCENTAGE_DENOMINATOR,
|
||||
wethSold
|
||||
wethSpent
|
||||
);
|
||||
|
||||
// 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-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
|
||||
|
||||
contract LibConstants {
|
||||
|
@ -35,10 +35,6 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
||||
0x91353a0c;
|
||||
|
||||
// bytes4(keccak256("MakerAssetMismatchError(bytes,bytes)"))
|
||||
bytes4 internal constant MAKER_ASSET_MISMATCH_ERROR_SELECTOR =
|
||||
0x56677f2c;
|
||||
|
||||
// bytes4(keccak256("UnsupportedFeeError(bytes)"))
|
||||
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
||||
0x31360af1;
|
||||
@ -51,9 +47,9 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
||||
0xecf40fd9;
|
||||
|
||||
// bytes4(keccak256("OversoldWethError(uint256,uint256)"))
|
||||
bytes4 internal constant OVERSOLD_WETH_ERROR_SELECTOR =
|
||||
0x5cc555c8;
|
||||
// bytes4(keccak256("OverspentWethError(uint256,uint256)"))
|
||||
bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR =
|
||||
0xcdcbed5d;
|
||||
|
||||
// bytes4(keccak256("TransferFailedError(bytes)"))
|
||||
bytes4 internal constant TRANSFER_FAILED_ERROR_SELECTOR =
|
||||
@ -63,9 +59,9 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
|
||||
0x08b18698;
|
||||
|
||||
// bytes4(keccak256("MsgValueCantEqualZeroError()"))
|
||||
bytes4 internal constant MSG_VALUE_CANT_EQUAL_ZERO_ERROR_SELECTOR =
|
||||
0x1213e1d6;
|
||||
// bytes4(keccak256("MsgValueCannotEqualZeroError()"))
|
||||
bytes4 internal constant MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR =
|
||||
0x8c0e562b;
|
||||
|
||||
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
|
||||
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||
@ -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(
|
||||
bytes memory takerFeeAssetData
|
||||
)
|
||||
@ -164,8 +145,8 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function OversoldWethError(
|
||||
uint256 wethSold,
|
||||
function OverspentWethError(
|
||||
uint256 wethSpent,
|
||||
uint256 msgValue
|
||||
)
|
||||
internal
|
||||
@ -173,8 +154,8 @@ library LibForwarderRichErrors {
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
OVERSOLD_WETH_ERROR_SELECTOR,
|
||||
wethSold,
|
||||
OVERSPENT_WETH_ERROR_SELECTOR,
|
||||
wethSpent,
|
||||
msgValue
|
||||
);
|
||||
}
|
||||
@ -205,12 +186,12 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function MsgValueCantEqualZeroError()
|
||||
function MsgValueCannotEqualZeroError()
|
||||
internal
|
||||
pure
|
||||
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(
|
||||
|
@ -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",
|
||||
"version": "3.0.12",
|
||||
"version": "3.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -11,6 +11,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ts": "tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers",
|
||||
"test": "yarn run_mocha",
|
||||
@ -34,7 +35,7 @@
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"repository": {
|
||||
@ -47,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -70,19 +71,19 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-erc721": "^2.1.15",
|
||||
"@0x/contracts-exchange": "^2.1.14",
|
||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -15,6 +15,7 @@ import * as MixinAssets from '../generated-artifacts/MixinAssets.json';
|
||||
import * as MixinExchangeWrapper from '../generated-artifacts/MixinExchangeWrapper.json';
|
||||
import * as MixinForwarderCore from '../generated-artifacts/MixinForwarderCore.json';
|
||||
import * as MixinWeth from '../generated-artifacts/MixinWeth.json';
|
||||
import * as TestProtocolFeeCollector from '../generated-artifacts/TestProtocolFeeCollector.json';
|
||||
export const artifacts = {
|
||||
Forwarder: Forwarder as ContractArtifact,
|
||||
MixinAssets: MixinAssets as ContractArtifact,
|
||||
@ -26,4 +27,5 @@ export const artifacts = {
|
||||
IForwarderCore: IForwarderCore as ContractArtifact,
|
||||
LibConstants: LibConstants 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_forwarder_core';
|
||||
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 { BigNumber } from '@0x/utils';
|
||||
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;
|
||||
|
||||
blockchainTests(ContractName.Forwarder, env => {
|
||||
let chainId: number;
|
||||
let makerAddress: string;
|
||||
let owner: string;
|
||||
let makerAddress: string;
|
||||
let takerAddress: string;
|
||||
let orderFeeRecipientAddress: string;
|
||||
let forwarderFeeRecipientAddress: string;
|
||||
let defaultMakerAssetAddress: string;
|
||||
let wethAssetData: string;
|
||||
|
||||
let weth: DummyERC20TokenContract;
|
||||
let erc20Token: DummyERC20TokenContract;
|
||||
@ -36,22 +39,26 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let forwarderContract: ForwarderContract;
|
||||
let wethContract: WETH9Contract;
|
||||
let exchangeContract: ExchangeContract;
|
||||
let protocolFeeCollector: TestProtocolFeeCollectorContract;
|
||||
|
||||
let forwarderWrapper: ForwarderWrapper;
|
||||
let exchangeWrapper: ExchangeWrapper;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
|
||||
let orderFactory: OrderFactory;
|
||||
let forwarderTestFactory: ForwarderTestFactory;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
let tx: TransactionReceiptWithDecodedLogs;
|
||||
|
||||
let chainId: number;
|
||||
let wethAssetData: string;
|
||||
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 () => {
|
||||
await env.blockchainLifecycle.startAsync();
|
||||
|
||||
chainId = await env.getChainIdAsync();
|
||||
|
||||
// Set up addresses
|
||||
const accounts = await env.getAccountAddressesAsync();
|
||||
const usedAddresses = ([
|
||||
owner,
|
||||
@ -61,24 +68,27 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
forwarderFeeRecipientAddress,
|
||||
] = accounts);
|
||||
|
||||
const erc721Wrapper = new ERC721Wrapper(env.provider, usedAddresses, owner);
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, usedAddresses, owner);
|
||||
|
||||
const numDummyErc20ToDeploy = 2;
|
||||
[erc20Token, secondErc20Token] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
numDummyErc20ToDeploy,
|
||||
constants.DUMMY_TOKEN_DECIMALS,
|
||||
// Set up Exchange
|
||||
chainId = await env.getChainIdAsync();
|
||||
exchangeContract = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
exchangeArtifacts.Exchange,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
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();
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
|
||||
[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(erc20Proxy.address, owner);
|
||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeContract.address, {
|
||||
from: owner,
|
||||
});
|
||||
|
||||
// Set up WETH
|
||||
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(
|
||||
erc20Artifacts.WETH9,
|
||||
env.provider,
|
||||
@ -86,59 +96,72 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
{},
|
||||
);
|
||||
weth = new DummyERC20TokenContract(wethContract.address, env.provider);
|
||||
erc20Wrapper.addDummyTokenContract(weth);
|
||||
|
||||
wethAssetData = assetDataUtils.encodeERC20AssetData(wethContract.address);
|
||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
exchangeArtifacts.Exchange,
|
||||
erc20Wrapper.addDummyTokenContract(weth);
|
||||
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.txDefaults,
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
wethContract.address,
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance, env.provider);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
|
||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
||||
from: owner,
|
||||
});
|
||||
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
||||
from: owner,
|
||||
});
|
||||
await exchangeContract.setProtocolFeeMultiplier.awaitTransactionSuccessAsync(PROTOCOL_FEE_MULTIPLIER);
|
||||
await exchangeContract.setProtocolFeeCollectorAddress.awaitTransactionSuccessAsync(
|
||||
protocolFeeCollector.address,
|
||||
);
|
||||
erc20Wrapper.addTokenOwnerAddress(protocolFeeCollector.address);
|
||||
|
||||
// Set defaults
|
||||
defaultMakerAssetAddress = erc20Token.address;
|
||||
const defaultTakerAssetAddress = wethContract.address;
|
||||
const defaultOrderParams = {
|
||||
makerAddress,
|
||||
feeRecipientAddress: orderFeeRecipientAddress,
|
||||
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(200, DECIMALS_DEFAULT),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(10, DECIMALS_DEFAULT),
|
||||
makerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
makerFee: 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,
|
||||
};
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
|
||||
// Set up Forwarder
|
||||
forwarderContract = await ForwarderContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Forwarder,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
exchangeInstance.address,
|
||||
exchangeContract.address,
|
||||
wethAssetData,
|
||||
);
|
||||
forwarderWrapper = new ForwarderWrapper(forwarderContract, env.provider);
|
||||
|
||||
await forwarderWrapper.approveMakerAssetProxyAsync(defaultOrderParams.makerAssetData, { from: takerAddress });
|
||||
await forwarderWrapper.approveMakerAssetProxyAsync(defaultOrderParams.makerAssetData, {
|
||||
from: takerAddress,
|
||||
});
|
||||
erc20Wrapper.addTokenOwnerAddress(forwarderContract.address);
|
||||
|
||||
// Set up factories
|
||||
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
|
||||
forwarderTestFactory = new ForwarderTestFactory(
|
||||
exchangeWrapper,
|
||||
forwarderWrapper,
|
||||
@ -146,16 +169,18 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
forwarderContract.address,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
protocolFeeCollector.address,
|
||||
orderFeeRecipientAddress,
|
||||
forwarderFeeRecipientAddress,
|
||||
weth.address,
|
||||
gasPrice,
|
||||
GAS_PRICE,
|
||||
PROTOCOL_FEE_MULTIPLIER,
|
||||
);
|
||||
});
|
||||
|
||||
blockchainTests.resets('constructor', () => {
|
||||
it('should revert if assetProxy is unregistered', async () => {
|
||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
exchangeArtifacts.Exchange,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
@ -168,7 +193,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
exchangeInstance.address,
|
||||
exchange.address,
|
||||
wethAssetData,
|
||||
) as any) as sendTransactionResult;
|
||||
|
||||
@ -178,7 +203,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
blockchainTests.resets('marketSellOrdersWithEth without extra fees', () => {
|
||||
it('should fill a single order without a taker fee', async () => {
|
||||
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 () => {
|
||||
const firstOrder = await orderFactory.newSignedOrderAsync();
|
||||
@ -187,14 +212,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(21, DECIMALS_DEFAULT),
|
||||
});
|
||||
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 () => {
|
||||
const orderWithPercentageFee = await orderFactory.newSignedOrderAsync({
|
||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||
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 () => {
|
||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||
@ -208,7 +233,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerFeeAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
|
||||
});
|
||||
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 () => {
|
||||
const unapprovedAsset = assetDataUtils.encodeERC20AssetData(secondErc20Token.address);
|
||||
@ -223,7 +248,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||
|
||||
// Execute test case
|
||||
tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
||||
const tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
||||
value: ethValue,
|
||||
from: takerAddress,
|
||||
});
|
||||
@ -231,7 +256,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
const totalEthSpent = gasPrice.times(tx.gasUsed);
|
||||
const totalEthSpent = GAS_PRICE.times(tx.gasUsed);
|
||||
|
||||
// Validate test case
|
||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||
@ -255,7 +280,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||
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 () => {
|
||||
const firstOrder = await orderFactory.newSignedOrderAsync({
|
||||
@ -269,23 +294,23 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerFeeAssetData: wethAssetData,
|
||||
});
|
||||
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 () => {
|
||||
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);
|
||||
|
||||
tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
||||
const tx = await forwarderWrapper.marketSellOrdersWithEthAsync([order], {
|
||||
value: ethValue,
|
||||
from: 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));
|
||||
});
|
||||
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 firstOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: firstOrderMakerAssetData,
|
||||
@ -295,16 +320,10 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const secondOrder = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetData: secondOrderMakerAssetData,
|
||||
});
|
||||
await forwarderWrapper.approveMakerAssetProxyAsync(secondOrderMakerAssetData, { from: takerAddress });
|
||||
|
||||
const orders = [firstOrder, secondOrder];
|
||||
|
||||
const revertError = new ForwarderRevertErrors.MakerAssetMismatchError(
|
||||
firstOrderMakerAssetData,
|
||||
secondOrderMakerAssetData,
|
||||
);
|
||||
await forwarderTestFactory.marketSellTestAsync(orders, 2, erc20Token, {
|
||||
revertError,
|
||||
});
|
||||
await forwarderTestFactory.marketSellTestAsync(orders, 1.5, [erc20Token, secondErc20Token]);
|
||||
});
|
||||
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);
|
||||
@ -317,14 +336,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
|
||||
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, erc20Token, {
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, [erc20Token], {
|
||||
revertError,
|
||||
});
|
||||
});
|
||||
it('should fill a partially-filled order without a taker fee', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.3, erc20Token);
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.8, erc20Token);
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.3, [erc20Token]);
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.8, [erc20Token]);
|
||||
});
|
||||
it('should skip over an order with an invalid maker asset amount', async () => {
|
||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||
@ -332,7 +351,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
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 () => {
|
||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||
@ -340,7 +359,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
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 () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
@ -349,21 +368,21 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
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 () => {
|
||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder], 1, erc20Token);
|
||||
await forwarderTestFactory.marketSellTestAsync([fullyFilledOrder], 1, [erc20Token]);
|
||||
|
||||
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 () => {
|
||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||
|
||||
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', () => {
|
||||
@ -372,7 +391,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(157, 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),
|
||||
});
|
||||
});
|
||||
@ -383,7 +402,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
ForwarderTestFactory.getPercentageOfValue(constants.PERCENTAGE_DENOMINATOR, forwarderFeePercentage),
|
||||
);
|
||||
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, erc20Token, {
|
||||
await forwarderTestFactory.marketSellTestAsync([order], 0.5, [erc20Token], {
|
||||
forwarderFeePercentage,
|
||||
revertError,
|
||||
});
|
||||
@ -395,7 +414,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(131, 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 () => {
|
||||
const firstOrder = await orderFactory.newSignedOrderAsync();
|
||||
@ -404,14 +423,29 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(11, DECIMALS_DEFAULT),
|
||||
});
|
||||
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 () => {
|
||||
const order = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(80, DECIMALS_DEFAULT),
|
||||
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(17, DECIMALS_DEFAULT),
|
||||
});
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.57, erc20Token, {
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.57, [erc20Token], {
|
||||
ethValueAdjustment: 2,
|
||||
});
|
||||
});
|
||||
@ -422,7 +456,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||
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 () => {
|
||||
const order = await orderFactory.newSignedOrderAsync({
|
||||
@ -431,7 +465,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||
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 () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
@ -440,7 +474,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
constants.ZERO_AMOUNT,
|
||||
);
|
||||
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||
ethValueAdjustment: -2,
|
||||
revertError,
|
||||
});
|
||||
@ -452,7 +486,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
makerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId),
|
||||
takerFeeAssetData: wethAssetData,
|
||||
});
|
||||
await forwarderTestFactory.marketBuyTestAsync([erc721Order], 1, erc721Token, {
|
||||
await forwarderTestFactory.marketBuyTestAsync([erc721Order], 1, [erc721Token], {
|
||||
makerAssetId,
|
||||
});
|
||||
});
|
||||
@ -464,7 +498,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
takerFee: Web3Wrapper.toBaseUnitAmount(1, DECIMALS_DEFAULT),
|
||||
takerFeeAssetData: wethAssetData,
|
||||
});
|
||||
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], 1, erc721Token, {
|
||||
await forwarderTestFactory.marketBuyTestAsync([erc721orderWithWethFee], 1, [erc721Token], {
|
||||
makerAssetId,
|
||||
});
|
||||
});
|
||||
@ -479,14 +513,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
|
||||
const revertError = new ForwarderRevertErrors.UnsupportedFeeError(takerFeeAssetData);
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, erc20Token, {
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.5, [erc20Token], {
|
||||
revertError,
|
||||
});
|
||||
});
|
||||
it('should fill a partially-filled order without a taker fee', async () => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.3, erc20Token);
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.8, erc20Token);
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.3, [erc20Token]);
|
||||
await forwarderTestFactory.marketBuyTestAsync([order], 0.8, [erc20Token]);
|
||||
});
|
||||
it('should skip over an order with an invalid maker asset amount', async () => {
|
||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||
@ -494,7 +528,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
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 () => {
|
||||
const unfillableOrder = await orderFactory.newSignedOrderAsync({
|
||||
@ -502,7 +536,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
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 () => {
|
||||
const currentTimestamp = await getLatestBlockTimestampAsync();
|
||||
@ -511,23 +545,23 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
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 () => {
|
||||
const fullyFilledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder], 1, erc20Token);
|
||||
await forwarderTestFactory.marketBuyTestAsync([fullyFilledOrder], 1, [erc20Token]);
|
||||
|
||||
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 () => {
|
||||
const cancelledOrder = await orderFactory.newSignedOrderAsync();
|
||||
await exchangeWrapper.cancelOrderAsync(cancelledOrder, makerAddress);
|
||||
|
||||
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.
|
||||
// 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.
|
||||
@ -553,13 +587,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
});
|
||||
const desiredMakerAssetFillAmount = new BigNumber('5');
|
||||
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 takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||
|
||||
// Execute test case
|
||||
tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
||||
const tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
||||
value: ethValue,
|
||||
from: takerAddress,
|
||||
});
|
||||
@ -567,8 +602,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(takerAddress);
|
||||
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
const primaryTakerAssetFillAmount = ethValue;
|
||||
const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
|
||||
const totalEthSpent = ethValue.plus(GAS_PRICE.times(tx.gasUsed));
|
||||
// Validate test case
|
||||
expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
|
||||
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);
|
||||
});
|
||||
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.
|
||||
const order = await orderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: new BigNumber('268166666666666666666'),
|
||||
@ -608,7 +644,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
.times(order.makerAssetAmount)
|
||||
.dividedToIntegerBy(order.takerAssetAmount);
|
||||
// Execute test case
|
||||
tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
||||
const tx = await forwarderWrapper.marketBuyOrdersWithEthAsync([order], desiredMakerAssetFillAmount, {
|
||||
value: ethValue,
|
||||
from: takerAddress,
|
||||
});
|
||||
@ -617,7 +653,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const forwarderEthBalance = await env.web3Wrapper.getBalanceInWeiAsync(forwarderContract.address);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
const primaryTakerAssetFillAmount = ethValue;
|
||||
const totalEthSpent = primaryTakerAssetFillAmount.plus(gasPrice.times(tx.gasUsed));
|
||||
const totalEthSpent = primaryTakerAssetFillAmount.plus(GAS_PRICE.times(tx.gasUsed));
|
||||
// Validate test case
|
||||
expect(makerAssetFillAmount).to.be.bignumber.greaterThan(desiredMakerAssetFillAmount);
|
||||
expect(takerEthBalanceAfter).to.be.bignumber.equal(takerEthBalanceBefore.minus(totalEthSpent));
|
||||
@ -643,7 +679,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(125, 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),
|
||||
});
|
||||
});
|
||||
@ -652,7 +688,7 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const revertError = new ForwarderRevertErrors.FeePercentageTooLargeError(
|
||||
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),
|
||||
revertError,
|
||||
});
|
||||
@ -661,14 +697,14 @@ blockchainTests(ContractName.Forwarder, env => {
|
||||
const order = await orderFactory.newSignedOrderAsync();
|
||||
const forwarderFeePercentage = new BigNumber(2);
|
||||
const ethFee = ForwarderTestFactory.getPercentageOfValue(
|
||||
order.takerAssetAmount.times(0.5),
|
||||
order.takerAssetAmount.times(0.5).plus(PROTOCOL_FEE),
|
||||
forwarderFeePercentage,
|
||||
);
|
||||
|
||||
const revertError = new ForwarderRevertErrors.InsufficientEthForFeeError(ethFee, ethFee.minus(1));
|
||||
|
||||
// -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,
|
||||
forwarderFeePercentage,
|
||||
revertError,
|
||||
|
@ -2,118 +2,36 @@ import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
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 { BigNumber, RevertError } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ForwarderWrapper } from './forwarder_wrapper';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
// Necessary bookkeeping to validate Forwarder results
|
||||
interface ForwarderFillState {
|
||||
takerAssetFillAmount: BigNumber;
|
||||
makerAssetFillAmount: BigNumber;
|
||||
makerAssetFillAmount: {
|
||||
[makerAssetData: string]: BigNumber;
|
||||
};
|
||||
protocolFees: BigNumber;
|
||||
wethFees: BigNumber;
|
||||
percentageFees: BigNumber;
|
||||
percentageFees: {
|
||||
[makerAssetData: string]: BigNumber;
|
||||
};
|
||||
maxOversoldWeth: 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
|
||||
function expectBalanceWithin(balance: BigNumber, low: BigNumber, high: BigNumber): void {
|
||||
expect(balance).to.be.bignumber.gte(low);
|
||||
expect(balance).to.be.bignumber.lte(high);
|
||||
function expectBalanceWithin(balance: BigNumber, low: BigNumber, high: BigNumber, message?: string): void {
|
||||
expect(balance, message).to.be.bignumber.gte(low);
|
||||
expect(balance, message).to.be.bignumber.lte(high);
|
||||
}
|
||||
|
||||
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 {
|
||||
const numerator = constants.PERCENTAGE_DENOMINATOR.times(percentage).dividedToIntegerBy(100);
|
||||
const newValue = value.times(numerator).dividedToIntegerBy(constants.PERCENTAGE_DENOMINATOR);
|
||||
@ -121,33 +39,24 @@ export class ForwarderTestFactory {
|
||||
}
|
||||
|
||||
constructor(
|
||||
exchangeWrapper: ExchangeWrapper,
|
||||
forwarderWrapper: ForwarderWrapper,
|
||||
erc20Wrapper: ERC20Wrapper,
|
||||
forwarderAddress: string,
|
||||
makerAddress: string,
|
||||
takerAddress: string,
|
||||
orderFeeRecipientAddress: string,
|
||||
forwarderFeeRecipientAddress: string,
|
||||
wethAddress: string,
|
||||
gasPrice: BigNumber,
|
||||
) {
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
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;
|
||||
}
|
||||
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 _protocolFeeCollectorAddress: string,
|
||||
private readonly _orderFeeRecipientAddress: string,
|
||||
private readonly _forwarderFeeRecipientAddress: string,
|
||||
private readonly _wethAddress: string,
|
||||
private readonly _gasPrice: BigNumber,
|
||||
private readonly _protocolFeeMultiplier: BigNumber,
|
||||
) {}
|
||||
|
||||
public async marketBuyTestAsync(
|
||||
orders: SignedOrder[],
|
||||
fractionalNumberOfOrdersToFill: number,
|
||||
makerAssetContract: DummyERC20TokenContract | DummyERC721TokenContract,
|
||||
makerAssetContracts: Array<DummyERC20TokenContract | DummyERC721TokenContract>,
|
||||
options: {
|
||||
ethValueAdjustment?: number; // Used to provided insufficient/excess ETH
|
||||
forwarderFeePercentage?: BigNumber;
|
||||
@ -167,25 +76,28 @@ export class ForwarderTestFactory {
|
||||
const ordersInfoBefore = await Promise.all(orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)));
|
||||
const orderStatusesBefore = ordersInfoBefore.map(orderInfo => orderInfo.orderStatus);
|
||||
|
||||
const expectedResults = computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
||||
expectedResults.takerAssetFillAmount,
|
||||
forwarderFeePercentage,
|
||||
);
|
||||
const expectedResults = this._computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
||||
const wethSpent = expectedResults.takerAssetFillAmount
|
||||
.plus(expectedResults.protocolFees)
|
||||
.plus(expectedResults.wethFees)
|
||||
.plus(expectedResults.maxOversoldWeth);
|
||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(wethSpent, forwarderFeePercentage);
|
||||
const ethValue = wethSpent.plus(ethSpentOnForwarderFee).plus(ethValueAdjustment);
|
||||
|
||||
const feePercentage = ForwarderTestFactory.getPercentageOfValue(
|
||||
constants.PERCENTAGE_DENOMINATOR,
|
||||
forwarderFeePercentage,
|
||||
);
|
||||
|
||||
const ethValue = expectedResults.takerAssetFillAmount
|
||||
.plus(expectedResults.wethFees)
|
||||
.plus(expectedResults.maxOversoldWeth)
|
||||
.plus(ethSpentOnForwarderFee)
|
||||
.plus(ethValueAdjustment);
|
||||
|
||||
const totalMakerAssetFillAmount = Object.values(expectedResults.makerAssetFillAmount).reduce((prev, current) =>
|
||||
prev.plus(current),
|
||||
);
|
||||
const totalPercentageFees = Object.values(expectedResults.percentageFees).reduce((prev, current) =>
|
||||
prev.plus(current),
|
||||
);
|
||||
const tx = this._forwarderWrapper.marketBuyOrdersWithEthAsync(
|
||||
orders,
|
||||
expectedResults.makerAssetFillAmount.minus(expectedResults.percentageFees),
|
||||
totalMakerAssetFillAmount.minus(totalPercentageFees),
|
||||
{
|
||||
value: ethValue,
|
||||
from: this._takerAddress,
|
||||
@ -210,7 +122,7 @@ export class ForwarderTestFactory {
|
||||
expectedResults,
|
||||
takerEthBalanceBefore,
|
||||
erc20Balances,
|
||||
makerAssetContract,
|
||||
makerAssetContracts,
|
||||
{
|
||||
forwarderFeePercentage,
|
||||
forwarderFeeRecipientEthBalanceBefore,
|
||||
@ -223,7 +135,7 @@ export class ForwarderTestFactory {
|
||||
public async marketSellTestAsync(
|
||||
orders: SignedOrder[],
|
||||
fractionalNumberOfOrdersToFill: number,
|
||||
makerAssetContract: DummyERC20TokenContract,
|
||||
makerAssetContracts: DummyERC20TokenContract[],
|
||||
options: {
|
||||
forwarderFeePercentage?: BigNumber;
|
||||
revertError?: RevertError;
|
||||
@ -240,21 +152,20 @@ export class ForwarderTestFactory {
|
||||
const ordersInfoBefore = await Promise.all(orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)));
|
||||
const orderStatusesBefore = ordersInfoBefore.map(orderInfo => orderInfo.orderStatus);
|
||||
|
||||
const expectedResults = computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
||||
expectedResults.takerAssetFillAmount,
|
||||
forwarderFeePercentage,
|
||||
);
|
||||
const expectedResults = this._computeExpectedResults(orders, ordersInfoBefore, fractionalNumberOfOrdersToFill);
|
||||
const wethSpent = expectedResults.takerAssetFillAmount
|
||||
.plus(expectedResults.protocolFees)
|
||||
.plus(expectedResults.wethFees)
|
||||
.plus(expectedResults.maxOversoldWeth);
|
||||
|
||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(wethSpent, forwarderFeePercentage);
|
||||
const ethValue = wethSpent.plus(ethSpentOnForwarderFee);
|
||||
|
||||
const feePercentage = ForwarderTestFactory.getPercentageOfValue(
|
||||
constants.PERCENTAGE_DENOMINATOR,
|
||||
forwarderFeePercentage,
|
||||
);
|
||||
|
||||
const ethValue = expectedResults.takerAssetFillAmount
|
||||
.plus(expectedResults.wethFees)
|
||||
.plus(expectedResults.maxOversoldWeth)
|
||||
.plus(ethSpentOnForwarderFee);
|
||||
|
||||
const tx = this._forwarderWrapper.marketSellOrdersWithEthAsync(
|
||||
orders,
|
||||
{
|
||||
@ -268,10 +179,9 @@ export class ForwarderTestFactory {
|
||||
await expect(tx).to.revertWith(options.revertError);
|
||||
} else {
|
||||
const gasUsed = (await tx).gasUsed;
|
||||
const ordersInfoAfter = await Promise.all(
|
||||
orders.map(order => this._exchangeWrapper.getOrderInfoAsync(order)),
|
||||
const orderStatusesAfter = await Promise.all(
|
||||
orders.map(async order => (await this._exchangeWrapper.getOrderInfoAsync(order)).orderStatus),
|
||||
);
|
||||
const orderStatusesAfter = ordersInfoAfter.map(orderInfo => orderInfo.orderStatus);
|
||||
|
||||
await this._checkResultsAsync(
|
||||
fractionalNumberOfOrdersToFill,
|
||||
@ -281,7 +191,7 @@ export class ForwarderTestFactory {
|
||||
expectedResults,
|
||||
takerEthBalanceBefore,
|
||||
erc20Balances,
|
||||
makerAssetContract,
|
||||
makerAssetContracts,
|
||||
{
|
||||
forwarderFeePercentage,
|
||||
forwarderFeeRecipientEthBalanceBefore,
|
||||
@ -297,27 +207,39 @@ export class ForwarderTestFactory {
|
||||
makerAssetContract: DummyERC20TokenContract,
|
||||
): void {
|
||||
const makerAssetAddress = makerAssetContract.address;
|
||||
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerAssetAddress);
|
||||
|
||||
const {
|
||||
maxOverboughtMakerAsset,
|
||||
makerAssetFillAmount: { [makerAssetData]: makerAssetFillAmount },
|
||||
percentageFees: { [makerAssetData]: percentageFees },
|
||||
} = expectedResults;
|
||||
|
||||
expectBalanceWithin(
|
||||
newBalances[this._makerAddress][makerAssetAddress],
|
||||
oldBalances[this._makerAddress][makerAssetAddress]
|
||||
.minus(expectedResults.makerAssetFillAmount)
|
||||
.minus(expectedResults.maxOverboughtMakerAsset),
|
||||
oldBalances[this._makerAddress][makerAssetAddress].minus(expectedResults.makerAssetFillAmount),
|
||||
.minus(makerAssetFillAmount)
|
||||
.minus(maxOverboughtMakerAsset),
|
||||
oldBalances[this._makerAddress][makerAssetAddress].minus(makerAssetFillAmount),
|
||||
'Maker makerAsset balance',
|
||||
);
|
||||
expectBalanceWithin(
|
||||
newBalances[this._takerAddress][makerAssetAddress],
|
||||
oldBalances[this._takerAddress][makerAssetAddress].plus(makerAssetFillAmount).minus(percentageFees),
|
||||
oldBalances[this._takerAddress][makerAssetAddress]
|
||||
.plus(expectedResults.makerAssetFillAmount)
|
||||
.minus(expectedResults.percentageFees),
|
||||
oldBalances[this._takerAddress][makerAssetAddress]
|
||||
.plus(expectedResults.makerAssetFillAmount)
|
||||
.minus(expectedResults.percentageFees)
|
||||
.plus(expectedResults.maxOverboughtMakerAsset),
|
||||
.plus(makerAssetFillAmount)
|
||||
.minus(percentageFees)
|
||||
.plus(maxOverboughtMakerAsset),
|
||||
'Taker makerAsset balance',
|
||||
);
|
||||
expect(newBalances[this._orderFeeRecipientAddress][makerAssetAddress]).to.be.bignumber.equal(
|
||||
oldBalances[this._orderFeeRecipientAddress][makerAssetAddress].plus(expectedResults.percentageFees),
|
||||
);
|
||||
expect(newBalances[this._forwarderAddress][makerAssetAddress]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||
expect(
|
||||
newBalances[this._orderFeeRecipientAddress][makerAssetAddress],
|
||||
'Order fee recipient makerAsset balance',
|
||||
).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(
|
||||
@ -328,7 +250,7 @@ export class ForwarderTestFactory {
|
||||
expectedResults: ForwarderFillState,
|
||||
takerEthBalanceBefore: BigNumber,
|
||||
erc20Balances: ERC20BalancesByOwner,
|
||||
makerAssetContract: DummyERC20TokenContract | DummyERC721TokenContract,
|
||||
makerAssetContracts: Array<DummyERC20TokenContract | DummyERC721TokenContract>,
|
||||
options: {
|
||||
forwarderFeePercentage?: BigNumber;
|
||||
forwarderFeeRecipientEthBalanceBefore?: BigNumber;
|
||||
@ -340,18 +262,17 @@ export class ForwarderTestFactory {
|
||||
if (fractionalNumberOfOrdersToFill >= i + 1 && orderStatusesBefore[i] === OrderStatus.Fillable) {
|
||||
expectedOrderStatus = OrderStatus.FullyFilled;
|
||||
}
|
||||
|
||||
expect(orderStatus).to.equal(expectedOrderStatus);
|
||||
expect(orderStatus, ` Order ${i} status`).to.equal(expectedOrderStatus);
|
||||
}
|
||||
|
||||
const wethSpent = expectedResults.takerAssetFillAmount
|
||||
.plus(expectedResults.protocolFees)
|
||||
.plus(expectedResults.wethFees);
|
||||
const ethSpentOnForwarderFee = ForwarderTestFactory.getPercentageOfValue(
|
||||
expectedResults.takerAssetFillAmount,
|
||||
wethSpent,
|
||||
options.forwarderFeePercentage || constants.ZERO_AMOUNT,
|
||||
);
|
||||
const totalEthSpent = expectedResults.takerAssetFillAmount
|
||||
.plus(expectedResults.wethFees)
|
||||
.plus(ethSpentOnForwarderFee)
|
||||
.plus(this._gasPrice.times(gasUsed));
|
||||
const totalEthSpent = wethSpent.plus(ethSpentOnForwarderFee).plus(this._gasPrice.times(gasUsed));
|
||||
|
||||
const takerEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(this._takerAddress);
|
||||
const forwarderEthBalance = await web3Wrapper.getBalanceInWeiAsync(this._forwarderAddress);
|
||||
@ -361,21 +282,24 @@ export class ForwarderTestFactory {
|
||||
takerEthBalanceAfter,
|
||||
takerEthBalanceBefore.minus(totalEthSpent).minus(expectedResults.maxOversoldWeth),
|
||||
takerEthBalanceBefore.minus(totalEthSpent),
|
||||
'Taker ETH balance',
|
||||
);
|
||||
if (options.forwarderFeeRecipientEthBalanceBefore !== undefined) {
|
||||
const fowarderFeeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(
|
||||
this._forwarderFeeRecipientAddress,
|
||||
);
|
||||
expect(fowarderFeeRecipientEthBalanceAfter).to.be.bignumber.equal(
|
||||
expect(fowarderFeeRecipientEthBalanceAfter, 'Forwarder fee recipient ETH balance').to.be.bignumber.equal(
|
||||
options.forwarderFeeRecipientEthBalanceBefore.plus(ethSpentOnForwarderFee),
|
||||
);
|
||||
}
|
||||
|
||||
if (makerAssetContract instanceof DummyERC20TokenContract) {
|
||||
this._checkErc20Balances(erc20Balances, newBalances, expectedResults, makerAssetContract);
|
||||
} else if (options.makerAssetId !== undefined) {
|
||||
const newOwner = await makerAssetContract.ownerOf.callAsync(options.makerAssetId);
|
||||
expect(newOwner).to.be.bignumber.equal(this._takerAddress);
|
||||
for (const makerAssetContract of makerAssetContracts) {
|
||||
if (makerAssetContract instanceof DummyERC20TokenContract) {
|
||||
this._checkErc20Balances(erc20Balances, newBalances, expectedResults, makerAssetContract);
|
||||
} else if (options.makerAssetId !== undefined) {
|
||||
const newOwner = await makerAssetContract.ownerOf.callAsync(options.makerAssetId);
|
||||
expect(newOwner, 'New ERC721 owner').to.be.bignumber.equal(this._takerAddress);
|
||||
}
|
||||
}
|
||||
|
||||
expectBalanceWithin(
|
||||
@ -384,12 +308,108 @@ export class ForwarderTestFactory {
|
||||
erc20Balances[this._makerAddress][this._wethAddress]
|
||||
.plus(expectedResults.takerAssetFillAmount)
|
||||
.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),
|
||||
);
|
||||
|
||||
expect(newBalances[this._forwarderAddress][this._wethAddress]).to.be.bignumber.equal(constants.ZERO_AMOUNT);
|
||||
expect(
|
||||
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);
|
||||
}
|
||||
|
||||
// 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/MixinExchangeWrapper.json",
|
||||
"generated-artifacts/MixinForwarderCore.json",
|
||||
"generated-artifacts/MixinWeth.json"
|
||||
"generated-artifacts/MixinWeth.json",
|
||||
"generated-artifacts/TestProtocolFeeCollector.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Break up `LibEIP712` into reusable components",
|
||||
@ -106,7 +106,8 @@
|
||||
"note": "Update `IncompleteFillError` to take an `errorCode`, `expectedAssetFillAmount`, and `actualAssetFillAmount` fields.",
|
||||
"pr": 2075
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,35 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "3.0.8",
|
||||
"version": "3.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,12 +48,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/subproviders": "^5.0.1",
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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/subproviders": "^5.1.0-beta.0",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -73,14 +73,14 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "3.0.0",
|
||||
"version": "2.2.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use new/cheaper reentrancy guard/mutex",
|
||||
@ -190,7 +190,8 @@
|
||||
"note": "Overridden functions in `ReentrancyTester` now return sane values.",
|
||||
"pr": 2075
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,56 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "2.1.14",
|
||||
"version": "2.2.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,11 +48,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@0x/contracts-multisig": "^3.2.0-beta.0",
|
||||
"@0x/contracts-staking": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -71,19 +73,19 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
||||
"@0x/contracts-erc1155": "^1.1.15",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-erc721": "^2.1.15",
|
||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc1155": "^1.2.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@ -1,3 +1,4 @@
|
||||
export * from './artifacts';
|
||||
export * from './wrappers';
|
||||
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 });
|
||||
|
||||
// Configure Exchange
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.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),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, owner);
|
||||
|
@ -96,7 +96,7 @@ blockchainTests.resets('Exchange transactions', env => {
|
||||
{},
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance, env.provider);
|
||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, 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 {
|
||||
BatchMatchedFillResults,
|
||||
FillResults,
|
||||
@ -8,7 +8,7 @@ import {
|
||||
SignedZeroExTransaction,
|
||||
} from '@0x/types';
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
import { MethodAbi, TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
|
||||
import { MethodAbi, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ExchangeContract } from '../../src';
|
||||
@ -16,18 +16,15 @@ import { ExchangeContract } from '../../src';
|
||||
import { AbiDecodedFillOrderData } from './types';
|
||||
|
||||
export class ExchangeWrapper {
|
||||
private readonly _exchange: ExchangeContract;
|
||||
// tslint:disable no-unused-variable
|
||||
constructor(exchangeContract: ExchangeContract, provider: Web3ProviderEngine | ZeroExProvider) {
|
||||
this._exchange = exchangeContract;
|
||||
}
|
||||
constructor(public readonly exchangeContract: ExchangeContract) {}
|
||||
|
||||
public async fillOrderAsync(
|
||||
signedOrder: SignedOrder,
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const txReceipt = await this._exchange.fillOrder.awaitTransactionSuccessAsync(
|
||||
const txReceipt = await this.exchangeContract.fillOrder.awaitTransactionSuccessAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
@ -37,7 +34,7 @@ export class ExchangeWrapper {
|
||||
}
|
||||
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
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;
|
||||
}
|
||||
public async fillOrKillOrderAsync(
|
||||
@ -46,7 +43,7 @@ export class ExchangeWrapper {
|
||||
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const txReceipt = await this._exchange.fillOrKillOrder.awaitTransactionSuccessAsync(
|
||||
const txReceipt = await this.exchangeContract.fillOrKillOrder.awaitTransactionSuccessAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
@ -59,7 +56,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchFillOrders.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchFillOrders.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.takerAssetFillAmounts === undefined
|
||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||
@ -73,7 +70,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchFillOrKillOrders.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchFillOrKillOrders.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.takerAssetFillAmounts === undefined
|
||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||
@ -87,7 +84,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number; gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchFillOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchFillOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.takerAssetFillAmounts === undefined
|
||||
? orders.map(signedOrder => signedOrder.takerAssetAmount)
|
||||
@ -101,7 +98,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.marketSellOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.marketSellOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.takerAssetFillAmount,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
@ -113,7 +110,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.makerAssetFillAmount,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
@ -125,7 +122,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { takerAssetFillAmount: BigNumber; gas?: number },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.marketSellOrdersFillOrKill.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.marketSellOrdersFillOrKill.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.takerAssetFillAmount,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
@ -137,7 +134,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { makerAssetFillAmount: BigNumber; gas?: number },
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.marketBuyOrdersFillOrKill.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.marketBuyOrdersFillOrKill.awaitTransactionSuccessAsync(
|
||||
orders,
|
||||
opts.makerAssetFillAmount,
|
||||
orders.map(signedOrder => signedOrder.signature),
|
||||
@ -148,19 +145,22 @@ export class ExchangeWrapper {
|
||||
orders: SignedOrder[],
|
||||
from: string,
|
||||
): 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> {
|
||||
const txReceipt = await this._exchange.cancelOrdersUpTo.awaitTransactionSuccessAsync(salt, { from });
|
||||
const txReceipt = await this.exchangeContract.cancelOrdersUpTo.awaitTransactionSuccessAsync(salt, { from });
|
||||
return txReceipt;
|
||||
}
|
||||
public async registerAssetProxyAsync(
|
||||
assetProxyAddress: string,
|
||||
from: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const txReceipt = await this._exchange.registerAssetProxy.awaitTransactionSuccessAsync(assetProxyAddress, {
|
||||
from,
|
||||
});
|
||||
const txReceipt = await this.exchangeContract.registerAssetProxy.awaitTransactionSuccessAsync(
|
||||
assetProxyAddress,
|
||||
{
|
||||
from,
|
||||
},
|
||||
);
|
||||
return txReceipt;
|
||||
}
|
||||
public async executeTransactionAsync(
|
||||
@ -168,7 +168,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.executeTransaction.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.executeTransaction.awaitTransactionSuccessAsync(
|
||||
signedTransaction,
|
||||
signedTransaction.signature,
|
||||
{ from, gasPrice: opts.gasPrice },
|
||||
@ -180,25 +180,29 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const signatures = signedTransactions.map(signedTransaction => signedTransaction.signature);
|
||||
return this._exchange.batchExecuteTransactions.awaitTransactionSuccessAsync(signedTransactions, signatures, {
|
||||
from,
|
||||
gasPrice: opts.gasPrice,
|
||||
});
|
||||
return this.exchangeContract.batchExecuteTransactions.awaitTransactionSuccessAsync(
|
||||
signedTransactions,
|
||||
signatures,
|
||||
{
|
||||
from,
|
||||
gasPrice: opts.gasPrice,
|
||||
},
|
||||
);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
public async batchMatchOrdersAsync(
|
||||
@ -208,7 +212,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
return this._exchange.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
@ -221,7 +225,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchMatchOrders.awaitTransactionSuccessAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
@ -236,7 +240,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<BatchMatchedFillResults> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
const batchMatchedFillResults = await this._exchange.batchMatchOrders.callAsync(
|
||||
const batchMatchedFillResults = await this.exchangeContract.batchMatchOrders.callAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
@ -252,7 +256,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
return this._exchange.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
@ -265,7 +269,7 @@ export class ExchangeWrapper {
|
||||
from: string,
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
return this._exchange.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.batchMatchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
@ -280,7 +284,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<BatchMatchedFillResults> {
|
||||
const params = orderUtils.createBatchMatchOrders(signedOrdersLeft, signedOrdersRight);
|
||||
const batchMatchedFillResults = await this._exchange.batchMatchOrdersWithMaximalFill.callAsync(
|
||||
const batchMatchedFillResults = await this.exchangeContract.batchMatchOrdersWithMaximalFill.callAsync(
|
||||
params.leftOrders,
|
||||
params.rightOrders,
|
||||
params.leftSignatures,
|
||||
@ -296,7 +300,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const txReceipt = await this._exchange.matchOrders.awaitTransactionSuccessAsync(
|
||||
const txReceipt = await this.exchangeContract.matchOrders.awaitTransactionSuccessAsync(
|
||||
params.left,
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
@ -312,7 +316,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<MatchedFillResults> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const matchedFillResults = await this._exchange.matchOrders.callAsync(
|
||||
const matchedFillResults = await this.exchangeContract.matchOrders.callAsync(
|
||||
params.left,
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
@ -328,7 +332,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber } = {},
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
return this._exchange.matchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
return this.exchangeContract.matchOrdersWithMaximalFill.awaitTransactionSuccessAsync(
|
||||
params.left,
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
@ -343,7 +347,7 @@ export class ExchangeWrapper {
|
||||
opts: { gasPrice?: BigNumber },
|
||||
): Promise<MatchedFillResults> {
|
||||
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
|
||||
const matchedFillResults = await this._exchange.matchOrdersWithMaximalFill.callAsync(
|
||||
const matchedFillResults = await this.exchangeContract.matchOrdersWithMaximalFill.callAsync(
|
||||
params.left,
|
||||
params.right,
|
||||
params.leftSignature,
|
||||
@ -358,7 +362,7 @@ export class ExchangeWrapper {
|
||||
opts: { takerAssetFillAmount?: BigNumber; gasPrice?: BigNumber } = {},
|
||||
): Promise<FillResults> {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const fillResults = await this._exchange.fillOrder.callAsync(
|
||||
const fillResults = await this.exchangeContract.fillOrder.callAsync(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
@ -368,7 +372,7 @@ export class ExchangeWrapper {
|
||||
}
|
||||
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
|
||||
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
|
||||
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
|
||||
const data = this.exchangeContract.fillOrder.getABIEncodedTransactionData(
|
||||
params.order,
|
||||
params.takerAssetFillAmount,
|
||||
params.signature,
|
||||
@ -377,13 +381,10 @@ export class ExchangeWrapper {
|
||||
}
|
||||
public abiDecodeFillOrder(data: string): AbiDecodedFillOrderData {
|
||||
// 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
|
||||
const abiEncoder = new AbiEncoder.Method(fillOrderAbi);
|
||||
const decodedData = abiEncoder.decode(data) as AbiDecodedFillOrderData;
|
||||
return decodedData;
|
||||
}
|
||||
public getExchangeAddress(): string {
|
||||
return this._exchange.address;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync(
|
||||
);
|
||||
|
||||
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(erc721Proxy.address, ownerAddress);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc1155Proxy.address, ownerAddress);
|
||||
@ -646,7 +646,7 @@ export class FillOrderCombinatorialUtils {
|
||||
|
||||
const exchangeLogs = _.filter(
|
||||
txReceipt.logs,
|
||||
txLog => txLog.address === this.exchangeWrapper.getExchangeAddress(),
|
||||
txLog => txLog.address === this.exchangeWrapper.exchangeContract.address,
|
||||
);
|
||||
expect(exchangeLogs.length).to.be.equal(1, 'logs length');
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
|
@ -78,7 +78,7 @@ blockchainTests.resets('Exchange wrappers', env => {
|
||||
from: owner,
|
||||
});
|
||||
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, env.provider);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
|
||||
await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(exchange.address, {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "4.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "4.0.8",
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.8 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
@ -40,6 +44,9 @@ CHANGELOG
|
||||
## v4.0.0 - _July 13, 2019_
|
||||
|
||||
* 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_
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "4.0.8",
|
||||
"version": "4.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -71,19 +71,19 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-erc721": "^2.1.15",
|
||||
"@0x/contracts-exchange": "^2.1.14",
|
||||
"@0x/contracts-exchange-libs": "^3.0.8",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc721": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange": "^2.2.0-beta.0",
|
||||
"@0x/contracts-exchange-libs": "^3.1.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -136,7 +136,7 @@ describe(ContractName.BalanceThresholdFilter, () => {
|
||||
zrxAssetData,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
|
||||
exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||
// Register proxies
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
|
||||
|
@ -95,7 +95,7 @@ describe(ContractName.DutchAuction, () => {
|
||||
zrxAssetData,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
|
||||
const exchangeWrapper = new ExchangeWrapper(exchangeInstance);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
|
||||
|
@ -115,7 +115,7 @@ describe('OrderMatcher', () => {
|
||||
assetDataUtils.encodeERC20AssetData(zrxToken.address),
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange, provider);
|
||||
exchangeWrapper = new ExchangeWrapper(exchange);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
|
||||
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
|
||||
// Authorize ERC20 trades by exchange
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "3.2.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "3.1.14",
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.14 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-multisig",
|
||||
"version": "3.1.14",
|
||||
"version": "3.2.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -47,11 +47,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
@ -69,15 +69,15 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.8",
|
||||
"@0x/contracts-erc20": "^2.2.14",
|
||||
"@0x/contracts-utils": "^3.2.4",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Created package",
|
||||
@ -70,6 +70,7 @@
|
||||
"note": "Removed explicit dependency on epoch+1 when delegating.",
|
||||
"pr": 2188
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
}
|
||||
]
|
||||
|
@ -4,3 +4,23 @@ Edit the package's CHANGELOG.json file only.
|
||||
-->
|
||||
|
||||
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",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -49,13 +49,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.1.0",
|
||||
"@0x/contracts-gen": "^1.0.13",
|
||||
"@0x/contracts-test-utils": "^3.1.2",
|
||||
"@0x/dev-utils": "^2.2.1",
|
||||
"@0x/sol-compiler": "^3.1.6",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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/utils": "^4.3.1",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/node": "*",
|
||||
"chai": "^4.0.1",
|
||||
@ -74,16 +74,16 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.1.0",
|
||||
"@0x/contracts-asset-proxy": "^2.2.5",
|
||||
"@0x/contracts-erc20": "^2.2.0",
|
||||
"@0x/contracts-utils": "^3.2.1",
|
||||
"@0x/order-utils": "^8.1.0",
|
||||
"@0x/types": "^2.2.2",
|
||||
"@0x/typescript-typings": "^4.2.2",
|
||||
"@0x/utils": "^4.3.1",
|
||||
"@0x/web3-wrapper": "^6.0.6",
|
||||
"ethereum-types": "^2.1.2",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contracts-asset-proxy": "^2.3.0-beta.0",
|
||||
"@0x/contracts-erc20": "^2.3.0-beta.0",
|
||||
"@0x/contracts-utils": "^3.3.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "4.0.0",
|
||||
"version": "3.2.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add `chainId` to `TransactionFactory` constructor",
|
||||
@ -93,8 +93,13 @@
|
||||
{
|
||||
"note": "Add `shortZip()` to `lang_utils.ts`",
|
||||
"pr": 2155
|
||||
},
|
||||
{
|
||||
"note": "Add `number_utils.ts` and `hexSize()`",
|
||||
"pr": 2220
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,33 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "3.1.16",
|
||||
"version": "3.2.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -34,41 +34,41 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/test-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.7",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/sol-coverage": "^3.0.12",
|
||||
"@0x/sol-profiler": "^3.1.14",
|
||||
"@0x/sol-trace": "^2.0.20",
|
||||
"@0x/subproviders": "^5.0.4",
|
||||
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/sol-compiler": "^3.2.0-beta.0",
|
||||
"@0x/sol-coverage": "^3.1.0-beta.0",
|
||||
"@0x/sol-profiler": "^3.2.0-beta.0",
|
||||
"@0x/sol-trace": "^2.1.0-beta.0",
|
||||
"@0x/subproviders": "^5.1.0-beta.0",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/js-combinatorics": "^0.5.29",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"bn.js": "^4.11.8",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"ethers": "~4.0.4",
|
||||
"js-combinatorics": "^0.5.3",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0"
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -65,6 +65,13 @@ export function hexHash(n: Numberish): string {
|
||||
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.
|
||||
* Works with negative numbers, as well.
|
||||
|
@ -28,7 +28,17 @@ export { bytes32Values, testCombinatoriallyWithReferenceFunc, uint256Values } fr
|
||||
export { TransactionFactory } from './transaction_factory';
|
||||
export { MutatorContractFunction, TransactionHelper } from './transaction_helper';
|
||||
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 {
|
||||
BatchMatchOrder,
|
||||
ContractName,
|
||||
@ -51,3 +61,12 @@ export { blockchainTests, BlockchainTestsEnvironment, describe } from './mocha_b
|
||||
export { chaiSetup, expect } from './chai_setup';
|
||||
export { getCodesizeFromArtifact } from './codesize';
|
||||
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 { TxData, Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
// Import ambient declarations (and clobber Jest).
|
||||
import 'mocha';
|
||||
import * as mocha from 'mocha';
|
||||
import * as process from 'process';
|
||||
|
||||
import { provider, txDefaults, web3Wrapper } from './web3_wrapper';
|
||||
|
||||
// tslint:disable: no-namespace only-arrow-functions no-unbound-method
|
||||
|
||||
export type ISuite = Mocha.ISuite;
|
||||
export type ISuiteCallbackContext = Mocha.ISuiteCallbackContext;
|
||||
export type ISuite = mocha.ISuite;
|
||||
export type ISuiteCallbackContext = mocha.ISuiteCallbackContext;
|
||||
export type SuiteCallback = (this: ISuiteCallbackContext) => void;
|
||||
export type ContextDefinitionCallback<T> = (description: string, callback: SuiteCallback) => T;
|
||||
export type BlockchainSuiteCallback = (this: ISuiteCallbackContext, env: BlockchainTestsEnvironment) => void;
|
||||
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>;
|
||||
}
|
||||
|
||||
@ -88,10 +87,10 @@ export class BlockchainTestsEnvironmentSingleton {
|
||||
}
|
||||
|
||||
// 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, {
|
||||
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 currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
||||
const order = ({
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
senderAddress: constants.NULL_ADDRESS,
|
||||
expirationTimeSeconds: new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds),
|
||||
salt: generatePseudoRandomSalt(),
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
...this._defaultOrderParams,
|
||||
...customOrderParams,
|
||||
} as any) as Order;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "3.2.5",
|
||||
"version": "3.3.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Change ReentrancyGuard implementation to cheaper one",
|
||||
@ -62,7 +62,8 @@
|
||||
"note": "Introduce automatic normalization and some zero-value shortcuts in `LibFractions`.",
|
||||
"pr": 2155
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
|
@ -5,6 +5,24 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* Dependencies updated
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "3.2.4",
|
||||
"version": "3.3.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -48,11 +48,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/contracts-gen": "^1.0.15",
|
||||
"@0x/contracts-test-utils": "^3.1.16",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/sol-compiler": "^3.1.15",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/contracts-gen": "^1.1.0-beta.0",
|
||||
"@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",
|
||||
"@types/bn.js": "^4.11.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
@ -72,14 +72,14 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"bn.js": "^4.11.8",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"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:local": "IS_LOCAL_PUBLISH=true yarn run:publish",
|
||||
"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",
|
||||
"wsrun": "wsrun",
|
||||
"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: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",
|
||||
@ -65,7 +65,7 @@
|
||||
},
|
||||
{
|
||||
"path": "packages/instant/umd/instant.js",
|
||||
"maxSize": "1460kB"
|
||||
"maxSize": "1960kB"
|
||||
}
|
||||
],
|
||||
"ci": {
|
||||
|
@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "7.1.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Updated to work with 0x v3"
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"timestamp": 1568744790,
|
||||
"version": "7.0.2",
|
||||
|
@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v7.1.0-beta.0 - _October 3, 2019_
|
||||
|
||||
* Updated to work with 0x v3
|
||||
|
||||
## v7.0.2 - _September 17, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "7.0.2",
|
||||
"version": "7.1.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -46,9 +46,9 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@0x/contract-addresses": "^3.2.0",
|
||||
"@0x/dev-utils": "^2.3.3",
|
||||
"@0x/migrations": "^4.3.2",
|
||||
"@0x/contract-addresses": "^3.3.0-beta.0",
|
||||
"@0x/dev-utils": "^2.4.0-beta.0",
|
||||
"@0x/migrations": "^4.4.0-beta.0",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
@ -77,19 +77,19 @@
|
||||
"webpack": "^4.20.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/abi-gen-wrappers": "^5.3.2",
|
||||
"@0x/assert": "^2.1.6",
|
||||
"@0x/asset-swapper": "^2.0.0",
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contract-wrappers": "^12.1.0",
|
||||
"@0x/order-utils": "^8.4.0",
|
||||
"@0x/subproviders": "^5.0.4",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/typescript-typings": "^4.3.0",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"@0x/abi-gen-wrappers": "^5.4.0-beta.0",
|
||||
"@0x/assert": "^2.2.0-beta.0",
|
||||
"@0x/asset-swapper": "^2.1.0-beta.0",
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contract-wrappers": "^12.2.0-beta.0",
|
||||
"@0x/order-utils": "^8.5.0-beta.0",
|
||||
"@0x/subproviders": "^5.1.0-beta.0",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/typescript-typings": "^4.4.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"@types/web3-provider-engine": "^14.0.0",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethers": "~4.0.4",
|
||||
"lodash": "^4.17.11",
|
||||
"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 {
|
||||
assetDataUtils,
|
||||
@ -8,21 +8,6 @@ export {
|
||||
transactionHashUtils,
|
||||
} from '@0x/order-utils';
|
||||
|
||||
export {
|
||||
ContractWrappers,
|
||||
CoordinatorWrapper,
|
||||
CoordinatorServerCancellationResponse,
|
||||
CoordinatorServerError,
|
||||
IndexedFilterValues,
|
||||
ContractWrappersConfig,
|
||||
OrderTransactionOpts,
|
||||
TransactionOpts,
|
||||
OrderInfo,
|
||||
EventCallback,
|
||||
DecodedLogEvent,
|
||||
OrderStatus,
|
||||
} from '@0x/contract-wrappers';
|
||||
|
||||
export {
|
||||
ExchangeEventArgs,
|
||||
ExchangeEvents,
|
||||
@ -33,13 +18,6 @@ export {
|
||||
ExchangeAssetProxyRegisteredEventArgs,
|
||||
ExchangeContract,
|
||||
DevUtilsContract,
|
||||
ForwarderContract,
|
||||
DutchAuctionContract,
|
||||
CoordinatorContract,
|
||||
CoordinatorRegistryEventArgs,
|
||||
CoordinatorRegistryEvents,
|
||||
CoordinatorRegistryCoordinatorEndpointSetEventArgs,
|
||||
CoordinatorRegistryContract,
|
||||
IValidatorContract,
|
||||
IWalletContract,
|
||||
WETH9EventArgs,
|
||||
@ -60,38 +38,14 @@ export {
|
||||
ERC721TokenApprovalEventArgs,
|
||||
ERC721TokenApprovalForAllEventArgs,
|
||||
ERC721TokenContract,
|
||||
ERC1155ProxyEventArgs,
|
||||
ERC1155ProxyEvents,
|
||||
ERC1155ProxyAuthorizedAddressAddedEventArgs,
|
||||
ERC1155ProxyAuthorizedAddressRemovedEventArgs,
|
||||
ERC1155ProxyContract,
|
||||
ZRXTokenEventArgs,
|
||||
ZRXTokenEvents,
|
||||
ZRXTokenTransferEventArgs,
|
||||
ZRXTokenApprovalEventArgs,
|
||||
ZRXTokenContract,
|
||||
DummyERC20TokenEventArgs,
|
||||
DummyERC20TokenEvents,
|
||||
DummyERC20TokenTransferEventArgs,
|
||||
DummyERC20TokenApprovalEventArgs,
|
||||
DummyERC20TokenContract,
|
||||
DummyERC721TokenEventArgs,
|
||||
DummyERC721TokenEvents,
|
||||
DummyERC721TokenTransferEventArgs,
|
||||
DummyERC721TokenApprovalEventArgs,
|
||||
DummyERC721TokenApprovalForAllEventArgs,
|
||||
DummyERC721TokenContract,
|
||||
ERC20ProxyEventArgs,
|
||||
ERC20ProxyEvents,
|
||||
ERC20ProxyContract,
|
||||
ERC20ProxyAuthorizedAddressAddedEventArgs,
|
||||
ERC20ProxyAuthorizedAddressRemovedEventArgs,
|
||||
ERC721ProxyEventArgs,
|
||||
ERC721ProxyEvents,
|
||||
ERC721ProxyAuthorizedAddressAddedEventArgs,
|
||||
ERC721ProxyAuthorizedAddressRemovedEventArgs,
|
||||
ERC721ProxyContract,
|
||||
OrderValidatorContract,
|
||||
ExchangeProtocolFeeCollectorAddressEventArgs,
|
||||
ExchangeProtocolFeeMultiplierEventArgs,
|
||||
ExchangeTransactionExecutionEventArgs,
|
||||
} from '@0x/abi-gen-wrappers';
|
||||
|
||||
export import Web3ProviderEngine = require('web3-provider-engine');
|
||||
@ -104,7 +58,7 @@ export {
|
||||
MetamaskSubprovider,
|
||||
} from '@0x/subproviders';
|
||||
|
||||
export { AbiDecoder, DecodedCalldata, BigNumber } from '@0x/utils';
|
||||
export { DecodedCalldata, BigNumber } from '@0x/utils';
|
||||
|
||||
export {
|
||||
Order,
|
||||
@ -128,23 +82,20 @@ export {
|
||||
SimpleStandardContractOutput,
|
||||
SimpleEvmOutput,
|
||||
SimpleEvmBytecodeOutput,
|
||||
EIP712DomainWithDefaultSchema,
|
||||
EventCallback,
|
||||
IndexedFilterValues,
|
||||
DecodedLogEvent,
|
||||
} from '@0x/types';
|
||||
|
||||
export {
|
||||
BlockRange,
|
||||
ContractAbi,
|
||||
LogWithDecodedArgs,
|
||||
ContractEventArg,
|
||||
SupportedProvider,
|
||||
JSONRPCRequestPayload,
|
||||
JSONRPCResponsePayload,
|
||||
JSONRPCResponseError,
|
||||
LogEntry,
|
||||
DecodedLogArgs,
|
||||
LogEntryEvent,
|
||||
DecodedLogEntry,
|
||||
DecodedLogEntryEvent,
|
||||
RawLog,
|
||||
AbiDefinition,
|
||||
FunctionAbi,
|
||||
EventAbi,
|
||||
@ -183,4 +134,7 @@ export {
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
EvmBytecodeOutput,
|
||||
RevertErrorAbi,
|
||||
DecodedLogArgs,
|
||||
LogWithDecodedArgs,
|
||||
} from 'ethereum-types';
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "6.0.0",
|
||||
"version": "5.4.0-beta.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use V3 contracts",
|
||||
@ -10,7 +10,8 @@
|
||||
"note": "Hardcode bytecode for local EVM execution",
|
||||
"pr": 2198
|
||||
}
|
||||
]
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
},
|
||||
{
|
||||
"version": "5.3.2",
|
||||
|
@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
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_
|
||||
|
||||
* 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_
|
||||
|
||||
* Update Coordinator and Exchange wrappers (#1742)
|
||||
* Update wrapper functions to expose `awaitTransactionSuccessAsync()` methods (#1797)
|
||||
* Update wrappers to automatically throw `RevertError` types when possible. (#1819)
|
||||
|
||||
## v4.2.0 - _April 11, 2019_
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/abi-gen-wrappers",
|
||||
"version": "5.3.2",
|
||||
"version": "5.4.0-beta.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@ -33,22 +33,22 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^4.2.1",
|
||||
"@0x/assert": "^2.1.6",
|
||||
"@0x/json-schemas": "^4.0.2",
|
||||
"@0x/abi-gen": "^4.3.0-beta.0",
|
||||
"@0x/assert": "^2.2.0-beta.0",
|
||||
"@0x/json-schemas": "^4.1.0-beta.0",
|
||||
"@0x/tslint-config": "^3.0.1",
|
||||
"@0x/types": "^2.4.3",
|
||||
"@0x/utils": "^4.5.2",
|
||||
"@0x/web3-wrapper": "^6.0.13",
|
||||
"ethereum-types": "^2.1.6",
|
||||
"@0x/types": "^2.5.0-beta.0",
|
||||
"@0x/utils": "^4.6.0-beta.0",
|
||||
"@0x/web3-wrapper": "^6.1.0-beta.0",
|
||||
"ethereum-types": "^2.2.0-beta.0",
|
||||
"ethers": "~4.0.4",
|
||||
"lodash": "^4.17.11",
|
||||
"shx": "^0.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^5.4.0",
|
||||
"@0x/contract-addresses": "^3.2.0",
|
||||
"@0x/contract-artifacts": "^2.2.2"
|
||||
"@0x/base-contract": "^5.5.0-beta.0",
|
||||
"@0x/contract-addresses": "^3.3.0-beta.0",
|
||||
"@0x/contract-artifacts": "^2.3.0-beta.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
File diff suppressed because one or more lines are too long
@ -18,7 +18,7 @@ import {
|
||||
SupportedProvider,
|
||||
} from 'ethereum-types';
|
||||
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 { assert } from '@0x/assert';
|
||||
import * as ethers from 'ethers';
|
||||
|
@ -1,13 +1,7 @@
|
||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma
|
||||
// tslint:disable:whitespace no-unbound-method no-trailing-whitespace
|
||||
// tslint:disable:no-unused-variable
|
||||
import {
|
||||
BaseContract,
|
||||
EventCallback,
|
||||
IndexedFilterValues,
|
||||
SubscriptionManager,
|
||||
PromiseWithTransactionHash,
|
||||
} from '@0x/base-contract';
|
||||
import { BaseContract, SubscriptionManager, PromiseWithTransactionHash } from '@0x/base-contract';
|
||||
import { schemas } from '@0x/json-schemas';
|
||||
import {
|
||||
BlockParam,
|
||||
@ -25,7 +19,7 @@ import {
|
||||
SupportedProvider,
|
||||
} from 'ethereum-types';
|
||||
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 { assert } from '@0x/assert';
|
||||
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