Compare commits

..

36 Commits

Author SHA1 Message Date
Jacob Evans
5d603b2f80 Publish
- @0x/contracts-asset-proxy@3.1.3
 - @0x/contracts-broker@1.0.1
 - @0x/contracts-coordinator@3.0.6
 - @0x/contracts-dev-utils@1.0.6
 - @0x/contracts-erc1155@2.0.6
 - @0x/contracts-erc20-bridge-sampler@1.2.1
 - @0x/contracts-erc20@3.0.6
 - @0x/contracts-erc721@3.0.6
 - @0x/contracts-exchange-forwarder@4.1.0
 - @0x/contracts-exchange-libs@4.2.0
 - @0x/contracts-exchange@3.1.2
 - @0x/contracts-extensions@6.0.0
 - @0x/contracts-integrations@2.2.3
 - @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.js@9.0.7
 - @0x/abi-gen@5.1.2
 - @0x/assert@3.0.5
 - @0x/asset-swapper@4.1.1
 - @0x/base-contract@6.1.2
 - @0x/connect@6.0.5
 - @0x/contract-artifacts@3.4.1
 - @0x/contract-wrappers-test@12.2.7
 - @0x/contract-wrappers@13.4.2
 - @0x/contracts-gen@2.0.6
 - @0x/dev-utils@3.1.3
 - @0x/instant@1.0.44
 - @0x/json-schemas@5.0.5
 - @0x/migrations@6.0.2
 - @0x/monorepo-scripts@1.0.49
 - @0x/order-utils@10.1.3
 - @0x/orderbook@2.1.2
 - @0x/sol-compiler@4.0.6
 - @0x/sol-coverage@4.0.6
 - @0x/sol-doc@3.1.3
 - @0x/sol-profiler@4.0.6
 - @0x/sol-trace@3.0.6
 - @0x/sol-tracing-utils@7.0.6
 - @0x/sra-spec@3.0.5
 - @0x/subproviders@6.0.6
 - @0x/utils@5.3.0
 - @0x/web3-wrapper@7.0.5
