Compare commits
36 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
5d603b2f80 | ||
|
0e1b08ff54 | ||
|
befc22d718 | ||
|
4a62e80967 | ||
|
ee9ef9f2c1 | ||
|
93dcb68437 | ||
|
0691cc7909 | ||
|
d82f34fe59 | ||
|
d2313b30af | ||
|
329719472a | ||
|
a2fcab47d4 | ||
|
4ab5951c25 | ||
|
403cabb201 | ||
|
3da7c5d3e2 | ||
|
c5e0de51aa | ||
|
c581f1bba4 | ||
|
b8ac9c2edd | ||
|
1027ee2481 | ||
|
2f311f7821 | ||
|
a98c95b514 | ||
|
5bbbae5b23 | ||
|
f9c9b9f924 | ||
|
5921208ea6 | ||
|
f89c78abd1 | ||
|
74d3b9334c | ||
|
919fc66b9d | ||
|
400fb5a5bb | ||
|
3bb4f9085c | ||
|
714c6cec3c | ||
|
cb69921202 | ||
|
277a0adac9 | ||
|
02d14f504f | ||
|
1ab7664a60 | ||
|
1be46ffb7e | ||
|
6ca52aed0d | ||
|
74e20970e2 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -79,6 +79,8 @@ TODO.md
|
||||
.vscode
|
||||
|
||||
# generated contract artifacts/
|
||||
contracts/broker/generated-artifacts/
|
||||
contracts/broker/test/generated-artifacts/
|
||||
contracts/erc20-bridge-sampler/generated-artifacts/
|
||||
contracts/erc20-bridge-sampler/test/generated-artifacts/
|
||||
contracts/integrations/generated-artifacts/
|
||||
@@ -113,6 +115,7 @@ packages/sol-tracing-utils/test/fixtures/artifacts/
|
||||
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||
|
||||
# generated truffle contract artifacts/
|
||||
contracts/broker/build/
|
||||
contracts/erc20-bridge-sampler/build/
|
||||
contracts/staking/build/
|
||||
contracts/coordinator/build/
|
||||
@@ -129,6 +132,8 @@ contracts/exchange-forwarder/build/
|
||||
contracts/dev-utils/build/
|
||||
|
||||
# generated contract wrappers
|
||||
contracts/broker/generated-wrappers/
|
||||
contracts/broker/test/generated-wrappers/
|
||||
packages/python-contract-wrappers/generated/
|
||||
contracts/erc20-bridge-sampler/generated-wrappers/
|
||||
contracts/erc20-bridge-sampler/test/generated-wrappers/
|
||||
|
@@ -1,5 +1,9 @@
|
||||
lib
|
||||
.nyc_output
|
||||
/contracts/broker/generated-wrappers
|
||||
/contracts/broker/test/generated-wrappers
|
||||
/contracts/broker/generated-artifacts
|
||||
/contracts/broker/test/generated-artifacts
|
||||
/contracts/integrations/generated-wrappers
|
||||
/contracts/integrations/test/generated-wrappers
|
||||
/contracts/integrations/generated-artifacts
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.1.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.1.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.1.1",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.3 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.2 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.1 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.1.1",
|
||||
"version": "3.1.3",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,12 +51,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
@@ -79,16 +79,16 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.4",
|
||||
"@0x/contracts-erc1155": "^2.0.4",
|
||||
"@0x/contracts-erc20": "^3.0.4",
|
||||
"@0x/contracts-erc721": "^3.0.4",
|
||||
"@0x/contracts-exchange-libs": "^4.1.0",
|
||||
"@0x/order-utils": "^10.1.1",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.6",
|
||||
"@0x/contracts-erc1155": "^2.0.6",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-erc721": "^3.0.6",
|
||||
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
10
contracts/broker/.npmignore
Normal file
10
contracts/broker/.npmignore
Normal file
@@ -0,0 +1,10 @@
|
||||
# Blacklist all files
|
||||
.*
|
||||
*
|
||||
# Whitelist lib
|
||||
!lib/**/*
|
||||
# Whitelist Solidity contracts
|
||||
!contracts/src/**/*
|
||||
# Blacklist tests in lib
|
||||
/lib/test/*
|
||||
# Package specific ignore
|
20
contracts/broker/CHANGELOG.json
Normal file
20
contracts/broker/CHANGELOG.json
Normal file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Created package",
|
||||
"pr": "2455"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
14
contracts/broker/CHANGELOG.md
Normal file
14
contracts/broker/CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
<!--
|
||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||
Edit the package's CHANGELOG.json file only.
|
||||
-->
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.1 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _Invalid date_
|
||||
|
||||
* Created package (#2455)
|
1
contracts/broker/DEPLOYS.json
Normal file
1
contracts/broker/DEPLOYS.json
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
73
contracts/broker/README.md
Normal file
73
contracts/broker/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
## Broker
|
||||
|
||||
This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
|
||||
## Installation
|
||||
|
||||
**Install**
|
||||
|
||||
```bash
|
||||
npm install @0x/contracts-broker --save
|
||||
```
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
|
||||
|
||||
## Contributing
|
||||
|
||||
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||
|
||||
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||
|
||||
```bash
|
||||
yarn config set workspaces-experimental true
|
||||
```
|
||||
|
||||
Then install dependencies
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-broker yarn build
|
||||
```
|
||||
|
||||
Or continuously rebuild on change:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-broker yarn watch
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
||||
```bash
|
||||
yarn clean
|
||||
```
|
||||
|
||||
### Lint
|
||||
|
||||
```bash
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
|
||||
```bash
|
||||
yarn test
|
||||
```
|
||||
|
||||
#### Testing options
|
||||
|
||||
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
26
contracts/broker/compiler.json
Normal file
26
contracts/broker/compiler.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"artifactsDir": "./test/generated-artifacts",
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"devdoc",
|
||||
"evm.bytecode.object",
|
||||
"evm.bytecode.sourceMap",
|
||||
"evm.deployedBytecode.object",
|
||||
"evm.deployedBytecode.sourceMap"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
314
contracts/broker/contracts/src/Broker.sol
Normal file
314
contracts/broker/contracts/src/Broker.sol
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./interfaces/IBroker.sol";
|
||||
import "./interfaces/IPropertyValidator.sol";
|
||||
import "./libs/LibBrokerRichErrors.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma, var-name-mixedcase
|
||||
contract Broker is
|
||||
IBroker,
|
||||
MixinWethUtils
|
||||
{
|
||||
// Contract addresses
|
||||
|
||||
// Address of the 0x Exchange contract
|
||||
address internal EXCHANGE;
|
||||
// Address of the 0x ERC1155 Asset Proxy contract
|
||||
address internal ERC1155_PROXY;
|
||||
|
||||
// The following storage variables are used to cache data for the duration of the transcation.
|
||||
// They should always cleared at the end of the transaction.
|
||||
|
||||
// Token IDs specified by the taker to be used to fill property-based orders.
|
||||
uint256[] internal _cachedTokenIds;
|
||||
// An index to the above array keeping track of which assets have been transferred.
|
||||
uint256 internal _cacheIndex;
|
||||
// The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to
|
||||
// and from this address as the effectual taker of the orders.
|
||||
address internal _sender;
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
using LibBytes for bytes;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
|
||||
/// @param exchange Address of the 0x Exchange contract.
|
||||
/// @param exchange Address of the Wrapped Ether contract.
|
||||
/// @param exchange Address of the 0x ERC1155 Asset Proxy contract.
|
||||
constructor (
|
||||
address exchange,
|
||||
address weth
|
||||
)
|
||||
public
|
||||
MixinWethUtils(
|
||||
exchange,
|
||||
weth
|
||||
)
|
||||
{
|
||||
EXCHANGE = exchange;
|
||||
ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
||||
}
|
||||
|
||||
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
|
||||
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
|
||||
/// @param to This should be the maker of the order.
|
||||
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
|
||||
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
|
||||
function safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata /* ids */,
|
||||
uint256[] calldata amounts,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
{
|
||||
// Only the ERC1155 asset proxy contract should be calling this function.
|
||||
if (msg.sender != ERC1155_PROXY) {
|
||||
LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError(
|
||||
msg.sender
|
||||
));
|
||||
}
|
||||
// Only `takerAssetData` should be using Broker assets
|
||||
if (from != address(this)) {
|
||||
LibRichErrors.rrevert(
|
||||
LibBrokerRichErrors.InvalidFromAddressError(from)
|
||||
);
|
||||
}
|
||||
// Only one asset amount should be specified.
|
||||
if (amounts.length != 1) {
|
||||
LibRichErrors.rrevert(
|
||||
LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length)
|
||||
);
|
||||
}
|
||||
|
||||
uint256 cacheIndex = _cacheIndex;
|
||||
uint256 remainingAmount = amounts[0];
|
||||
|
||||
// Verify that there are enough broker assets to transfer
|
||||
if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) {
|
||||
LibRichErrors.rrevert(
|
||||
LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length)
|
||||
);
|
||||
}
|
||||
|
||||
// Decode validator and params from `data`
|
||||
(address tokenAddress, address validator, bytes memory propertyData) = abi.decode(
|
||||
data,
|
||||
(address, address, bytes)
|
||||
);
|
||||
|
||||
while (remainingAmount != 0) {
|
||||
uint256 tokenId = _cachedTokenIds[cacheIndex];
|
||||
cacheIndex++;
|
||||
|
||||
// Validate asset properties
|
||||
IPropertyValidator(validator).checkBrokerAsset(
|
||||
tokenId,
|
||||
propertyData
|
||||
);
|
||||
|
||||
// Perform the transfer
|
||||
IERC721Token(tokenAddress).transferFrom(
|
||||
_sender,
|
||||
to,
|
||||
tokenId
|
||||
);
|
||||
|
||||
remainingAmount--;
|
||||
}
|
||||
// Update cache index in storage
|
||||
_cacheIndex = cacheIndex;
|
||||
}
|
||||
|
||||
/// @dev Fills a single property-based order by the given amount using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param order The property-based order to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmount The amount to fill the order by.
|
||||
/// @param signature The maker's signature of the given order.
|
||||
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the maker and taker.
|
||||
function brokerTrade(
|
||||
uint256[] memory brokeredTokenIds,
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature,
|
||||
bytes4 fillFunctionSelector,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
// Cache the taker-supplied asset data
|
||||
_cachedTokenIds = brokeredTokenIds;
|
||||
// Cache the sender's address
|
||||
_sender = msg.sender;
|
||||
|
||||
// Sanity-check the provided function selector
|
||||
if (
|
||||
fillFunctionSelector != IExchange(address(0)).fillOrder.selector &&
|
||||
fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector
|
||||
) {
|
||||
LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector);
|
||||
}
|
||||
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
|
||||
|
||||
// Perform the fill
|
||||
bytes memory fillCalldata = abi.encodeWithSelector(
|
||||
fillFunctionSelector,
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
// solhint-disable-next-line avoid-call-value
|
||||
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata);
|
||||
if (didSucceed) {
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||
} else {
|
||||
// Re-throw error
|
||||
LibRichErrors.rrevert(returnData);
|
||||
}
|
||||
|
||||
// Transfer maker asset to taker
|
||||
if (!order.makerAssetData.equals(WETH_ASSET_DATA)) {
|
||||
order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount);
|
||||
}
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
|
||||
|
||||
_clearStorage();
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param orders The property-based orders to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmounts The amounts to fill the orders by.
|
||||
/// @param signatures The makers' signatures for the given orders.
|
||||
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
|
||||
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the makers and taker.
|
||||
function batchBrokerTrade(
|
||||
uint256[] memory brokeredTokenIds,
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256[] memory takerAssetFillAmounts,
|
||||
bytes[] memory signatures,
|
||||
bytes4 batchFillFunctionSelector,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (LibFillResults.FillResults[] memory fillResults)
|
||||
{
|
||||
// Cache the taker-supplied asset data
|
||||
_cachedTokenIds = brokeredTokenIds;
|
||||
// Cache the sender's address
|
||||
_sender = msg.sender;
|
||||
|
||||
// Sanity-check the provided function selector
|
||||
if (
|
||||
batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector &&
|
||||
batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector &&
|
||||
batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector
|
||||
) {
|
||||
LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector);
|
||||
}
|
||||
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
|
||||
|
||||
// Perform the batch fill
|
||||
bytes memory batchFillCalldata = abi.encodeWithSelector(
|
||||
batchFillFunctionSelector,
|
||||
orders,
|
||||
takerAssetFillAmounts,
|
||||
signatures
|
||||
);
|
||||
// solhint-disable-next-line avoid-call-value
|
||||
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata);
|
||||
if (didSucceed) {
|
||||
// solhint-disable-next-line indent
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults[]));
|
||||
} else {
|
||||
// Re-throw error
|
||||
LibRichErrors.rrevert(returnData);
|
||||
}
|
||||
|
||||
// Transfer maker assets to taker
|
||||
for (uint256 i = 0; i < orders.length; i++) {
|
||||
if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) {
|
||||
orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount);
|
||||
}
|
||||
}
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
|
||||
|
||||
_clearStorage();
|
||||
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
function _clearStorage()
|
||||
private
|
||||
{
|
||||
delete _cachedTokenIds;
|
||||
_cacheIndex = 0;
|
||||
_sender = address(0);
|
||||
}
|
||||
}
|
101
contracts/broker/contracts/src/interfaces/IBroker.sol
Normal file
101
contracts/broker/contracts/src/interfaces/IBroker.sol
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
// solhint-disable space-after-comma
|
||||
interface IBroker {
|
||||
|
||||
/// @dev Fills a single property-based order by the given amount using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param order The property-based order to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmount The amount to fill the order by.
|
||||
/// @param signature The maker's signature of the given order.
|
||||
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the maker and taker.
|
||||
function brokerTrade(
|
||||
uint256[] calldata brokeredTokenIds,
|
||||
LibOrder.Order calldata order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes calldata signature,
|
||||
bytes4 fillFunctionSelector,
|
||||
uint256[] calldata ethFeeAmounts,
|
||||
address payable[] calldata feeRecipients
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (LibFillResults.FillResults memory fillResults);
|
||||
|
||||
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
|
||||
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||
/// @param orders The property-based orders to fill. The format of a property-based order is the
|
||||
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||
/// WETH (or zero).
|
||||
/// @param takerAssetFillAmounts The amounts to fill the orders by.
|
||||
/// @param signatures The makers' signatures for the given orders.
|
||||
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
|
||||
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return fillResults Amounts filled and fees paid by the makers and taker.
|
||||
function batchBrokerTrade(
|
||||
uint256[] calldata brokeredTokenIds,
|
||||
LibOrder.Order[] calldata orders,
|
||||
uint256[] calldata takerAssetFillAmounts,
|
||||
bytes[] calldata signatures,
|
||||
bytes4 batchFillFunctionSelector,
|
||||
uint256[] calldata ethFeeAmounts,
|
||||
address payable[] calldata feeRecipients
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (LibFillResults.FillResults[] memory fillResults);
|
||||
|
||||
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
|
||||
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
|
||||
/// @param to This should be the maker of the order.
|
||||
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
|
||||
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
|
||||
function safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] calldata /* ids */,
|
||||
uint256[] calldata amounts,
|
||||
bytes calldata data
|
||||
)
|
||||
external;
|
||||
}
|
@@ -19,20 +19,15 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./MixinMatchOrders.sol";
|
||||
import "./MixinAssets.sol";
|
||||
|
||||
interface IGodsUnchained {
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract OrderMatcher is
|
||||
MixinMatchOrders,
|
||||
MixinAssets
|
||||
{
|
||||
constructor (address _exchange)
|
||||
public
|
||||
LibConstants(_exchange)
|
||||
Ownable()
|
||||
{}
|
||||
/// @dev Returns the proto and quality for a particular card given its token id
|
||||
/// @param tokenId The id of the card to query.
|
||||
/// @return proto The proto of the given card.
|
||||
/// @return quality The quality of the given card
|
||||
function getDetails(uint256 tokenId)
|
||||
external
|
||||
view
|
||||
returns (uint16 proto, uint8 quality);
|
||||
}
|
@@ -17,15 +17,19 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract IThresholdAsset {
|
||||
interface IPropertyValidator {
|
||||
|
||||
/// @param _owner The address from which the balance will be retrieved
|
||||
/// @return Balance of owner
|
||||
function balanceOf(address _owner)
|
||||
/// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`.
|
||||
/// Should revert if the asset does not satisfy the specified properties.
|
||||
/// @param tokenId The ERC721 tokenId of the asset to check.
|
||||
/// @param propertyData Encoded properties or auxiliary data needed to perform the check.
|
||||
function checkBrokerAsset(
|
||||
uint256 tokenId,
|
||||
bytes calldata propertyData
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
view;
|
||||
}
|
109
contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
Normal file
109
contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
library LibBrokerRichErrors {
|
||||
|
||||
// bytes4(keccak256("InvalidFromAddressError(address)"))
|
||||
bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR =
|
||||
0x906bfb3c;
|
||||
|
||||
// bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)"))
|
||||
bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||
0xba9be200;
|
||||
|
||||
// bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)"))
|
||||
bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR =
|
||||
0x55272586;
|
||||
|
||||
// bytes4(keccak256("InvalidFunctionSelectorError(bytes4)"))
|
||||
bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR =
|
||||
0x540943f1;
|
||||
|
||||
// bytes4(keccak256("OnlyERC1155ProxyError(address)"))
|
||||
bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR =
|
||||
0xccc529af;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function InvalidFromAddressError(
|
||||
address from
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INVALID_FROM_ADDRESS_ERROR_SELECTOR,
|
||||
from
|
||||
);
|
||||
}
|
||||
|
||||
function AmountsLengthMustEqualOneError(
|
||||
uint256 amountsLength
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR,
|
||||
amountsLength
|
||||
);
|
||||
}
|
||||
|
||||
function TooFewBrokerAssetsProvidedError(
|
||||
uint256 numBrokeredAssets
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR,
|
||||
numBrokeredAssets
|
||||
);
|
||||
}
|
||||
|
||||
function InvalidFunctionSelectorError(
|
||||
bytes4 selector
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR,
|
||||
selector
|
||||
);
|
||||
}
|
||||
|
||||
function OnlyERC1155ProxyError(
|
||||
address sender
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ONLY_ERC_1155_PROXY_ERROR_SELECTOR,
|
||||
sender
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
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 "../interfaces/IGodsUnchained.sol";
|
||||
import "../interfaces/IPropertyValidator.sol";
|
||||
|
||||
|
||||
contract GodsUnchainedValidator is
|
||||
IPropertyValidator
|
||||
{
|
||||
IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase
|
||||
|
||||
using LibBytes for bytes;
|
||||
|
||||
constructor(address _godsUnchained)
|
||||
public
|
||||
{
|
||||
GODS_UNCHAINED = IGodsUnchained(_godsUnchained);
|
||||
}
|
||||
|
||||
/// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`.
|
||||
/// Reverts if the card doesn't match the specified proto and quality.
|
||||
/// @param tokenId The ERC721 tokenId of the card to check.
|
||||
/// @param propertyData Encoded proto and quality that the card is expected to have.
|
||||
function checkBrokerAsset(
|
||||
uint256 tokenId,
|
||||
bytes calldata propertyData
|
||||
)
|
||||
external
|
||||
view
|
||||
{
|
||||
(uint16 expectedProto, uint8 expectedQuality) = abi.decode(
|
||||
propertyData,
|
||||
(uint16, uint8)
|
||||
);
|
||||
|
||||
// Validate card properties.
|
||||
(uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId);
|
||||
require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH");
|
||||
require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH");
|
||||
}
|
||||
}
|
55
contracts/broker/contracts/test/TestGodsUnchained.sol
Normal file
55
contracts/broker/contracts/test/TestGodsUnchained.sol
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
|
||||
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-erc721/contracts/test/DummyERC721Token.sol";
|
||||
import "../src/interfaces/IGodsUnchained.sol";
|
||||
|
||||
|
||||
contract TestGodsUnchained is
|
||||
IGodsUnchained,
|
||||
DummyERC721Token
|
||||
{
|
||||
mapping (uint256 => uint16) internal _protoByTokenId;
|
||||
mapping (uint256 => uint8) internal _qualityByTokenId;
|
||||
|
||||
constructor (
|
||||
string memory _name,
|
||||
string memory _symbol
|
||||
)
|
||||
public
|
||||
DummyERC721Token(_name, _symbol)
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
|
||||
function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality)
|
||||
external
|
||||
{
|
||||
_protoByTokenId[tokenId] = proto;
|
||||
_qualityByTokenId[tokenId] = quality;
|
||||
}
|
||||
|
||||
function getDetails(uint256 tokenId)
|
||||
external
|
||||
view
|
||||
returns (uint16 proto, uint8 quality)
|
||||
{
|
||||
return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]);
|
||||
}
|
||||
}
|
96
contracts/broker/package.json
Normal file
96
contracts/broker/package.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.0.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
"description": "Extension of 0x protocol for property-based orders",
|
||||
"main": "lib/src/index.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn build:contracts && yarn build:ts",
|
||||
"build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||
"build:ts": "tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"compile:truffle": "truffle compile",
|
||||
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-erc721": "^3.0.6",
|
||||
"@0x/contracts-exchange": "^3.1.2",
|
||||
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"lodash": "^4.17.11",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typedoc": "^0.15.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
23
contracts/broker/src/artifacts.ts
Normal file
23
contracts/broker/src/artifacts.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as Broker from '../generated-artifacts/Broker.json';
|
||||
import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json';
|
||||
import * as IBroker from '../generated-artifacts/IBroker.json';
|
||||
import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json';
|
||||
import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json';
|
||||
import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json';
|
||||
import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json';
|
||||
export const artifacts = {
|
||||
Broker: Broker as ContractArtifact,
|
||||
IBroker: IBroker as ContractArtifact,
|
||||
IGodsUnchained: IGodsUnchained as ContractArtifact,
|
||||
IPropertyValidator: IPropertyValidator as ContractArtifact,
|
||||
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
|
||||
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
|
||||
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
|
||||
};
|
42
contracts/broker/src/gods_unchained_utils.ts
Normal file
42
contracts/broker/src/gods_unchained_utils.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
export const godsUnchainedUtils = {
|
||||
/**
|
||||
* Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator.
|
||||
*/
|
||||
encodePropertyData(proto: BigNumber, quality: BigNumber): string {
|
||||
return AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]).encode({
|
||||
proto,
|
||||
quality,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData
|
||||
* of a property-based GodsUnchained order. Must also provide the addresses of the Broker,
|
||||
* GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies
|
||||
* how many cards are expected for each "unit" of the takerAssetAmount. For example, If the
|
||||
* takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards
|
||||
* with the given proto and quality to fill the order. If an odd number is provided, the fill fails.
|
||||
*/
|
||||
encodeBrokerAssetData(
|
||||
brokerAddress: string,
|
||||
godsUnchainedAddress: string,
|
||||
validatorAddress: string,
|
||||
proto: BigNumber,
|
||||
quality: BigNumber,
|
||||
bundleSize: number = 1,
|
||||
): string {
|
||||
const dataEncoder = AbiEncoder.create([
|
||||
{ name: 'godsUnchainedAddress', type: 'address' },
|
||||
{ name: 'validatorAddress', type: 'address' },
|
||||
{ name: 'propertyData', type: 'bytes' },
|
||||
]);
|
||||
const propertyData = AbiEncoder.create([
|
||||
{ name: 'proto', type: 'uint16' },
|
||||
{ name: 'quality', type: 'uint8' },
|
||||
]).encode({ proto, quality });
|
||||
const data = dataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData });
|
||||
return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], data);
|
||||
},
|
||||
};
|
32
contracts/broker/src/index.ts
Normal file
32
contracts/broker/src/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
|
||||
export { godsUnchainedUtils } from './gods_unchained_utils';
|
||||
export { BrokerRevertErrors } from '@0x/utils';
|
||||
export {
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
CompilerOpts,
|
||||
StandardContractOutput,
|
||||
CompilerSettings,
|
||||
ContractChainData,
|
||||
ContractAbi,
|
||||
DevdocOutput,
|
||||
EvmOutput,
|
||||
CompilerSettingsMetadata,
|
||||
OptimizerSettings,
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
EvmBytecodeOutput,
|
||||
AbiDefinition,
|
||||
FunctionAbi,
|
||||
EventAbi,
|
||||
RevertErrorAbi,
|
||||
EventParameter,
|
||||
DataItem,
|
||||
MethodAbi,
|
||||
ConstructorAbi,
|
||||
FallbackAbi,
|
||||
ConstructorStateMutability,
|
||||
TupleDataItem,
|
||||
StateMutability,
|
||||
} from 'ethereum-types';
|
12
contracts/broker/src/wrappers.ts
Normal file
12
contracts/broker/src/wrappers.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/broker';
|
||||
export * from '../generated-wrappers/gods_unchained_validator';
|
||||
export * from '../generated-wrappers/i_broker';
|
||||
export * from '../generated-wrappers/i_gods_unchained';
|
||||
export * from '../generated-wrappers/i_property_validator';
|
||||
export * from '../generated-wrappers/lib_broker_rich_errors';
|
||||
export * from '../generated-wrappers/test_gods_unchained';
|
23
contracts/broker/test/artifacts.ts
Normal file
23
contracts/broker/test/artifacts.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as Broker from '../test/generated-artifacts/Broker.json';
|
||||
import * as GodsUnchainedValidator from '../test/generated-artifacts/GodsUnchainedValidator.json';
|
||||
import * as IBroker from '../test/generated-artifacts/IBroker.json';
|
||||
import * as IGodsUnchained from '../test/generated-artifacts/IGodsUnchained.json';
|
||||
import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json';
|
||||
import * as LibBrokerRichErrors from '../test/generated-artifacts/LibBrokerRichErrors.json';
|
||||
import * as TestGodsUnchained from '../test/generated-artifacts/TestGodsUnchained.json';
|
||||
export const artifacts = {
|
||||
Broker: Broker as ContractArtifact,
|
||||
IBroker: IBroker as ContractArtifact,
|
||||
IGodsUnchained: IGodsUnchained as ContractArtifact,
|
||||
IPropertyValidator: IPropertyValidator as ContractArtifact,
|
||||
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
|
||||
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
|
||||
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
|
||||
};
|
56
contracts/broker/test/gods_unchained_validator_test.ts
Normal file
56
contracts/broker/test/gods_unchained_validator_test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { godsUnchainedUtils } from '../src/gods_unchained_utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
|
||||
|
||||
blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
|
||||
let godsUnchained: TestGodsUnchainedContract;
|
||||
let validator: GodsUnchainedValidatorContract;
|
||||
|
||||
before(async () => {
|
||||
godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestGodsUnchained,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
'Gods Unchained Cards',
|
||||
'GU',
|
||||
);
|
||||
|
||||
validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync(
|
||||
artifacts.GodsUnchainedValidator,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
godsUnchained.address,
|
||||
);
|
||||
});
|
||||
|
||||
describe('checkBrokerAsset', () => {
|
||||
const proto = new BigNumber(42);
|
||||
const quality = new BigNumber(7);
|
||||
const propertyData = godsUnchainedUtils.encodePropertyData(proto, quality);
|
||||
|
||||
it('succeeds if assetData proto and quality match propertyData', async () => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto, quality).awaitTransactionSuccessAsync();
|
||||
await validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
});
|
||||
it("reverts if assetData proto doesn't match propertyData", async () => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync();
|
||||
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
expect(tx).to.revertWith('PROTO_MISMATCH');
|
||||
});
|
||||
it("reverts if assetData quality doesn't match proeprtyData", async () => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync();
|
||||
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
expect(tx).to.revertWith('QUALITY_MISMATCH');
|
||||
});
|
||||
});
|
||||
});
|
12
contracts/broker/test/wrappers.ts
Normal file
12
contracts/broker/test/wrappers.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/broker';
|
||||
export * from '../test/generated-wrappers/gods_unchained_validator';
|
||||
export * from '../test/generated-wrappers/i_broker';
|
||||
export * from '../test/generated-wrappers/i_gods_unchained';
|
||||
export * from '../test/generated-wrappers/i_property_validator';
|
||||
export * from '../test/generated-wrappers/lib_broker_rich_errors';
|
||||
export * from '../test/generated-wrappers/test_gods_unchained';
|
96
contracts/broker/truffle-config.js
Normal file
96
contracts/broker/truffle-config.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
// development: {
|
||||
// host: "127.0.0.1", // Localhost (default: none)
|
||||
// port: 8545, // Standard Ethereum port (default: none)
|
||||
// network_id: "*", // Any network (default: none)
|
||||
// },
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
22
contracts/broker/tsconfig.json
Normal file
22
contracts/broker/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/Broker.json",
|
||||
"generated-artifacts/GodsUnchainedValidator.json",
|
||||
"generated-artifacts/IBroker.json",
|
||||
"generated-artifacts/IGodsUnchained.json",
|
||||
"generated-artifacts/IPropertyValidator.json",
|
||||
"generated-artifacts/LibBrokerRichErrors.json",
|
||||
"generated-artifacts/TestGodsUnchained.json",
|
||||
"test/generated-artifacts/Broker.json",
|
||||
"test/generated-artifacts/GodsUnchainedValidator.json",
|
||||
"test/generated-artifacts/IBroker.json",
|
||||
"test/generated-artifacts/IGodsUnchained.json",
|
||||
"test/generated-artifacts/IPropertyValidator.json",
|
||||
"test/generated-artifacts/LibBrokerRichErrors.json",
|
||||
"test/generated-artifacts/TestGodsUnchained.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
6
contracts/broker/tslint.json
Normal file
6
contracts/broker/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false
|
||||
}
|
||||
}
|
7
contracts/broker/typedoc-tsconfig.json
Normal file
7
contracts/broker/typedoc-tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../typedoc-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
}
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.0.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.6 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,19 +52,19 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.1.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.4",
|
||||
"@0x/contracts-erc20": "^3.0.4",
|
||||
"@0x/contracts-exchange": "^3.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/order-utils": "^10.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||
"@0x/contracts-dev-utils": "^1.0.6",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-exchange": "^3.1.2",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -84,14 +84,14 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.4",
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/contract-addresses": "^4.3.0",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/json-schemas": "^5.0.4",
|
||||
"@0x/assert": "^3.0.5",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/contract-addresses": "^4.4.0",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/json-schemas": "^5.0.5",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"http-status-codes": "^1.3.2"
|
||||
},
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "1.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "1.0.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.6 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -41,13 +41,13 @@ yarn install
|
||||
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-extensions yarn build
|
||||
PKG=@0x/contracts-dev-utils yarn build
|
||||
```
|
||||
|
||||
Or continuously rebuild on change:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-extensions yarn watch
|
||||
PKG=@0x/contracts-dev-utils yarn watch
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,10 +41,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/assert": "^3.0.4",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/assert": "^3.0.5",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@types/node": "*",
|
||||
@@ -59,7 +59,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0"
|
||||
"@0x/base-contract": "^6.1.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "2.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "2.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "2.0.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.6 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,11 +52,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
@@ -80,10 +80,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "1.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Make source IDs static on all networks, not inherited from `DeploymentConstants`.",
|
||||
"pr": 2459
|
||||
}
|
||||
],
|
||||
"timestamp": 1580811564
|
||||
},
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.2.1 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.2.0 - _February 4, 2020_
|
||||
|
||||
* Make source IDs static on all networks, not inherited from `DeploymentConstants`. (#2459)
|
||||
|
||||
## v1.1.0 - _January 22, 2020_
|
||||
|
||||
* Add batch functions to query quotes (#2427)
|
||||
|
@@ -40,6 +40,9 @@ contract ERC20BridgeSampler is
|
||||
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 1500e3;
|
||||
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
|
||||
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 1000e3;
|
||||
address constant private UNISWAP_SOURCE = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||
address constant private ETH2DAI_SOURCE = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||
address constant private KYBER_SOURCE = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
|
||||
|
||||
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
@@ -606,13 +609,13 @@ contract ERC20BridgeSampler is
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
if (source == _getEth2DaiAddress()) {
|
||||
if (source == ETH2DAI_SOURCE) {
|
||||
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
||||
if (source == UNISWAP_SOURCE) {
|
||||
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == _getKyberNetworkProxyAddress()) {
|
||||
if (source == KYBER_SOURCE) {
|
||||
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
@@ -634,10 +637,10 @@ contract ERC20BridgeSampler is
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
if (source == _getEth2DaiAddress()) {
|
||||
if (source == ETH2DAI_SOURCE) {
|
||||
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
||||
if (source == UNISWAP_SOURCE) {
|
||||
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,18 +50,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.1.1",
|
||||
"@0x/contracts-erc20": "^3.0.4",
|
||||
"@0x/contracts-exchange": "^3.1.0",
|
||||
"@0x/contracts-exchange-libs": "^4.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-exchange": "^3.1.2",
|
||||
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -79,10 +79,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -15,7 +15,6 @@ import { TestERC20BridgeSamplerContract } from './wrappers';
|
||||
|
||||
blockchainTests('erc20-bridge-sampler', env => {
|
||||
let testContract: TestERC20BridgeSamplerContract;
|
||||
let allSources: { [name: string]: string };
|
||||
const RATE_DENOMINATOR = constants.ONE_ETHER;
|
||||
const MIN_RATE = new BigNumber('0.01');
|
||||
const MAX_RATE = new BigNumber('100');
|
||||
@@ -30,6 +29,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const INVALID_ASSET_DATA = hexUtils.random(37);
|
||||
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
|
||||
const BUY_SOURCES = ['Eth2Dai', 'Uniswap'];
|
||||
const SOURCE_IDS: { [source: string]: string } = {
|
||||
Uniswap: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95',
|
||||
Eth2Dai: '0x39755357759ce0d7f32dc8dc45414cca409ae24e',
|
||||
Kyber: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
|
||||
};
|
||||
const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
|
||||
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
|
||||
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
|
||||
@@ -45,14 +49,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
allSources = _.zipObject(
|
||||
['Uniswap', 'Eth2Dai', 'Kyber'],
|
||||
[
|
||||
await testContract.uniswap().callAsync(),
|
||||
await testContract.eth2Dai().callAsync(),
|
||||
await testContract.kyber().callAsync(),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
function getPackedHash(...args: string[]): string {
|
||||
@@ -340,7 +336,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
@@ -349,14 +345,14 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), sampleAmounts)
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
@@ -366,7 +362,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -381,7 +377,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -396,7 +392,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -411,7 +407,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -426,7 +422,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -446,7 +442,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
@@ -455,14 +451,14 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), sampleAmounts)
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
@@ -472,7 +468,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -485,7 +481,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
sources.map(n => allSources[n]),
|
||||
sources.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -500,7 +496,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -515,7 +511,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -530,7 +526,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -545,7 +541,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -561,7 +557,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns empty quotes with no sample amounts', async () => {
|
||||
const emptyQuotes = _.times(SELL_SOURCES.length, () => []);
|
||||
const quotes = await testContract
|
||||
.sampleSells(SELL_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(emptyQuotes);
|
||||
});
|
||||
@@ -570,7 +566,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSells(SELL_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -580,7 +576,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sources = _.sampleSize(SELL_SOURCES, 1);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSells(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleSells(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -588,7 +584,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.sampleSells(
|
||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
@@ -606,7 +602,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns empty quotes with no sample amounts', async () => {
|
||||
const emptyQuotes = _.times(BUY_SOURCES.length, () => []);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(BUY_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(emptyQuotes);
|
||||
});
|
||||
@@ -615,7 +611,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(BUY_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -625,7 +621,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sources = _.sampleSize(BUY_SOURCES, 1);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -633,7 +629,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.sampleBuys(
|
||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
@@ -645,7 +641,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws if kyber is passed in as a source', async () => {
|
||||
const sources = [...BUY_SOURCES, 'Kyber'];
|
||||
const tx = testContract
|
||||
.sampleBuys(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN))
|
||||
.sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.0.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.6 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,18 +51,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -82,7 +82,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0"
|
||||
"@0x/base-contract": "^6.1.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.0.6",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.0.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.6 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.6",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,18 +52,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -84,7 +84,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0"
|
||||
"@0x/base-contract": "^6.1.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"version": "4.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Refactor, moved LibAssetDataTransfer and MixinWeth(Utils) to extensions",
|
||||
"pr": 2455
|
||||
}
|
||||
],
|
||||
"timestamp": 1580988106
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "4.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "4.0.4",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.0 - _February 6, 2020_
|
||||
|
||||
* Refactor, moved LibAssetDataTransfer and MixinWeth(Utils) to extensions (#2455)
|
||||
|
||||
## v4.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -19,19 +19,32 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./MixinForwarderCore.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./MixinExchangeWrapper.sol";
|
||||
import "./MixinReceiver.sol";
|
||||
import "./interfaces/IForwarder.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
// MixinAssets, MixinExchangeWrapper, and MixinWeth are all inherited via
|
||||
// MixinForwarderCore.
|
||||
contract Forwarder is
|
||||
LibConstants,
|
||||
MixinForwarderCore,
|
||||
IForwarder,
|
||||
Ownable,
|
||||
MixinWethUtils,
|
||||
MixinExchangeWrapper,
|
||||
MixinReceiver
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _exchangeV2,
|
||||
@@ -39,11 +52,158 @@ contract Forwarder is
|
||||
)
|
||||
public
|
||||
Ownable()
|
||||
LibConstants(
|
||||
MixinWethUtils(
|
||||
_exchange,
|
||||
_exchangeV2,
|
||||
_weth
|
||||
)
|
||||
MixinForwarderCore()
|
||||
{}
|
||||
MixinExchangeWrapper(
|
||||
_exchange,
|
||||
_exchangeV2
|
||||
)
|
||||
{} // solhint-disable-line no-empty-blocks
|
||||
|
||||
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
|
||||
/// that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of the asset to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
assetData.transferOut(amount);
|
||||
}
|
||||
|
||||
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
|
||||
/// Forwarder contract to the fee recipient.
|
||||
/// This method needs to be called before forwarding orders of a maker asset that hasn't
|
||||
/// previously been approved.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
function approveMakerAssetProxy(bytes calldata assetData)
|
||||
external
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector;
|
||||
|
||||
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
|
||||
if (proxyId == erc20ProxyId) {
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(erc20ProxyId);
|
||||
if (proxyAddress == address(0)) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||
}
|
||||
address token = assetData.readAddress(16);
|
||||
LibERC20Token.approve(token, proxyAddress, MAX_UINT256);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
||||
/// as possible, accounting for order and forwarder fees.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketSellOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
|
||||
// and pays WETH order fees.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketSellNoThrow(
|
||||
orders,
|
||||
wethRemaining,
|
||||
signatures
|
||||
);
|
||||
|
||||
// Ensure that no extra WETH owned by this contract has been spent.
|
||||
if (wethSpentAmount > wethRemaining) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||
wethSpentAmount,
|
||||
msg.value
|
||||
));
|
||||
}
|
||||
|
||||
// Calculate amount of WETH that hasn't been spent.
|
||||
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(wethRemaining);
|
||||
}
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||
/// Any ETH not spent will be refunded to sender.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketBuyOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
|
||||
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketBuyFillOrKill(
|
||||
orders,
|
||||
makerAssetBuyAmount,
|
||||
signatures
|
||||
);
|
||||
|
||||
// Ensure that no extra WETH owned by this contract has been spent.
|
||||
if (wethSpentAmount > wethRemaining) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||
wethSpentAmount,
|
||||
msg.value
|
||||
));
|
||||
}
|
||||
|
||||
// Calculate amount of WETH that hasn't been spent.
|
||||
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_unwrapAndTransferEth(wethRemaining);
|
||||
}
|
||||
}
|
||||
|
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibAssetDataTransfer.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./interfaces/IAssets.sol";
|
||||
|
||||
|
||||
contract MixinAssets is
|
||||
Ownable,
|
||||
LibConstants,
|
||||
IAssets
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
|
||||
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
|
||||
/// that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of the asset to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
assetData.transferOut(amount);
|
||||
}
|
||||
|
||||
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
|
||||
/// Forwarder contract to the fee recipient.
|
||||
/// This method needs to be called before forwarding orders of a maker asset that hasn't
|
||||
/// previously been approved.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
function approveMakerAssetProxy(bytes calldata assetData)
|
||||
external
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector;
|
||||
|
||||
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
|
||||
if (proxyId == erc20ProxyId) {
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(erc20ProxyId);
|
||||
if (proxyAddress == address(0)) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||
}
|
||||
address token = assetData.readAddress(16);
|
||||
LibERC20Token.approve(token, proxyAddress, MAX_UINT);
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,28 +19,60 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./interfaces/IExchangeV2.sol";
|
||||
import "./MixinAssets.sol";
|
||||
|
||||
|
||||
contract MixinExchangeWrapper is
|
||||
LibConstants,
|
||||
MixinAssets
|
||||
{
|
||||
contract MixinExchangeWrapper {
|
||||
|
||||
// The v2 order id is the first 4 bytes of the ExchangeV2 order schema hash.
|
||||
// bytes4(keccak256(abi.encodePacked(
|
||||
// "Order(",
|
||||
// "address makerAddress,",
|
||||
// "address takerAddress,",
|
||||
// "address feeRecipientAddress,",
|
||||
// "address senderAddress,",
|
||||
// "uint256 makerAssetAmount,",
|
||||
// "uint256 takerAssetAmount,",
|
||||
// "uint256 makerFee,",
|
||||
// "uint256 takerFee,",
|
||||
// "uint256 expirationTimeSeconds,",
|
||||
// "uint256 salt,",
|
||||
// "bytes makerAssetData,",
|
||||
// "bytes takerAssetData",
|
||||
// ")"
|
||||
// )));
|
||||
bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
IExchangeV2 internal EXCHANGE_V2;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
using LibBytes for bytes;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _exchangeV2
|
||||
)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
|
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./interfaces/IAssets.sol";
|
||||
import "./interfaces/IForwarderCore.sol";
|
||||
import "./MixinExchangeWrapper.sol";
|
||||
import "./MixinWeth.sol";
|
||||
|
||||
|
||||
contract MixinForwarderCore is
|
||||
LibConstants,
|
||||
IAssets,
|
||||
IForwarderCore,
|
||||
MixinWeth,
|
||||
MixinExchangeWrapper
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
/// @dev Constructor approves ERC20 proxy to transfer WETH on this contract's behalf.
|
||||
constructor ()
|
||||
public
|
||||
{
|
||||
address proxyAddress = EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
|
||||
if (proxyAddress == address(0)) {
|
||||
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
|
||||
/// as possible, accounting for order and forwarder fees.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketSellOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
|
||||
// and pays WETH order fees.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketSellNoThrow(
|
||||
orders,
|
||||
wethRemaining,
|
||||
signatures
|
||||
);
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_transferEthRefund(wethRemaining, wethSpentAmount);
|
||||
}
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||
/// Any ETH not spent will be refunded to sender.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketBuyOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
)
|
||||
{
|
||||
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
|
||||
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||
(
|
||||
wethSpentAmount,
|
||||
makerAssetAcquiredAmount
|
||||
) = _marketBuyFillOrKill(
|
||||
orders,
|
||||
makerAssetBuyAmount,
|
||||
signatures
|
||||
);
|
||||
|
||||
// Refund remaining ETH to msg.sender.
|
||||
_transferEthRefund(wethRemaining, wethSpentAmount);
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IAssets {
|
||||
|
||||
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||
/// used to withdraw assets that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of ERC20 token to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
|
||||
/// Forwarder contract to the fee recipient.
|
||||
/// This method needs to be called before forwarding orders of a maker asset that hasn't
|
||||
/// previously been approved.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
function approveMakerAssetProxy(
|
||||
bytes calldata assetData
|
||||
)
|
||||
external;
|
||||
}
|
@@ -19,12 +19,77 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./IForwarderCore.sol";
|
||||
import "./IAssets.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract IForwarder is
|
||||
IForwarderCore,
|
||||
IAssets
|
||||
{}
|
||||
contract IForwarder {
|
||||
|
||||
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||
/// used to withdraw assets that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of ERC20 token to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
|
||||
/// Forwarder contract to the fee recipient.
|
||||
/// This method needs to be called before forwarding orders of a maker asset that hasn't
|
||||
/// previously been approved.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
function approveMakerAssetProxy(
|
||||
bytes calldata assetData
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
||||
/// as possible, accounting for order and forwarder fees.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketSellOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
);
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||
/// Any ETH not spent will be refunded to sender.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketBuyOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
);
|
||||
}
|
||||
|
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
|
||||
|
||||
contract IForwarderCore {
|
||||
|
||||
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
||||
/// as possible, accounting for order and forwarder fees.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketSellOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
);
|
||||
|
||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||
/// Any ETH not spent will be refunded to sender.
|
||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||
/// @param signatures Proofs that orders have been created by makers.
|
||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||
function marketBuyOrdersWithEth(
|
||||
LibOrder.Order[] memory orders,
|
||||
uint256 makerAssetBuyAmount,
|
||||
bytes[] memory signatures,
|
||||
uint256[] memory ethFeeAmounts,
|
||||
address payable[] memory feeRecipients
|
||||
)
|
||||
public
|
||||
payable
|
||||
returns (
|
||||
uint256 wethSpentAmount,
|
||||
uint256 makerAssetAcquiredAmount
|
||||
);
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "../interfaces/IExchangeV2.sol";
|
||||
|
||||
|
||||
contract LibConstants {
|
||||
|
||||
uint256 constant internal MAX_UINT = uint256(-1);
|
||||
|
||||
// The v2 order id is the first 4 bytes of the ExchangeV2 order schema hash.
|
||||
// bytes4(keccak256(abi.encodePacked(
|
||||
// "Order(",
|
||||
// "address makerAddress,",
|
||||
// "address takerAddress,",
|
||||
// "address feeRecipientAddress,",
|
||||
// "address senderAddress,",
|
||||
// "uint256 makerAssetAmount,",
|
||||
// "uint256 takerAssetAmount,",
|
||||
// "uint256 makerFee,",
|
||||
// "uint256 takerFee,",
|
||||
// "uint256 expirationTimeSeconds,",
|
||||
// "uint256 salt,",
|
||||
// "bytes makerAssetData,",
|
||||
// "bytes takerAssetData",
|
||||
// ")"
|
||||
// )));
|
||||
bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
IExchangeV2 internal EXCHANGE_V2;
|
||||
IEtherToken internal ETHER_TOKEN;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _exchangeV2,
|
||||
address _weth
|
||||
)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
|
||||
ETHER_TOKEN = IEtherToken(_weth);
|
||||
}
|
||||
}
|
@@ -25,10 +25,6 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
|
||||
0xf3b96b8d;
|
||||
|
||||
// bytes4(keccak256("UnsupportedAssetProxyError(bytes4)"))
|
||||
bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR =
|
||||
0x7996a271;
|
||||
|
||||
// bytes4(keccak256("CompleteBuyFailedError(uint256,uint256)"))
|
||||
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
||||
0x91353a0c;
|
||||
@@ -37,26 +33,10 @@ library LibForwarderRichErrors {
|
||||
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
||||
0x31360af1;
|
||||
|
||||
// bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)"))
|
||||
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
||||
0xecf40fd9;
|
||||
|
||||
// bytes4(keccak256("OverspentWethError(uint256,uint256)"))
|
||||
bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR =
|
||||
0xcdcbed5d;
|
||||
|
||||
// bytes4(keccak256("DefaultFunctionWethContractOnlyError(address)"))
|
||||
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
|
||||
0x08b18698;
|
||||
|
||||
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
|
||||
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||
0xbaffa474;
|
||||
|
||||
// bytes4(keccak256("EthFeeLengthMismatchError(uint256,uint256)"))
|
||||
bytes4 internal constant ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR =
|
||||
0x3ecb6ceb;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function UnregisteredAssetProxyError()
|
||||
internal
|
||||
@@ -66,19 +46,6 @@ library LibForwarderRichErrors {
|
||||
return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR);
|
||||
}
|
||||
|
||||
function UnsupportedAssetProxyError(
|
||||
bytes4 proxyId
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR,
|
||||
proxyId
|
||||
);
|
||||
}
|
||||
|
||||
function CompleteBuyFailedError(
|
||||
uint256 expectedAssetBuyAmount,
|
||||
uint256 actualAssetBuyAmount
|
||||
@@ -107,21 +74,6 @@ library LibForwarderRichErrors {
|
||||
);
|
||||
}
|
||||
|
||||
function InsufficientEthForFeeError(
|
||||
uint256 ethFeeRequired,
|
||||
uint256 ethAvailable
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR,
|
||||
ethFeeRequired,
|
||||
ethAvailable
|
||||
);
|
||||
}
|
||||
|
||||
function OverspentWethError(
|
||||
uint256 wethSpent,
|
||||
uint256 msgValue
|
||||
@@ -136,45 +88,4 @@ library LibForwarderRichErrors {
|
||||
msgValue
|
||||
);
|
||||
}
|
||||
|
||||
function DefaultFunctionWethContractOnlyError(
|
||||
address senderAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR,
|
||||
senderAddress
|
||||
);
|
||||
}
|
||||
|
||||
function Erc721AmountMustEqualOneError(
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
function EthFeeLengthMismatchError(
|
||||
uint256 ethFeesLength,
|
||||
uint256 feeRecipientsLength
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR,
|
||||
ethFeesLength,
|
||||
feeRecipientsLength
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -19,14 +19,12 @@
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||
import "../src/MixinExchangeWrapper.sol";
|
||||
import "../src/libs/LibConstants.sol";
|
||||
import "../src/libs/LibAssetDataTransfer.sol";
|
||||
import "../src/MixinReceiver.sol";
|
||||
|
||||
|
||||
contract TestForwarder is
|
||||
LibConstants,
|
||||
MixinExchangeWrapper,
|
||||
MixinReceiver
|
||||
{
|
||||
@@ -35,8 +33,7 @@ contract TestForwarder is
|
||||
// solhint-disable no-empty-blocks
|
||||
constructor ()
|
||||
public
|
||||
LibConstants(
|
||||
address(0),
|
||||
MixinExchangeWrapper(
|
||||
address(0),
|
||||
address(0)
|
||||
)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.0.4",
|
||||
"version": "4.1.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "Forwarder,IExchangeV2",
|
||||
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IExchangeV2|IForwarder|IForwarderCore|LibAssetDataTransfer|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinReceiver|MixinWeth|TestForwarder).json",
|
||||
"abis": "./test/generated-artifacts/@(Forwarder|IExchangeV2|IForwarder|LibForwarderRichErrors|MixinExchangeWrapper|MixinReceiver|TestForwarder).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -52,25 +52,25 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.1.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.4",
|
||||
"@0x/contracts-erc1155": "^2.0.4",
|
||||
"@0x/contracts-erc20": "^3.0.4",
|
||||
"@0x/contracts-erc721": "^3.0.4",
|
||||
"@0x/contracts-exchange": "^3.1.0",
|
||||
"@0x/contracts-exchange-libs": "^4.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/order-utils": "^10.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||
"@0x/contracts-dev-utils": "^1.0.6",
|
||||
"@0x/contracts-erc1155": "^2.0.6",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-erc721": "^3.0.6",
|
||||
"@0x/contracts-exchange": "^3.1.2",
|
||||
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -90,7 +90,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
|
@@ -6,32 +6,18 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as Forwarder from '../test/generated-artifacts/Forwarder.json';
|
||||
import * as IAssets from '../test/generated-artifacts/IAssets.json';
|
||||
import * as IExchangeV2 from '../test/generated-artifacts/IExchangeV2.json';
|
||||
import * as IForwarder from '../test/generated-artifacts/IForwarder.json';
|
||||
import * as IForwarderCore from '../test/generated-artifacts/IForwarderCore.json';
|
||||
import * as LibAssetDataTransfer from '../test/generated-artifacts/LibAssetDataTransfer.json';
|
||||
import * as LibConstants from '../test/generated-artifacts/LibConstants.json';
|
||||
import * as LibForwarderRichErrors from '../test/generated-artifacts/LibForwarderRichErrors.json';
|
||||
import * as MixinAssets from '../test/generated-artifacts/MixinAssets.json';
|
||||
import * as MixinExchangeWrapper from '../test/generated-artifacts/MixinExchangeWrapper.json';
|
||||
import * as MixinForwarderCore from '../test/generated-artifacts/MixinForwarderCore.json';
|
||||
import * as MixinReceiver from '../test/generated-artifacts/MixinReceiver.json';
|
||||
import * as MixinWeth from '../test/generated-artifacts/MixinWeth.json';
|
||||
import * as TestForwarder from '../test/generated-artifacts/TestForwarder.json';
|
||||
export const artifacts = {
|
||||
Forwarder: Forwarder as ContractArtifact,
|
||||
MixinAssets: MixinAssets as ContractArtifact,
|
||||
MixinExchangeWrapper: MixinExchangeWrapper as ContractArtifact,
|
||||
MixinForwarderCore: MixinForwarderCore as ContractArtifact,
|
||||
MixinReceiver: MixinReceiver as ContractArtifact,
|
||||
MixinWeth: MixinWeth as ContractArtifact,
|
||||
IAssets: IAssets as ContractArtifact,
|
||||
IExchangeV2: IExchangeV2 as ContractArtifact,
|
||||
IForwarder: IForwarder as ContractArtifact,
|
||||
IForwarderCore: IForwarderCore as ContractArtifact,
|
||||
LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact,
|
||||
LibConstants: LibConstants as ContractArtifact,
|
||||
LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact,
|
||||
TestForwarder: TestForwarder as ContractArtifact,
|
||||
};
|
||||
|
@@ -26,7 +26,7 @@ import {
|
||||
randomAddress,
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils';
|
||||
import { BigNumber, hexUtils, LibAssetDataTransferRevertErrors } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
@@ -235,7 +235,7 @@ blockchainTests.resets('Supported asset type unit tests', env => {
|
||||
const tx = forwarder
|
||||
.transferOut(erc721AssetData, invalidAmount)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
const expectedError = new ExchangeForwarderRevertErrors.Erc721AmountMustEqualOneError(invalidAmount);
|
||||
const expectedError = new LibAssetDataTransferRevertErrors.Erc721AmountMustEqualOneError(invalidAmount);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('transfers a single ERC1155 token', async () => {
|
||||
@@ -365,7 +365,7 @@ blockchainTests.resets('Supported asset type unit tests', env => {
|
||||
const tx = forwarder
|
||||
.transferOut(randomBytes, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
const expectedError = new ExchangeForwarderRevertErrors.UnsupportedAssetProxyError(
|
||||
const expectedError = new LibAssetDataTransferRevertErrors.UnsupportedAssetProxyError(
|
||||
hexUtils.slice(randomBytes, 0, 4),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
|
@@ -4,16 +4,9 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/forwarder';
|
||||
export * from '../test/generated-wrappers/i_assets';
|
||||
export * from '../test/generated-wrappers/i_exchange_v2';
|
||||
export * from '../test/generated-wrappers/i_forwarder';
|
||||
export * from '../test/generated-wrappers/i_forwarder_core';
|
||||
export * from '../test/generated-wrappers/lib_asset_data_transfer';
|
||||
export * from '../test/generated-wrappers/lib_constants';
|
||||
export * from '../test/generated-wrappers/lib_forwarder_rich_errors';
|
||||
export * from '../test/generated-wrappers/mixin_assets';
|
||||
export * from '../test/generated-wrappers/mixin_exchange_wrapper';
|
||||
export * from '../test/generated-wrappers/mixin_forwarder_core';
|
||||
export * from '../test/generated-wrappers/mixin_receiver';
|
||||
export * from '../test/generated-wrappers/mixin_weth';
|
||||
export * from '../test/generated-wrappers/test_forwarder';
|
||||
|
@@ -6,18 +6,11 @@
|
||||
"generated-artifacts/Forwarder.json",
|
||||
"generated-artifacts/IExchangeV2.json",
|
||||
"test/generated-artifacts/Forwarder.json",
|
||||
"test/generated-artifacts/IAssets.json",
|
||||
"test/generated-artifacts/IExchangeV2.json",
|
||||
"test/generated-artifacts/IForwarder.json",
|
||||
"test/generated-artifacts/IForwarderCore.json",
|
||||
"test/generated-artifacts/LibAssetDataTransfer.json",
|
||||
"test/generated-artifacts/LibConstants.json",
|
||||
"test/generated-artifacts/LibForwarderRichErrors.json",
|
||||
"test/generated-artifacts/MixinAssets.json",
|
||||
"test/generated-artifacts/MixinExchangeWrapper.json",
|
||||
"test/generated-artifacts/MixinForwarderCore.json",
|
||||
"test/generated-artifacts/MixinReceiver.json",
|
||||
"test/generated-artifacts/MixinWeth.json",
|
||||
"test/generated-artifacts/TestForwarder.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"version": "4.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Moved LibAssetDataTransfer here from forwarder",
|
||||
"pr": 2455
|
||||
}
|
||||
],
|
||||
"timestamp": 1580988106
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "4.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.0 - _February 6, 2020_
|
||||
|
||||
* Moved LibAssetDataTransfer here from forwarder (#2455)
|
||||
|
||||
## v4.1.1 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.0 - _January 22, 2020_
|
||||
|
||||
* Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.1.0",
|
||||
"version": "4.2.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,14 +52,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/subproviders": "^6.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/subproviders": "^6.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -80,13 +80,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/order-utils": "^10.1.1",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "3.1.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.2 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.1 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.0 - _January 22, 2020_
|
||||
|
||||
* Uses updated event decoding to properly decodes arrays and objects. (#2443)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,21 +52,21 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.1.1",
|
||||
"@0x/contracts-exchange-libs": "^4.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-multisig": "^4.0.4",
|
||||
"@0x/contracts-staking": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-multisig": "^4.0.6",
|
||||
"@0x/contracts-staking": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -88,13 +88,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.4",
|
||||
"@0x/contracts-erc1155": "^2.0.4",
|
||||
"@0x/contracts-erc20": "^3.0.4",
|
||||
"@0x/contracts-erc721": "^3.0.4",
|
||||
"@0x/order-utils": "^10.1.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.6",
|
||||
"@0x/contracts-erc1155": "^2.0.6",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-erc721": "^3.0.6",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"version": "6.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "New year, new me: remove everything, add MixinWethUtils and LibAssetDataTransfer",
|
||||
"pr": 2455
|
||||
}
|
||||
],
|
||||
"timestamp": 1580988106
|
||||
},
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "5.1.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "5.1.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.0.0 - _February 6, 2020_
|
||||
|
||||
* New year, new me: remove everything, add MixinWethUtils and LibAssetDataTransfer (#2455)
|
||||
|
||||
## v5.1.4 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.1.3 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
## Extensions
|
||||
|
||||
This package implements various extensions to the 0x protocol. Extension contracts can add various rules around how orders are settled while still getting the interoperability and security benefits of using the underlying 0x protocol contracts. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||
This package includes utility smart contracts that may be useful for developing on top of the core 0x Exchange. For example, `MixinWethUtils` includes functions to pay affiliate fees in ETH, wrap ETH to be used for 0x trades and protocol fees, and unwrap WETH to refund the sender.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -12,7 +12,7 @@ npm install @0x/contracts-extensions --save
|
||||
|
||||
## Bug bounty
|
||||
|
||||
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
|
||||
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "./interfaces/IThresholdAsset.sol";
|
||||
import "./MixinBalanceThresholdFilterCore.sol";
|
||||
|
||||
|
||||
contract BalanceThresholdFilter is
|
||||
MixinBalanceThresholdFilterCore
|
||||
{
|
||||
|
||||
/// @dev Constructs BalanceThresholdFilter.
|
||||
/// @param exchange Address of 0x exchange.
|
||||
/// @param thresholdAsset The asset that must be held by makers/takers.
|
||||
/// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers.
|
||||
constructor (
|
||||
address exchange,
|
||||
address thresholdAsset,
|
||||
uint256 balanceThreshold
|
||||
)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(exchange);
|
||||
THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
|
||||
BALANCE_THRESHOLD = balanceThreshold;
|
||||
}
|
||||
}
|
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "./MixinExchangeCalldata.sol";
|
||||
import "./interfaces/IBalanceThresholdFilterCore.sol";
|
||||
|
||||
|
||||
contract MixinBalanceThresholdFilterCore is
|
||||
IBalanceThresholdFilterCore,
|
||||
MixinExchangeCalldata
|
||||
{
|
||||
|
||||
/// @dev Executes an Exchange transaction iff the maker and taker meet
|
||||
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
|
||||
/// the exchange function is a cancellation.
|
||||
/// Supported Exchange functions:
|
||||
/// batchFillOrders
|
||||
/// batchFillOrdersNoThrow
|
||||
/// batchFillOrKillOrders
|
||||
/// fillOrder
|
||||
/// fillOrderNoThrow
|
||||
/// fillOrKillOrder
|
||||
/// marketBuyOrders
|
||||
/// marketBuyOrdersNoThrow
|
||||
/// marketSellOrders
|
||||
/// marketSellOrdersNoThrow
|
||||
/// matchOrders
|
||||
/// cancelOrder
|
||||
/// batchCancelOrders
|
||||
/// cancelOrdersUpTo
|
||||
/// Trying to call any other exchange function will throw.
|
||||
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||
/// @param signerAddress Address of transaction signer.
|
||||
/// @param signedExchangeTransaction AbiV2 encoded calldata.
|
||||
/// @param signature Proof of signer transaction by signer.
|
||||
function executeTransaction(
|
||||
uint256 salt,
|
||||
address signerAddress,
|
||||
bytes calldata signedExchangeTransaction,
|
||||
bytes calldata signature
|
||||
)
|
||||
external
|
||||
{
|
||||
// Get accounts whose balances must be validated
|
||||
address[] memory addressesToValidate = _getAddressesToValidate(signerAddress);
|
||||
|
||||
// Validate account balances
|
||||
uint256 balanceThreshold = BALANCE_THRESHOLD;
|
||||
IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
|
||||
for (uint256 i = 0; i < addressesToValidate.length; ++i) {
|
||||
uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
|
||||
require(
|
||||
addressBalance >= balanceThreshold,
|
||||
"AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD"
|
||||
);
|
||||
}
|
||||
emit ValidatedAddresses(addressesToValidate);
|
||||
|
||||
LibZeroExTransaction.ZeroExTransaction memory transaction = LibZeroExTransaction.ZeroExTransaction({
|
||||
salt: salt,
|
||||
data: signedExchangeTransaction,
|
||||
signerAddress: signerAddress
|
||||
});
|
||||
|
||||
// All addresses are valid. Execute exchange function.
|
||||
EXCHANGE.executeTransaction(transaction, signature);
|
||||
}
|
||||
|
||||
/// @dev Constructs an array of addresses to be validated.
|
||||
/// Addresses depend on which Exchange function is to be called
|
||||
/// (defined by `signedExchangeTransaction` above).
|
||||
/// @param signerAddress Address of transaction signer.
|
||||
/// @return addressesToValidate Array of addresses to validate.
|
||||
function _getAddressesToValidate(address signerAddress)
|
||||
internal
|
||||
pure
|
||||
returns (address[] memory addressesToValidate)
|
||||
{
|
||||
bytes4 exchangeFunctionSelector = bytes4(_exchangeCalldataload(0));
|
||||
// solhint-disable expression-indent
|
||||
if (
|
||||
exchangeFunctionSelector == IExchange(address(0)).batchFillOrders.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).batchFillOrdersNoThrow.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).batchFillOrKillOrders.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).marketBuyOrders.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).marketBuyOrdersNoThrow.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).marketSellOrders.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).marketSellOrdersNoThrow.selector
|
||||
) {
|
||||
addressesToValidate = _loadMakerAddressesFromOrderArray(0);
|
||||
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||
} else if (
|
||||
exchangeFunctionSelector == IExchange(address(0)).fillOrder.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).fillOrderNoThrow.selector ||
|
||||
exchangeFunctionSelector == IExchange(address(0)).fillOrKillOrder.selector
|
||||
) {
|
||||
address makerAddress = _loadMakerAddressFromOrder(0);
|
||||
addressesToValidate = addressesToValidate.append(makerAddress);
|
||||
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||
} else if (exchangeFunctionSelector == IExchange(address(0)).matchOrders.selector) {
|
||||
address leftMakerAddress = _loadMakerAddressFromOrder(0);
|
||||
addressesToValidate = addressesToValidate.append(leftMakerAddress);
|
||||
address rightMakerAddress = _loadMakerAddressFromOrder(1);
|
||||
addressesToValidate = addressesToValidate.append(rightMakerAddress);
|
||||
addressesToValidate = addressesToValidate.append(signerAddress);
|
||||
} else if (
|
||||
exchangeFunctionSelector != IExchange(address(0)).cancelOrder.selector &&
|
||||
exchangeFunctionSelector != IExchange(address(0)).batchCancelOrders.selector &&
|
||||
exchangeFunctionSelector != IExchange(address(0)).cancelOrdersUpTo.selector
|
||||
) {
|
||||
revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
|
||||
}
|
||||
// solhint-enable expression-indent
|
||||
return addressesToValidate;
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE2.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;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
|
||||
|
||||
|
||||
contract MixinExchangeCalldata {
|
||||
|
||||
using LibAddressArray for address[];
|
||||
|
||||
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
|
||||
/// which is accessed through `signedExchangeTransaction`.
|
||||
/// @param offset Offset into the Exchange calldata.
|
||||
/// @return value Corresponding 32 byte value stored at `offset`.
|
||||
function _exchangeCalldataload(uint256 offset)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 value)
|
||||
{
|
||||
assembly {
|
||||
// Pointer to exchange transaction
|
||||
// 0x04 for calldata selector
|
||||
// 0x40 to access `signedExchangeTransaction`, which is the third parameter
|
||||
let exchangeTxPtr := calldataload(0x44)
|
||||
|
||||
// Offset into Exchange calldata
|
||||
// We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
|
||||
// 0x04 for calldata selector
|
||||
// 0x20 for length field of `signedExchangeTransaction`
|
||||
let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
|
||||
value := calldataload(exchangeCalldataOffset)
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// @dev Convenience function that skips the 4 byte selector when loading
|
||||
/// from the embedded Exchange calldata.
|
||||
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
|
||||
/// @return value Corresponding 32 byte value stored at `offset` + 4.
|
||||
function _loadExchangeData(uint256 offset)
|
||||
internal
|
||||
pure
|
||||
returns (bytes32 value)
|
||||
{
|
||||
value = _exchangeCalldataload(offset + 4);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// @dev Extracts the maker address from an order stored in the Exchange calldata
|
||||
/// (which is embedded in `signedExchangeTransaction`).
|
||||
/// @param orderParamIndex Index of the order in the Exchange function's signature.
|
||||
/// @return makerAddress The extracted maker address.
|
||||
function _loadMakerAddressFromOrder(uint256 orderParamIndex)
|
||||
internal
|
||||
pure
|
||||
returns (address makerAddress)
|
||||
{
|
||||
uint256 orderOffsetInBytes = orderParamIndex * 32;
|
||||
uint256 orderPtr = uint256(_loadExchangeData(orderOffsetInBytes));
|
||||
makerAddress = address(uint256(_loadExchangeData(orderPtr)));
|
||||
return makerAddress;
|
||||
}
|
||||
|
||||
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
|
||||
/// (which is embedded in `signedExchangeTransaction`).
|
||||
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
|
||||
/// @return makerAddresses The extracted maker addresses.
|
||||
function _loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
|
||||
internal
|
||||
pure
|
||||
returns (address[] memory makerAddresses)
|
||||
{
|
||||
uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
|
||||
uint256 orderArrayPtr = uint256(_loadExchangeData(orderArrayOffsetInBytes));
|
||||
uint256 orderArrayLength = uint256(_loadExchangeData(orderArrayPtr));
|
||||
uint256 orderArrayLengthInBytes = orderArrayLength * 32;
|
||||
uint256 orderArrayElementPtr = orderArrayPtr + 32;
|
||||
uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
|
||||
for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
|
||||
uint256 orderPtr = uint256(_loadExchangeData(orderPtrOffset));
|
||||
address makerAddress = address(uint256(_loadExchangeData(orderPtr + orderArrayElementPtr)));
|
||||
makerAddresses = makerAddresses.append(makerAddress);
|
||||
}
|
||||
return makerAddresses;
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IBalanceThresholdFilterCore {
|
||||
|
||||
/// @dev Executes an Exchange transaction iff the maker and taker meet
|
||||
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
|
||||
/// the exchange function is a cancellation.
|
||||
/// Supported Exchange functions:
|
||||
/// - batchFillOrders
|
||||
/// - batchFillOrdersNoThrow
|
||||
/// - batchFillOrKillOrders
|
||||
/// - fillOrder
|
||||
/// - fillOrderNoThrow
|
||||
/// - fillOrKillOrder
|
||||
/// - marketBuyOrders
|
||||
/// - marketBuyOrdersNoThrow
|
||||
/// - marketSellOrders
|
||||
/// - marketSellOrdersNoThrow
|
||||
/// - matchOrders
|
||||
/// - cancelOrder
|
||||
/// - batchCancelOrders
|
||||
/// - cancelOrdersUpTo
|
||||
/// Trying to call any other exchange function will throw.
|
||||
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
|
||||
/// @param signerAddress Address of transaction signer.
|
||||
/// @param signedExchangeTransaction AbiV2 encoded calldata.
|
||||
/// @param signature Proof of signer transaction by signer.
|
||||
function executeTransaction(
|
||||
uint256 salt,
|
||||
address signerAddress,
|
||||
bytes calldata signedExchangeTransaction,
|
||||
bytes calldata signature
|
||||
)
|
||||
external;
|
||||
}
|
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
|
||||
|
||||
contract DutchAuction {
|
||||
|
||||
using LibBytes for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
|
||||
struct AuctionDetails {
|
||||
uint256 beginTimeSeconds; // Auction begin unix timestamp: sellOrder.makerAssetData
|
||||
uint256 endTimeSeconds; // Auction end unix timestamp: sellOrder.expiryTimeSeconds
|
||||
uint256 beginAmount; // Auction begin amount: sellOrder.makerAssetData
|
||||
uint256 endAmount; // Auction end amount: sellOrder.takerAssetAmount
|
||||
uint256 currentAmount; // Calculated amount given block.timestamp
|
||||
uint256 currentTimeSeconds; // block.timestamp
|
||||
}
|
||||
|
||||
constructor (address _exchange)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
}
|
||||
|
||||
/// @dev Matches the buy and sell orders at an amount given the following: the current block time, the auction
|
||||
/// start time and the auction begin amount. The sell order is a an order at the lowest amount
|
||||
/// at the end of the auction. Excess from the match is transferred to the seller.
|
||||
/// Over time the price moves from beginAmount to endAmount given the current block.timestamp.
|
||||
/// sellOrder.expiryTimeSeconds is the end time of the auction.
|
||||
/// sellOrder.takerAssetAmount is the end amount of the auction (lowest possible amount).
|
||||
/// sellOrder.makerAssetData is the ABI encoded Asset Proxy data with the following data appended
|
||||
/// buyOrder.makerAssetData is the buyers bid on the auction, must meet the amount for the current block timestamp
|
||||
/// (uint256 beginTimeSeconds, uint256 beginAmount).
|
||||
/// This function reverts in the following scenarios:
|
||||
/// * Auction has not started (auctionDetails.currentTimeSeconds < auctionDetails.beginTimeSeconds)
|
||||
/// * Auction has expired (auctionDetails.endTimeSeconds < auctionDetails.currentTimeSeconds)
|
||||
/// * Amount is invalid: Buy order amount is too low (buyOrder.makerAssetAmount < auctionDetails.currentAmount)
|
||||
/// * Amount is invalid: Invalid begin amount (auctionDetails.beginAmount > auctionDetails.endAmount)
|
||||
/// * Any failure in the 0x Match Orders
|
||||
/// @param buyOrder The Buyer's order. This order is for the current expected price of the auction.
|
||||
/// @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction).
|
||||
/// @param buySignature Proof that order was created by the buyer.
|
||||
/// @param sellSignature Proof that order was created by the seller.
|
||||
/// @return matchedFillResults amounts filled and fees paid by maker and taker of matched orders.
|
||||
function matchOrders(
|
||||
LibOrder.Order memory buyOrder,
|
||||
LibOrder.Order memory sellOrder,
|
||||
bytes memory buySignature,
|
||||
bytes memory sellSignature
|
||||
)
|
||||
public
|
||||
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
|
||||
{
|
||||
AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder);
|
||||
// Ensure the auction has not yet started
|
||||
require(
|
||||
auctionDetails.currentTimeSeconds >= auctionDetails.beginTimeSeconds,
|
||||
"AUCTION_NOT_STARTED"
|
||||
);
|
||||
// Ensure the auction has not expired. This will fail later in 0x but we can save gas by failing early
|
||||
require(
|
||||
sellOrder.expirationTimeSeconds > auctionDetails.currentTimeSeconds,
|
||||
"AUCTION_EXPIRED"
|
||||
);
|
||||
// Validate the buyer amount is greater than the current auction amount
|
||||
require(
|
||||
buyOrder.makerAssetAmount >= auctionDetails.currentAmount,
|
||||
"INVALID_AMOUNT"
|
||||
);
|
||||
// Match orders, maximally filling `buyOrder`
|
||||
matchedFillResults = EXCHANGE.matchOrders(
|
||||
buyOrder,
|
||||
sellOrder,
|
||||
buySignature,
|
||||
sellSignature
|
||||
);
|
||||
// The difference in sellOrder.takerAssetAmount and current amount is given as spread to the matcher
|
||||
// This may include additional spread from the buyOrder.makerAssetAmount and the currentAmount.
|
||||
// e.g currentAmount is 30, sellOrder.takerAssetAmount is 10 and buyOrder.makerAssetamount is 40.
|
||||
// 10 (40-30) is returned to the buyer, 20 (30-10) sent to the seller and 10 has previously
|
||||
// been transferred to the seller during matchOrders
|
||||
uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
|
||||
if (leftMakerAssetSpreadAmount > 0) {
|
||||
// ERC20 Asset data itself is encoded as follows:
|
||||
//
|
||||
// | Area | Offset | Length | Contents |
|
||||
// |----------|--------|---------|-------------------------------------|
|
||||
// | Header | 0 | 4 | function selector |
|
||||
// | Params | | 1 * 32 | function parameters: |
|
||||
// | | 4 | 12 | 1. token address padding |
|
||||
// | | 16 | 20 | 2. token address |
|
||||
bytes memory assetData = sellOrder.takerAssetData;
|
||||
address token = assetData.readAddress(16);
|
||||
// Calculate the excess from the buy order. This can occur if the buyer sends in a higher
|
||||
// amount than the calculated current amount
|
||||
uint256 buyerExcessAmount = buyOrder.makerAssetAmount.safeSub(auctionDetails.currentAmount);
|
||||
uint256 sellerExcessAmount = leftMakerAssetSpreadAmount.safeSub(buyerExcessAmount);
|
||||
// Return the difference between auctionDetails.currentAmount and sellOrder.takerAssetAmount
|
||||
// to the seller
|
||||
if (sellerExcessAmount > 0) {
|
||||
IERC20Token(token).transfer(sellOrder.makerAddress, sellerExcessAmount);
|
||||
}
|
||||
// Return the difference between buyOrder.makerAssetAmount and auctionDetails.currentAmount
|
||||
// to the buyer
|
||||
if (buyerExcessAmount > 0) {
|
||||
IERC20Token(token).transfer(buyOrder.makerAddress, buyerExcessAmount);
|
||||
}
|
||||
}
|
||||
return matchedFillResults;
|
||||
}
|
||||
|
||||
/// @dev Calculates the Auction Details for the given order
|
||||
/// @param order The sell order
|
||||
/// @return AuctionDetails
|
||||
function getAuctionDetails(LibOrder.Order memory order)
|
||||
public
|
||||
returns (AuctionDetails memory auctionDetails)
|
||||
{
|
||||
uint256 makerAssetDataLength = order.makerAssetData.length;
|
||||
// It is unknown the encoded data of makerAssetData, we assume the last 64 bytes
|
||||
// are the Auction Details encoding.
|
||||
// Auction Details is encoded as follows:
|
||||
//
|
||||
// | Area | Offset | Length | Contents |
|
||||
// |----------|--------|---------|-------------------------------------|
|
||||
// | Params | | 2 * 32 | parameters: |
|
||||
// | | -64 | 32 | 1. auction begin unix timestamp |
|
||||
// | | -32 | 32 | 2. auction begin begin amount |
|
||||
// ERC20 asset data length is 4+32, 64 for auction details results in min length 100
|
||||
require(
|
||||
makerAssetDataLength >= 100,
|
||||
"INVALID_ASSET_DATA"
|
||||
);
|
||||
uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength - 64);
|
||||
uint256 auctionBeginAmount = order.makerAssetData.readUint256(makerAssetDataLength - 32);
|
||||
// Ensure the auction has a valid begin time
|
||||
require(
|
||||
order.expirationTimeSeconds > auctionBeginTimeSeconds,
|
||||
"INVALID_BEGIN_TIME"
|
||||
);
|
||||
uint256 auctionDurationSeconds = order.expirationTimeSeconds-auctionBeginTimeSeconds;
|
||||
// Ensure the auction goes from high to low
|
||||
uint256 minAmount = order.takerAssetAmount;
|
||||
require(
|
||||
auctionBeginAmount > minAmount,
|
||||
"INVALID_AMOUNT"
|
||||
);
|
||||
uint256 amountDelta = auctionBeginAmount-minAmount;
|
||||
// solhint-disable-next-line not-rely-on-time
|
||||
uint256 timestamp = block.timestamp;
|
||||
auctionDetails.beginTimeSeconds = auctionBeginTimeSeconds;
|
||||
auctionDetails.endTimeSeconds = order.expirationTimeSeconds;
|
||||
auctionDetails.beginAmount = auctionBeginAmount;
|
||||
auctionDetails.endAmount = minAmount;
|
||||
auctionDetails.currentTimeSeconds = timestamp;
|
||||
|
||||
uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp;
|
||||
if (timestamp < auctionBeginTimeSeconds) {
|
||||
// If the auction has not yet begun the current amount is the auctionBeginAmount
|
||||
auctionDetails.currentAmount = auctionBeginAmount;
|
||||
} else if (timestamp >= order.expirationTimeSeconds) {
|
||||
// If the auction has ended the current amount is the minAmount.
|
||||
// Auction end time is guaranteed by 0x Exchange due to the order expiration
|
||||
auctionDetails.currentAmount = minAmount;
|
||||
} else {
|
||||
auctionDetails.currentAmount = minAmount.safeAdd(
|
||||
remainingDurationSeconds.safeMul(amountDelta).safeDiv(auctionDurationSeconds)
|
||||
);
|
||||
}
|
||||
return auctionDetails;
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "./LibForwarderRichErrors.sol";
|
||||
import "./rich-errors/LibAssetDataTransferRichErrors.sol";
|
||||
|
||||
|
||||
library LibAssetDataTransfer {
|
||||
@@ -82,7 +82,7 @@ library LibAssetDataTransfer {
|
||||
amount
|
||||
);
|
||||
} else if (proxyId != IAssetData(address(0)).StaticCall.selector) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
|
||||
LibRichErrors.rrevert(LibAssetDataTransferRichErrors.UnsupportedAssetProxyError(
|
||||
proxyId
|
||||
));
|
||||
}
|
||||
@@ -165,7 +165,7 @@ library LibAssetDataTransfer {
|
||||
internal
|
||||
{
|
||||
if (amount != 1) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.Erc721AmountMustEqualOneError(
|
||||
LibRichErrors.rrevert(LibAssetDataTransferRichErrors.Erc721AmountMustEqualOneError(
|
||||
amount
|
||||
));
|
||||
}
|
@@ -12,30 +12,62 @@
|
||||
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.
|
||||
limitations \under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./rich-errors/LibWethUtilsRichErrors.sol";
|
||||
|
||||
|
||||
contract MixinWeth is
|
||||
LibConstants
|
||||
{
|
||||
contract MixinWethUtils {
|
||||
|
||||
uint256 constant internal MAX_UINT256 = uint256(-1);
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IEtherToken internal WETH;
|
||||
bytes internal WETH_ASSET_DATA;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
constructor (
|
||||
address exchange,
|
||||
address weth
|
||||
)
|
||||
public
|
||||
{
|
||||
WETH = IEtherToken(weth);
|
||||
WETH_ASSET_DATA = abi.encodeWithSelector(
|
||||
IAssetData(address(0)).ERC20Token.selector,
|
||||
weth
|
||||
);
|
||||
|
||||
address proxyAddress = IExchange(exchange).getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
|
||||
if (proxyAddress == address(0)) {
|
||||
LibRichErrors.rrevert(LibWethUtilsRichErrors.UnregisteredAssetProxyError());
|
||||
}
|
||||
WETH.approve(proxyAddress, MAX_UINT256);
|
||||
|
||||
address protocolFeeCollector = IExchange(exchange).protocolFeeCollector();
|
||||
if (protocolFeeCollector != address(0)) {
|
||||
WETH.approve(protocolFeeCollector, MAX_UINT256);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Default payable function, this allows us to withdraw WETH
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{
|
||||
if (msg.sender != address(ETHER_TOKEN)) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.DefaultFunctionWethContractOnlyError(
|
||||
if (msg.sender != address(WETH)) {
|
||||
LibRichErrors.rrevert(LibWethUtilsRichErrors.DefaultFunctionWethContractOnlyError(
|
||||
msg.sender
|
||||
));
|
||||
}
|
||||
@@ -55,7 +87,7 @@ contract MixinWeth is
|
||||
uint256 feesLen = ethFeeAmounts.length;
|
||||
// ethFeeAmounts len must equal feeRecipients len
|
||||
if (feesLen != feeRecipients.length) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.EthFeeLengthMismatchError(
|
||||
LibRichErrors.rrevert(LibWethUtilsRichErrors.EthFeeLengthMismatchError(
|
||||
feesLen,
|
||||
feeRecipients.length
|
||||
));
|
||||
@@ -69,7 +101,7 @@ contract MixinWeth is
|
||||
uint256 ethFeeAmount = ethFeeAmounts[i];
|
||||
// Ensure there is enough ETH to pay the fee
|
||||
if (ethRemaining < ethFeeAmount) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.InsufficientEthForFeeError(
|
||||
LibRichErrors.rrevert(LibWethUtilsRichErrors.InsufficientEthForFeeError(
|
||||
ethFeeAmount,
|
||||
ethRemaining
|
||||
));
|
||||
@@ -80,37 +112,24 @@ contract MixinWeth is
|
||||
}
|
||||
|
||||
// Convert remaining ETH to WETH.
|
||||
ETHER_TOKEN.deposit.value(ethRemaining)();
|
||||
WETH.deposit.value(ethRemaining)();
|
||||
|
||||
return ethRemaining;
|
||||
}
|
||||
|
||||
/// @dev Refunds any excess ETH to msg.sender.
|
||||
/// @param initialWethAmount Amount of WETH available after transferring affiliate fees.
|
||||
/// @param wethSpent Amount of WETH spent when filling orders.
|
||||
function _transferEthRefund(
|
||||
uint256 initialWethAmount,
|
||||
uint256 wethSpent
|
||||
/// @dev Unwraps WETH and transfers ETH to msg.sender.
|
||||
/// @param transferAmount Amount of WETH balance to unwrap and transfer.
|
||||
function _unwrapAndTransferEth(
|
||||
uint256 transferAmount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Ensure that no extra WETH owned by this contract has been spent.
|
||||
if (wethSpent > initialWethAmount) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||
wethSpent,
|
||||
msg.value
|
||||
));
|
||||
}
|
||||
|
||||
// Calculate amount of WETH that hasn't been spent.
|
||||
uint256 wethRemaining = initialWethAmount.safeSub(wethSpent);
|
||||
|
||||
// Do nothing if no WETH remaining
|
||||
if (wethRemaining > 0) {
|
||||
// Convert remaining WETH to ETH
|
||||
ETHER_TOKEN.withdraw(wethRemaining);
|
||||
// Transfer remaining ETH to sender
|
||||
msg.sender.transfer(wethRemaining);
|
||||
// Do nothing if amount is zero
|
||||
if (transferAmount > 0) {
|
||||
// Convert WETH to ETH
|
||||
WETH.withdraw(transferAmount);
|
||||
// Transfer ETH to sender
|
||||
msg.sender.transfer(transferAmount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./interfaces/IAssets.sol";
|
||||
|
||||
|
||||
contract MixinAssets is
|
||||
IAssets,
|
||||
Ownable,
|
||||
LibConstants
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
|
||||
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||
/// used to withdraw assets that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
_transferAssetToSender(assetData, amount);
|
||||
}
|
||||
|
||||
/// @dev Approves or disapproves an AssetProxy to spend asset.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to approve for respective proxy.
|
||||
function approveAssetProxy(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
|
||||
if (proxyId == ERC20_DATA_ID) {
|
||||
_approveERC20Token(assetData, amount);
|
||||
} else if (proxyId == ERC721_DATA_ID) {
|
||||
_approveERC721Token(assetData, amount);
|
||||
} else {
|
||||
revert("UNSUPPORTED_ASSET_PROXY");
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Transfers given amount of asset to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferAssetToSender(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
|
||||
if (proxyId == ERC20_DATA_ID) {
|
||||
_transferERC20Token(assetData, amount);
|
||||
} else if (proxyId == ERC721_DATA_ID) {
|
||||
_transferERC721Token(assetData, amount);
|
||||
} else {
|
||||
revert("UNSUPPORTED_ASSET_PROXY");
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20 assetData and transfers given amount to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferERC20Token(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// 4 byte id + 12 0 bytes before ABI encoded token address.
|
||||
address token = assetData.readAddress(16);
|
||||
|
||||
// Transfer tokens.
|
||||
// We do a raw call so we can check the success separate
|
||||
// from the return data.
|
||||
(bool success,) = token.call(abi.encodeWithSelector(
|
||||
ERC20_TRANSFER_SELECTOR,
|
||||
msg.sender,
|
||||
amount
|
||||
));
|
||||
require(
|
||||
success,
|
||||
"TRANSFER_FAILED"
|
||||
);
|
||||
|
||||
// Check return data.
|
||||
// If there is no return data, we assume the token incorrectly
|
||||
// does not return a bool. In this case we expect it to revert
|
||||
// on failure, which was handled above.
|
||||
// If the token does return data, we require that it is a single
|
||||
// value that evaluates to true.
|
||||
assembly {
|
||||
if returndatasize {
|
||||
success := 0
|
||||
if eq(returndatasize, 32) {
|
||||
// First 64 bytes of memory are reserved scratch space
|
||||
returndatacopy(0, 0, 32)
|
||||
success := mload(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
require(
|
||||
success,
|
||||
"TRANSFER_FAILED"
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferERC721Token(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
require(
|
||||
amount == 1,
|
||||
"INVALID_AMOUNT"
|
||||
);
|
||||
// Decode asset data.
|
||||
// 4 byte id + 12 0 bytes before ABI encoded token address.
|
||||
address token = assetData.readAddress(16);
|
||||
// 4 byte id + 32 byte ABI encoded token address before token id.
|
||||
uint256 tokenId = assetData.readUint256(36);
|
||||
|
||||
// Perform transfer.
|
||||
IERC721Token(token).transferFrom(
|
||||
address(this),
|
||||
msg.sender,
|
||||
tokenId
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sets approval for ERC20 AssetProxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to approve for respective proxy.
|
||||
function _approveERC20Token(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
address token = assetData.readAddress(16);
|
||||
require(
|
||||
IERC20Token(token).approve(ERC20_PROXY_ADDRESS, amount),
|
||||
"APPROVAL_FAILED"
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Sets approval for ERC721 AssetProxy.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to approve for respective proxy.
|
||||
function _approveERC721Token(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
address token = assetData.readAddress(16);
|
||||
bool approval = amount >= 1;
|
||||
IERC721Token(token).setApprovalForAll(ERC721_PROXY_ADDRESS, approval);
|
||||
}
|
||||
}
|
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./libs/LibConstants.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
|
||||
|
||||
contract MixinMatchOrders is
|
||||
Ownable,
|
||||
LibConstants
|
||||
{
|
||||
/// @dev Match two complementary orders that have a profitable spread.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the left order is then used to fill the right order as much as possible.
|
||||
/// This results in a spread being taken in terms of both assets. The spread is held within this contract.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftSignature Proof that order was created by the left maker.
|
||||
/// @param rightSignature Proof that order was created by the right maker.
|
||||
function matchOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public
|
||||
onlyOwner
|
||||
{
|
||||
// Match orders, maximally filling `leftOrder`
|
||||
LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
|
||||
leftOrder,
|
||||
rightOrder,
|
||||
leftSignature,
|
||||
rightSignature
|
||||
);
|
||||
|
||||
uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
|
||||
uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
|
||||
|
||||
// Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
|
||||
if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
|
||||
rightOrder.makerAssetData = leftOrder.takerAssetData;
|
||||
rightOrder.takerAssetData = leftOrder.makerAssetData;
|
||||
|
||||
// Query `rightOrder` info to check if it has been completely filled
|
||||
// We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
|
||||
LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
|
||||
|
||||
// Do not attempt to call `fillOrder` if order has been completely filled
|
||||
if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We do not need to pass in a signature since it was already validated in the `matchOrders` call
|
||||
EXCHANGE.fillOrder(
|
||||
rightOrder,
|
||||
leftMakerAssetSpreadAmount,
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract IAssets {
|
||||
|
||||
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||
/// used to withdraw assets that were accidentally sent to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to withdraw.
|
||||
function withdrawAsset(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Approves or disapproves an AssetProxy to spend asset.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to approve for respective proxy.
|
||||
function approveAssetProxy(
|
||||
bytes calldata assetData,
|
||||
uint256 amount
|
||||
)
|
||||
external;
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
contract IMatchOrders {
|
||||
|
||||
/// @dev Match two complementary orders that have a profitable spread.
|
||||
/// Each order is filled at their respective price point. However, the calculations are
|
||||
/// carried out as though the orders are both being filled at the right order's price point.
|
||||
/// The profit made by the left order is then used to fill the right order as much as possible.
|
||||
/// This results in a spread being taken in terms of both assets. The spread is held within this contract.
|
||||
/// @param leftOrder First order to match.
|
||||
/// @param rightOrder Second order to match.
|
||||
/// @param leftSignature Proof that order was created by the left maker.
|
||||
/// @param rightSignature Proof that order was created by the right maker.
|
||||
function matchOrders(
|
||||
LibOrder.Order memory leftOrder,
|
||||
LibOrder.Order memory rightOrder,
|
||||
bytes memory leftSignature,
|
||||
bytes memory rightSignature
|
||||
)
|
||||
public;
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
|
||||
import "./IMatchOrders.sol";
|
||||
import "./IAssets.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract IOrderMatcher is
|
||||
IOwnable,
|
||||
IMatchOrders,
|
||||
IAssets
|
||||
{}
|
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
|
||||
|
||||
contract LibConstants {
|
||||
|
||||
// bytes4(keccak256("transfer(address,uint256)"))
|
||||
bytes4 constant internal ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
|
||||
// bytes4(keccak256("ERC20Token(address)"))
|
||||
bytes4 constant internal ERC20_DATA_ID = 0xf47261b0;
|
||||
// bytes4(keccak256("ERC721Token(address,uint256)"))
|
||||
bytes4 constant internal ERC721_DATA_ID = 0x02571792;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
address internal ERC20_PROXY_ADDRESS;
|
||||
address internal ERC721_PROXY_ADDRESS;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (address _exchange)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
|
||||
ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
|
||||
require(
|
||||
ERC20_PROXY_ADDRESS != address(0),
|
||||
"UNREGISTERED_ASSET_PROXY"
|
||||
);
|
||||
|
||||
ERC721_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC721_DATA_ID);
|
||||
require(
|
||||
ERC721_PROXY_ADDRESS != address(0),
|
||||
"UNREGISTERED_ASSET_PROXY"
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
library LibAssetDataTransferRichErrors {
|
||||
|
||||
// bytes4(keccak256("UnsupportedAssetProxyError(bytes4)"))
|
||||
bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR =
|
||||
0x7996a271;
|
||||
|
||||
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
|
||||
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||
0xbaffa474;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function UnsupportedAssetProxyError(
|
||||
bytes4 proxyId
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR,
|
||||
proxyId
|
||||
);
|
||||
}
|
||||
|
||||
function Erc721AmountMustEqualOneError(
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR,
|
||||
amount
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
library LibWethUtilsRichErrors {
|
||||
|
||||
// bytes4(keccak256("UnregisteredAssetProxyError()"))
|
||||
bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
|
||||
0xf3b96b8d;
|
||||
|
||||
// bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)"))
|
||||
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
||||
0xecf40fd9;
|
||||
|
||||
// bytes4(keccak256("DefaultFunctionWethContractOnlyError(address)"))
|
||||
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
|
||||
0x08b18698;
|
||||
|
||||
// bytes4(keccak256("EthFeeLengthMismatchError(uint256,uint256)"))
|
||||
bytes4 internal constant ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR =
|
||||
0x3ecb6ceb;
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
function UnregisteredAssetProxyError()
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR);
|
||||
}
|
||||
|
||||
function InsufficientEthForFeeError(
|
||||
uint256 ethFeeRequired,
|
||||
uint256 ethAvailable
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR,
|
||||
ethFeeRequired,
|
||||
ethAvailable
|
||||
);
|
||||
}
|
||||
|
||||
function DefaultFunctionWethContractOnlyError(
|
||||
address senderAddress
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR,
|
||||
senderAddress
|
||||
);
|
||||
}
|
||||
|
||||
function EthFeeLengthMismatchError(
|
||||
uint256 ethFeesLength,
|
||||
uint256 feeRecipientsLength
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodeWithSelector(
|
||||
ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR,
|
||||
ethFeesLength,
|
||||
feeRecipientsLength
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "5.1.3",
|
||||
"version": "6.0.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,8 +38,7 @@
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "DutchAuction,OrderMatcher,BalanceThresholdFilter",
|
||||
"abis": "./generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Exchange|ExchangeWrapper|OrderMatcher|WETH9).json",
|
||||
"abis": "./test/generated-artifacts/@(LibAssetDataTransfer|LibAssetDataTransferRichErrors|LibWethUtilsRichErrors|MixinWethUtils).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -52,24 +51,24 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.1.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.4",
|
||||
"@0x/contracts-erc20": "^3.0.4",
|
||||
"@0x/contracts-erc721": "^3.0.4",
|
||||
"@0x/contracts-exchange": "^3.1.0",
|
||||
"@0x/contracts-exchange-libs": "^4.1.0",
|
||||
"@0x/contracts-gen": "^2.0.4",
|
||||
"@0x/contracts-test-utils": "^5.1.1",
|
||||
"@0x/contracts-utils": "^4.1.0",
|
||||
"@0x/dev-utils": "^3.1.1",
|
||||
"@0x/order-utils": "^10.1.1",
|
||||
"@0x/sol-compiler": "^4.0.4",
|
||||
"@0x/abi-gen": "^5.1.2",
|
||||
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||
"@0x/contracts-dev-utils": "^1.0.6",
|
||||
"@0x/contracts-erc20": "^3.0.6",
|
||||
"@0x/contracts-erc721": "^3.0.6",
|
||||
"@0x/contracts-exchange": "^3.1.2",
|
||||
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||
"@0x/contracts-gen": "^2.0.6",
|
||||
"@0x/contracts-test-utils": "^5.1.3",
|
||||
"@0x/contracts-utils": "^4.2.1",
|
||||
"@0x/dev-utils": "^3.1.3",
|
||||
"@0x/order-utils": "^10.1.3",
|
||||
"@0x/sol-compiler": "^4.0.6",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@0x/utils": "^5.3.0",
|
||||
"@0x/web3-wrapper": "^7.0.5",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -91,7 +90,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.1.0",
|
||||
"@0x/base-contract": "^6.1.2",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
|
@@ -5,17 +5,13 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as BalanceThresholdFilter from '../generated-artifacts/BalanceThresholdFilter.json';
|
||||
import * as DutchAuction from '../generated-artifacts/DutchAuction.json';
|
||||
import * as Exchange from '../generated-artifacts/Exchange.json';
|
||||
import * as ExchangeWrapper from '../generated-artifacts/ExchangeWrapper.json';
|
||||
import * as OrderMatcher from '../generated-artifacts/OrderMatcher.json';
|
||||
import * as WETH9 from '../generated-artifacts/WETH9.json';
|
||||
import * as LibAssetDataTransfer from '../generated-artifacts/LibAssetDataTransfer.json';
|
||||
import * as LibAssetDataTransferRichErrors from '../generated-artifacts/LibAssetDataTransferRichErrors.json';
|
||||
import * as LibWethUtilsRichErrors from '../generated-artifacts/LibWethUtilsRichErrors.json';
|
||||
import * as MixinWethUtils from '../generated-artifacts/MixinWethUtils.json';
|
||||
export const artifacts = {
|
||||
WETH9: WETH9 as ContractArtifact,
|
||||
ExchangeWrapper: ExchangeWrapper as ContractArtifact,
|
||||
Exchange: Exchange as ContractArtifact,
|
||||
BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
|
||||
DutchAuction: DutchAuction as ContractArtifact,
|
||||
OrderMatcher: OrderMatcher as ContractArtifact,
|
||||
LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact,
|
||||
MixinWethUtils: MixinWethUtils as ContractArtifact,
|
||||
LibAssetDataTransferRichErrors: LibAssetDataTransferRichErrors as ContractArtifact,
|
||||
LibWethUtilsRichErrors: LibWethUtilsRichErrors as ContractArtifact,
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export { BalanceThresholdFilterContract, DutchAuctionContract, OrderMatcherContract } from './wrappers';
|
||||
export { LibAssetDataTransferRevertErrors, MixinWethUtilsRevertErrors } from '@0x/utils';
|
||||
export {
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/balance_threshold_filter';
|
||||
export * from '../generated-wrappers/dutch_auction';
|
||||
export * from '../generated-wrappers/order_matcher';
|
||||
export * from '../generated-wrappers/lib_asset_data_transfer';
|
||||
export * from '../generated-wrappers/lib_asset_data_transfer_rich_errors';
|
||||
export * from '../generated-wrappers/lib_weth_utils_rich_errors';
|
||||
export * from '../generated-wrappers/mixin_weth_utils';
|
||||
|
17
contracts/extensions/test/artifacts.ts
Normal file
17
contracts/extensions/test/artifacts.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* -----------------------------------------------------------------------------
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as LibAssetDataTransfer from '../test/generated-artifacts/LibAssetDataTransfer.json';
|
||||
import * as LibAssetDataTransferRichErrors from '../test/generated-artifacts/LibAssetDataTransferRichErrors.json';
|
||||
import * as LibWethUtilsRichErrors from '../test/generated-artifacts/LibWethUtilsRichErrors.json';
|
||||
import * as MixinWethUtils from '../test/generated-artifacts/MixinWethUtils.json';
|
||||
export const artifacts = {
|
||||
LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact,
|
||||
MixinWethUtils: MixinWethUtils as ContractArtifact,
|
||||
LibAssetDataTransferRichErrors: LibAssetDataTransferRichErrors as ContractArtifact,
|
||||
LibWethUtilsRichErrors: LibWethUtilsRichErrors as ContractArtifact,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@@ -1,368 +0,0 @@
|
||||
import { ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy';
|
||||
import { DevUtilsContract } from '@0x/contracts-dev-utils';
|
||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
import { ExchangeContract } from '@0x/contracts-exchange';
|
||||
import {
|
||||
chaiSetup,
|
||||
constants,
|
||||
ContractName,
|
||||
ERC20BalancesByOwner,
|
||||
getLatestBlockTimestampAsync,
|
||||
OrderFactory,
|
||||
provider,
|
||||
txDefaults,
|
||||
web3Wrapper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DutchAuctionContract, DutchAuctionTestWrapper, WETH9Contract } from './wrappers';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
|
||||
import { encodeDutchAuctionAssetData } from './utils';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
const DECIMALS_DEFAULT = 18;
|
||||
|
||||
describe(ContractName.DutchAuction, () => {
|
||||
let chainId: number;
|
||||
let makerAddress: string;
|
||||
let owner: string;
|
||||
let takerAddress: string;
|
||||
let feeRecipientAddress: string;
|
||||
let defaultMakerAssetAddress: string;
|
||||
|
||||
let zrxToken: DummyERC20TokenContract;
|
||||
let erc20TokenA: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let dutchAuctionContract: DutchAuctionContract;
|
||||
let wethContract: WETH9Contract;
|
||||
|
||||
let sellerOrderFactory: OrderFactory;
|
||||
let buyerOrderFactory: OrderFactory;
|
||||
let erc20Wrapper: ERC20Wrapper;
|
||||
let erc20Balances: ERC20BalancesByOwner;
|
||||
let currentBlockTimestamp: number;
|
||||
let auctionBeginTimeSeconds: BigNumber;
|
||||
let auctionEndTimeSeconds: BigNumber;
|
||||
let auctionBeginAmount: BigNumber;
|
||||
let auctionEndAmount: BigNumber;
|
||||
let sellOrder: SignedOrder;
|
||||
let buyOrder: SignedOrder;
|
||||
let erc721MakerAssetIds: BigNumber[];
|
||||
const tenMinutesInSeconds = 10 * 60;
|
||||
|
||||
let dutchAuctionTestWrapper: DutchAuctionTestWrapper;
|
||||
let defaultERC20MakerAssetData: string;
|
||||
|
||||
const devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
|
||||
chainId = await providerUtils.getChainIdAsync(provider);
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
|
||||
|
||||
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
|
||||
|
||||
const numDummyErc20ToDeploy = 2;
|
||||
[erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
|
||||
numDummyErc20ToDeploy,
|
||||
constants.DUMMY_TOKEN_DECIMALS,
|
||||
);
|
||||
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
|
||||
await erc20Wrapper.setBalancesAndAllowancesAsync();
|
||||
|
||||
const erc721Wrapper = new ERC721Wrapper(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];
|
||||
|
||||
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults, artifacts);
|
||||
erc20Wrapper.addDummyTokenContract(wethContract as any);
|
||||
|
||||
const zrxAssetData = await devUtils.encodeERC20AssetData(zrxToken.address).callAsync();
|
||||
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Exchange,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
zrxAssetData,
|
||||
new BigNumber(chainId),
|
||||
);
|
||||
await exchangeInstance.registerAssetProxy.awaitTransactionSuccessAsync(erc20Proxy.address, {
|
||||
from: owner,
|
||||
});
|
||||
await exchangeInstance.registerAssetProxy.awaitTransactionSuccessAsync(erc721Proxy.address, {
|
||||
from: owner,
|
||||
});
|
||||
|
||||
await erc20Proxy.addAuthorizedAddress(exchangeInstance.address).sendTransactionAsync({
|
||||
from: owner,
|
||||
});
|
||||
await erc721Proxy.addAuthorizedAddress(exchangeInstance.address).sendTransactionAsync({
|
||||
from: owner,
|
||||
});
|
||||
|
||||
const dutchAuctionInstance = await DutchAuctionContract.deployFrom0xArtifactAsync(
|
||||
artifacts.DutchAuction,
|
||||
provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
exchangeInstance.address,
|
||||
);
|
||||
dutchAuctionContract = new DutchAuctionContract(dutchAuctionInstance.address, provider);
|
||||
dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider);
|
||||
|
||||
defaultMakerAssetAddress = erc20TokenA.address;
|
||||
const defaultTakerAssetAddress = wethContract.address;
|
||||
|
||||
// Set up taker WETH balance and allowance
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await wethContract.deposit.sendTransactionAsync({
|
||||
from: takerAddress,
|
||||
value: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT),
|
||||
}),
|
||||
);
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await wethContract
|
||||
.approve(erc20Proxy.address, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)
|
||||
.sendTransactionAsync({ from: takerAddress }),
|
||||
);
|
||||
web3Wrapper.abiDecoder.addABI(exchangeInstance.abi);
|
||||
web3Wrapper.abiDecoder.addABI(zrxToken.abi);
|
||||
erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address);
|
||||
|
||||
currentBlockTimestamp = await getLatestBlockTimestampAsync();
|
||||
// Default auction begins 10 minutes ago
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds);
|
||||
// Default auction ends 10 from now
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds);
|
||||
auctionBeginAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT);
|
||||
auctionEndAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT);
|
||||
|
||||
// Default sell order and buy order are exact mirrors
|
||||
const sellerDefaultOrderParams = {
|
||||
salt: generatePseudoRandomSalt(),
|
||||
makerAddress,
|
||||
feeRecipientAddress,
|
||||
// taker address or sender address should be set to the ducth auction contract
|
||||
takerAddress: dutchAuctionContract.address,
|
||||
makerAssetData: encodeDutchAuctionAssetData(
|
||||
await devUtils.encodeERC20AssetData(defaultMakerAssetAddress).callAsync(),
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
),
|
||||
takerAssetData: await devUtils.encodeERC20AssetData(defaultTakerAssetAddress).callAsync(),
|
||||
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
|
||||
takerAssetAmount: auctionEndAmount,
|
||||
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
exchangeAddress: exchangeInstance.address,
|
||||
chainId,
|
||||
};
|
||||
// Default buy order is for the auction begin price
|
||||
const buyerDefaultOrderParams = {
|
||||
...sellerDefaultOrderParams,
|
||||
makerAddress: takerAddress,
|
||||
makerAssetData: sellerDefaultOrderParams.takerAssetData,
|
||||
takerAssetData: sellerDefaultOrderParams.makerAssetData,
|
||||
makerAssetAmount: auctionBeginAmount,
|
||||
takerAssetAmount: sellerDefaultOrderParams.makerAssetAmount,
|
||||
};
|
||||
const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
|
||||
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
|
||||
sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams);
|
||||
buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams);
|
||||
defaultERC20MakerAssetData = await devUtils.encodeERC20AssetData(defaultMakerAssetAddress).callAsync();
|
||||
});
|
||||
after(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
erc20Balances = await erc20Wrapper.getBalancesAsync();
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync();
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
describe('matchOrders', () => {
|
||||
it('should be worth the begin price at the begining of the auction', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2);
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
);
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({ makerAssetData });
|
||||
const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds);
|
||||
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
});
|
||||
it('should be be worth the end price at the end of the auction', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
);
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
makerAssetData,
|
||||
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||
});
|
||||
const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.gte(auctionEndTimeSeconds);
|
||||
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount);
|
||||
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
|
||||
});
|
||||
it('should match orders at current amount and send excess to buyer', async () => {
|
||||
const beforeAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
|
||||
});
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal(
|
||||
constants.ZERO_AMOUNT,
|
||||
);
|
||||
// HACK gte used here due to a bug in ganache where the timestamp can change
|
||||
// between multiple calls to the same block. Which can move the amount in our case
|
||||
// ref: https://github.com/trufflesuite/ganache-core/issues/111
|
||||
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||
);
|
||||
expect(newBalances[takerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[takerAddress][wethContract.address].minus(beforeAuctionDetails.currentAmount),
|
||||
);
|
||||
});
|
||||
it('maker fees on sellOrder are paid to the fee receipient', async () => {
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
makerFee: new BigNumber(1),
|
||||
});
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||
);
|
||||
expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
|
||||
erc20Balances[feeRecipientAddress][zrxToken.address].plus(sellOrder.makerFee),
|
||||
);
|
||||
});
|
||||
it('maker fees on buyOrder are paid to the fee receipient', async () => {
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||
makerFee: new BigNumber(1),
|
||||
});
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||
);
|
||||
expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
|
||||
erc20Balances[feeRecipientAddress][zrxToken.address].plus(buyOrder.makerFee),
|
||||
);
|
||||
});
|
||||
it('should revert when auction expires', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
|
||||
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
);
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||
makerAssetData,
|
||||
});
|
||||
const tx = dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(RevertReason.AuctionExpired);
|
||||
});
|
||||
it('cannot be filled for less than the current price', async () => {
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: sellOrder.takerAssetAmount,
|
||||
});
|
||||
const tx = dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(RevertReason.AuctionInvalidAmount);
|
||||
});
|
||||
it('auction begin amount must be higher than final amount ', async () => {
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
takerAssetAmount: auctionBeginAmount.plus(1),
|
||||
});
|
||||
const tx = dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(RevertReason.AuctionInvalidAmount);
|
||||
});
|
||||
it('begin time is less than end time', async () => {
|
||||
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
defaultERC20MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
);
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
expirationTimeSeconds: auctionEndTimeSeconds,
|
||||
makerAssetData,
|
||||
});
|
||||
const tx = dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(RevertReason.AuctionInvalidBeginTime);
|
||||
});
|
||||
it('asset data contains auction parameters', async () => {
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
makerAssetData: await devUtils.encodeERC20AssetData(defaultMakerAssetAddress).callAsync(),
|
||||
});
|
||||
const tx = dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
return expect(tx).to.revertWith(RevertReason.InvalidAssetData);
|
||||
});
|
||||
|
||||
describe('ERC721', () => {
|
||||
it('should match orders when ERC721', async () => {
|
||||
const makerAssetId = erc721MakerAssetIds[0];
|
||||
const erc721MakerAssetData = await devUtils
|
||||
.encodeERC721AssetData(erc721Token.address, makerAssetId)
|
||||
.callAsync();
|
||||
const makerAssetData = encodeDutchAuctionAssetData(
|
||||
erc721MakerAssetData,
|
||||
auctionBeginTimeSeconds,
|
||||
auctionBeginAmount,
|
||||
);
|
||||
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
|
||||
makerAssetAmount: new BigNumber(1),
|
||||
makerAssetData,
|
||||
});
|
||||
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
|
||||
takerAssetAmount: new BigNumber(1),
|
||||
takerAssetData: sellOrder.makerAssetData,
|
||||
});
|
||||
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
|
||||
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
|
||||
const newBalances = await erc20Wrapper.getBalancesAsync();
|
||||
// HACK gte used here due to a bug in ganache where the timestamp can change
|
||||
// between multiple calls to the same block. Which can move the amount in our case
|
||||
// ref: https://github.com/trufflesuite/ganache-core/issues/111
|
||||
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
|
||||
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
|
||||
);
|
||||
const newOwner = await erc721Token.ownerOf(makerAssetId).callAsync();
|
||||
expect(newOwner).to.be.bignumber.equal(takerAddress);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,19 +0,0 @@
|
||||
import { env, EnvVars } from '@0x/dev-utils';
|
||||
|
||||
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
|
||||
import { providerUtils } from '@0x/utils';
|
||||
|
||||
before('start web3 provider', () => {
|
||||
providerUtils.startProviderEngine(provider);
|
||||
});
|
||||
after('generate coverage report', async () => {
|
||||
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
|
||||
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
|
||||
await coverageSubprovider.writeCoverageAsync();
|
||||
}
|
||||
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
|
||||
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
|
||||
await profilerSubprovider.writeProfilerOutputAsync();
|
||||
}
|
||||
provider.stop();
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user