2020-02-06 21:24:29 +10:00
Jacob Evans
0e1b08ff54 Updated CHANGELOGS & MD docs 2020-02-06 21:24:05 +10:00
David Sun
befc22d718 [FIX] asset-swapper liquidity breakdown (#2472)
* changed divided

* added changelog

* prettier

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-02-06 15:09:39 +10:00
Jacob Evans
4a62e80967 [asset-swapper] Bump sampler gas limit and allow for override (#2471)
* [asset-swapper] Bump sampler gas limit and allow for override

* Fix imports

* Set to 36e6
2020-02-06 12:31:28 +10:00
Jacob Evans
ee9ef9f2c1 [asset-swapper] prune before dummy order creation (#2470) 2020-02-06 07:08:31 +10:00
mzhu25
93dcb68437 Merge pull request #2455 from 0xProject/feature/broker/gods-unchained
`@0x/contracts-broker`: Property-based Gods Unchained orders
2020-02-04 10:53:54 -08:00
Michael Zhu
0691cc7909 rename _transferEthRefund -> _unwrapAndTransferEth 2020-02-04 10:13:07 -08:00
Michael Zhu
d82f34fe59 add weth-related integration tests 2020-02-04 10:13:07 -08:00
Michael Zhu
d2313b30af Address PR feedback and add support for affiliate fees 2020-02-04 10:13:07 -08:00
Michael Zhu
329719472a Move LibAssetDataTransfer and MixinWeth(Utils) to contracts-extensions 2020-02-04 10:13:02 -08:00
Michael Zhu
a2fcab47d4 skip coordinator client test 2020-02-04 10:08:25 -08:00
Michael Zhu
4ab5951c25 Add comments 2020-02-04 10:08:25 -08:00
Michael Zhu
403cabb201 more integrations tests 2020-02-04 10:08:25 -08:00
Michael Zhu
3da7c5d3e2 Move LibAssetDataTransfer from forwarder to exchange-libs package 2020-02-04 10:08:21 -08:00
Michael Zhu
c5e0de51aa Add Broker rich errors 2020-02-04 10:06:12 -08:00
Michael Zhu
c581f1bba4 Update Broker README 2020-02-04 10:06:12 -08:00
Michael Zhu
b8ac9c2edd lint 2020-02-04 10:06:10 -08:00
Michael Zhu
1027ee2481 Broker integrations tests 2020-02-04 10:05:17 -08:00
Michael Zhu
2f311f7821 GodsUnchainedValidator unit tests 2020-02-04 10:04:19 -08:00
Michael Zhu
a98c95b514 Broker contracts 2020-02-04 10:04:19 -08:00
Michael Zhu
5bbbae5b23 create contracts-broker package 2020-02-04 10:04:19 -08:00
Jacob Evans
f9c9b9f924 Prevent docs dir from being completely removed 2020-02-04 20:29:16 +10:00
Jacob Evans
5921208ea6 Publish
- @0x/contracts-asset-proxy@3.1.2
 - @0x/contracts-coordinator@3.0.5
 - @0x/contracts-dev-utils@1.0.5
 - @0x/contracts-erc1155@2.0.5
 - @0x/contracts-erc20-bridge-sampler@1.2.0
 - @0x/contracts-erc20@3.0.5
 - @0x/contracts-erc721@3.0.5
 - @0x/contracts-exchange-forwarder@4.0.5
 - @0x/contracts-exchange-libs@4.1.1
 - @0x/contracts-exchange@3.1.1
 - @0x/contracts-extensions@5.1.4
 - @0x/contracts-integrations@2.2.2
 - @0x/contracts-multisig@4.0.5
 - @0x/contracts-staking@2.0.5
 - @0x/contracts-test-utils@5.1.2
 - @0x/contracts-utils@4.2.0
 - 0x.js@9.0.6
 - @0x/abi-gen@5.1.1
 - @0x/asset-swapper@4.1.0
 - @0x/base-contract@6.1.1
 - @0x/contract-addresses@4.4.0
 - @0x/contract-wrappers-test@12.2.6
 - @0x/contract-wrappers@13.4.1
 - @0x/contracts-gen@2.0.5
 - @0x/dev-utils@3.1.2
 - @0x/instant@1.0.43
 - @0x/migrations@6.0.1
 - @0x/monorepo-scripts@1.0.48
 - @0x/order-utils@10.1.2
 - @0x/orderbook@2.1.1
 - @0x/sol-compiler@4.0.5
 - @0x/sol-coverage@4.0.5
 - @0x/sol-doc@3.1.2
 - @0x/sol-profiler@4.0.5
 - @0x/sol-trace@3.0.5
 - @0x/sol-tracing-utils@7.0.5
 - @0x/subproviders@6.0.5
2020-02-04 20:22:07 +10:00
Jacob Evans
f89c78abd1 Updated CHANGELOGS & MD docs 2020-02-04 20:21:45 +10:00
David Sun
74d3b9334c Add liquidity source breakdown to asset-swapper (#2465)
* add liquidity source breakdown to asset-swapper

* remove debug line

* use OptimizedMarketOrder metadata

* updated change-log

* prettier + lint

* bug fixes

* fixes

* Prettier

* Fix types

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-02-04 19:03:28 +10:00
Xianny
919fc66b9d Stop hardcoding contract addresses (#2461)
* stop hardcoding contract addresses

* update changelog

* export ContractAddresses for docs
2020-02-04 17:49:45 +10:00
Francesco Agosti
400fb5a5bb Merge pull request #2468 from 0xProject/feat/fix-test-publish
Bump maxBuffer?
2020-02-03 19:59:03 -08:00
fragosti
3bb4f9085c Add post-instal step 2020-02-03 18:13:31 -08:00
Jacob Evans
714c6cec3c Bump maxBuffer? 2020-02-03 17:50:32 -08:00
Lawrence Forman
cb69921202 ERC20BridgeSampler: Unlock full sampling on Kovan (#2459)
* `@0x/contracts-utils`: Update kovan addresses in `DeploymentConstants`

* `@0x/contracts-erc20-bridge-sampler`: Make source IDs static on all networks, not inherited from `DeploymentConstants`.

* `@0x/contract-addresses`: Update `ERC20BridgeSampler` addresses on mainnet and kovan.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-31 11:27:28 -05:00
Jacob Evans
277a0adac9 [base-contract] throw string revert error (#2453) 2020-01-24 07:48:26 +10:00
Jacob Evans
02d14f504f Remove docs from sol-doc gitignore 2020-01-23 12:10:42 +10:00
Jacob Evans
1ab7664a60 Publish
- @0x/contracts-integrations@2.2.1
 - 0x.js@9.0.5
 - @0x/asset-swapper@4.0.1
 - @0x/instant@1.0.42
2020-01-23 11:58:27 +10:00
Jacob Evans
1be46ffb7e Updated CHANGELOGS & MD docs 2020-01-23 11:58:10 +10:00
Lawrence Forman
6ca52aed0d @0x/asset-swapper: Fix understimated protocol fee in worst case quote. (#2452) 2020-01-22 18:22:56 -05:00
Jacob Evans
74e20970e2 Create docs folder for sol-doc 2020-01-22 18:56:10 +10:00
225 changed files with 4819 additions and 5870 deletions

5
.gitignore vendored
View File

@@ -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/

View File

@@ -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

View File

@@ -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",

View File

@@ -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

View File

@@ -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"
},

View 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

View 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"
}
]
}
]

View 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)

View File

@@ -0,0 +1 @@
[]

View 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).

View 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"
]
}
}
}
}

View 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);
}
}

View 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;
}

View File

@@ -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);
}

View File

@@ -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;
}

View 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
);
}
}

View File

@@ -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");
}
}

View 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]);
}
}

View 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"
}
}

View 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,
};

View 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);
},
};

View 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';

View 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';

View 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,
};

View 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');
});
});
});

View 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';

View 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 },
},
},
},
},
};

View 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"]
}

View File

@@ -0,0 +1,6 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -0,0 +1,7 @@
{
"extends": "../../typedoc-tsconfig",
"compilerOptions": {
"outDir": "lib"
},
"include": ["./src/**/*", "./test/**/*"]
}

View File

@@ -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",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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",

View File

@@ -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

View File

@@ -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": {

View File

@@ -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": [

View File

@@ -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)

View File

@@ -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");

View File

@@ -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"
},

View File

@@ -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);
});

View File

@@ -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",

View File

@@ -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

View File

@@ -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"

View File

@@ -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",

View File

@@ -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

View File

@@ -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"

View File

@@ -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",

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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
);
}

View File

@@ -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
);
}

View File

@@ -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);
}
}

View File

@@ -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
);
}
}

View File

@@ -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)
)

View File

@@ -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"
},

View File

@@ -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,
};

View File

@@ -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);

View File

@@ -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';

View File

@@ -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"]

View File

@@ -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": [

View File

@@ -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)

View File

@@ -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": {

View File

@@ -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": [

View File

@@ -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)

View File

@@ -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": {

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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
));
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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,
""
);
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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
{}

View File

@@ -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"
);
}
}

View File

@@ -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
);
}
}

View File

@@ -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
);
}
}

View File

@@ -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"
},

View File

@@ -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,
};

View File

@@ -1,5 +1,5 @@
export { artifacts } from './artifacts';
export { BalanceThresholdFilterContract, DutchAuctionContract, OrderMatcherContract } from './wrappers';
export { LibAssetDataTransferRevertErrors, MixinWethUtilsRevertErrors } from '@0x/utils';
export {
ContractArtifact,
ContractChains,

View File

@@ -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';

View 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

View File

@@ -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);
});
});
});
});

View File

@@ -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