Compare commits
154 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
5d603b2f80 | ||
|
0e1b08ff54 | ||
|
befc22d718 | ||
|
4a62e80967 | ||
|
ee9ef9f2c1 | ||
|
93dcb68437 | ||
|
0691cc7909 | ||
|
d82f34fe59 | ||
|
d2313b30af | ||
|
329719472a | ||
|
a2fcab47d4 | ||
|
4ab5951c25 | ||
|
403cabb201 | ||
|
3da7c5d3e2 | ||
|
c5e0de51aa | ||
|
c581f1bba4 | ||
|
b8ac9c2edd | ||
|
1027ee2481 | ||
|
2f311f7821 | ||
|
a98c95b514 | ||
|
5bbbae5b23 | ||
|
f9c9b9f924 | ||
|
5921208ea6 | ||
|
f89c78abd1 | ||
|
74d3b9334c | ||
|
919fc66b9d | ||
|
400fb5a5bb | ||
|
3bb4f9085c | ||
|
714c6cec3c | ||
|
cb69921202 | ||
|
277a0adac9 | ||
|
02d14f504f | ||
|
1ab7664a60 | ||
|
1be46ffb7e | ||
|
6ca52aed0d | ||
|
74e20970e2 | ||
|
93f2b6b4d8 | ||
|
00e616b57a | ||
|
e436673304 | ||
|
ce04d3ce41 | ||
|
4e46bf4697 | ||
|
9b95508f99 | ||
|
c8c24456c1 | ||
|
80a6e82e1b | ||
|
80cec20d38 | ||
|
26cb22020d | ||
|
09d05d09c9 | ||
|
160c91f908 | ||
|
58f41bcd42 | ||
|
0235429995 | ||
|
f79697e117 | ||
|
6f0019c71e | ||
|
1a04a18245 | ||
|
0cf3ff8209 | ||
|
7f56091fbd | ||
|
391f9b31f6 | ||
|
1d7c0f504a | ||
|
9cdc62f918 | ||
|
6027d0481e | ||
|
277fb92f9e | ||
|
79b6c3c1af | ||
|
ad17174119 | ||
|
6c2692eec0 | ||
|
08640e8575 | ||
|
4a2575136f | ||
|
e792afad17 | ||
|
5ecc4b027d | ||
|
bc540f0cf0 | ||
|
a24b14c465 | ||
|
c3f36c3123 | ||
|
1d34da7557 | ||
|
27d74a4327 | ||
|
8a20cc682c | ||
|
9b20359e7b | ||
|
8866d0ccef | ||
|
7fa91a9971 | ||
|
28d1f3eef0 | ||
|
f321cf6655 | ||
|
14ade737da | ||
|
41b1b1f141 | ||
|
25dfd47d32 | ||
|
6afa9c8b92 | ||
|
2fc449da4c | ||
|
5dd3b8cf9d | ||
|
e834fa0050 | ||
|
9a97401606 | ||
|
410a3fef18 | ||
|
969b9814d5 | ||
|
2275e27b87 | ||
|
62b06cd204 | ||
|
350934ca21 | ||
|
6332673434 | ||
|
f217840998 | ||
|
089ec35ceb | ||
|
fecd0b809e | ||
|
4707a46561 | ||
|
616533c5a8 | ||
|
c5b2991821 | ||
|
c36d0fdc7c | ||
|
544e09cf4b | ||
|
c110dc9e6a | ||
|
3bf37d6afd | ||
|
b80ae5796b | ||
|
2083632299 | ||
|
3ca2f8ac9e | ||
|
7172432084 | ||
|
0e6afd147f | ||
|
46275a4f43 | ||
|
1dca378e03 | ||
|
06669594b1 | ||
|
c09ac58ac0 | ||
|
e01d32ef1a | ||
|
5ea3bcf59e | ||
|
aa8b14b7ee | ||
|
e1722cf739 | ||
|
7a7f70e15d | ||
|
b3c3ec16e5 | ||
|
149f863951 | ||
|
684d09faac | ||
|
8a42691c80 | ||
|
d591b3dd98 | ||
|
a90fb4d8b6 | ||
|
ebd08d9c63 | ||
|
71731d223b | ||
|
726ea5e01e | ||
|
16c7d2964b | ||
|
5a6e494bda | ||
|
88c6d89fbb | ||
|
de12da18da | ||
|
8d10736934 | ||
|
2328e02d82 | ||
|
87cd5fca90 | ||
|
b70cb726c5 | ||
|
295811ed5a | ||
|
4bc55551c6 | ||
|
2b8c6dc8f9 | ||
|
8b27380feb | ||
|
8de3a90851 | ||
|
f8bb94d721 | ||
|
0c6d06e7bb | ||
|
b0aa5d3af2 | ||
|
27d09713fd | ||
|
ff18852879 | ||
|
e515c91e5e | ||
|
1d5800c4f7 | ||
|
de8f190945 | ||
|
f371e3c8d3 | ||
|
b15a6290a7 | ||
|
0f151db355 | ||
|
fa99b75d1f | ||
|
4a299c1f39 | ||
|
30a2015a68 | ||
|
c7c8a4891f | ||
|
fe9fc6b459 |
@@ -193,7 +193,7 @@ jobs:
|
|||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||||
- image: 0xorg/ganache-cli
|
- image: 0xorg/ganache-cli:6.0.0
|
||||||
- image: 0xorg/mesh:0xV3
|
- image: 0xorg/mesh:0xV3
|
||||||
environment:
|
environment:
|
||||||
ETHEREUM_RPC_URL: 'http://localhost:8545'
|
ETHEREUM_RPC_URL: 'http://localhost:8545'
|
||||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -79,6 +79,8 @@ TODO.md
|
|||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
# generated contract artifacts/
|
# generated contract artifacts/
|
||||||
|
contracts/broker/generated-artifacts/
|
||||||
|
contracts/broker/test/generated-artifacts/
|
||||||
contracts/erc20-bridge-sampler/generated-artifacts/
|
contracts/erc20-bridge-sampler/generated-artifacts/
|
||||||
contracts/erc20-bridge-sampler/test/generated-artifacts/
|
contracts/erc20-bridge-sampler/test/generated-artifacts/
|
||||||
contracts/integrations/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/
|
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
|
||||||
|
|
||||||
# generated truffle contract artifacts/
|
# generated truffle contract artifacts/
|
||||||
|
contracts/broker/build/
|
||||||
contracts/erc20-bridge-sampler/build/
|
contracts/erc20-bridge-sampler/build/
|
||||||
contracts/staking/build/
|
contracts/staking/build/
|
||||||
contracts/coordinator/build/
|
contracts/coordinator/build/
|
||||||
@@ -129,6 +132,8 @@ contracts/exchange-forwarder/build/
|
|||||||
contracts/dev-utils/build/
|
contracts/dev-utils/build/
|
||||||
|
|
||||||
# generated contract wrappers
|
# generated contract wrappers
|
||||||
|
contracts/broker/generated-wrappers/
|
||||||
|
contracts/broker/test/generated-wrappers/
|
||||||
packages/python-contract-wrappers/generated/
|
packages/python-contract-wrappers/generated/
|
||||||
contracts/erc20-bridge-sampler/generated-wrappers/
|
contracts/erc20-bridge-sampler/generated-wrappers/
|
||||||
contracts/erc20-bridge-sampler/test/generated-wrappers/
|
contracts/erc20-bridge-sampler/test/generated-wrappers/
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
lib
|
lib
|
||||||
.nyc_output
|
.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/generated-wrappers
|
||||||
/contracts/integrations/test/generated-wrappers
|
/contracts/integrations/test/generated-wrappers
|
||||||
/contracts/integrations/generated-artifacts
|
/contracts/integrations/generated-artifacts
|
||||||
|
@@ -1,4 +1,31 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v3.1.0 - _January 6, 2020_
|
## v3.1.0 - _January 6, 2020_
|
||||||
|
|
||||||
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
|
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -18,10 +18,22 @@
|
|||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract PotLike {
|
||||||
|
function chi() external returns (uint256);
|
||||||
|
function rho() external returns (uint256);
|
||||||
|
function drip() external returns (uint256);
|
||||||
|
function join(uint256) external;
|
||||||
|
function exit(uint256) external;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// The actual Chai contract can be found here: https://github.com/dapphub/chai
|
// The actual Chai contract can be found here: https://github.com/dapphub/chai
|
||||||
contract IChai {
|
contract IChai is
|
||||||
|
IERC20Token
|
||||||
|
{
|
||||||
/// @dev Withdraws Dai owned by `src`
|
/// @dev Withdraws Dai owned by `src`
|
||||||
/// @param src Address that owns Dai.
|
/// @param src Address that owns Dai.
|
||||||
/// @param wad Amount of Dai to withdraw.
|
/// @param wad Amount of Dai to withdraw.
|
||||||
@@ -30,4 +42,25 @@ contract IChai {
|
|||||||
uint256 wad
|
uint256 wad
|
||||||
)
|
)
|
||||||
external;
|
external;
|
||||||
|
|
||||||
|
/// @dev Queries Dai balance of Chai holder.
|
||||||
|
/// @param usr Address of Chai holder.
|
||||||
|
/// @return Dai balance.
|
||||||
|
function dai(address usr)
|
||||||
|
external
|
||||||
|
returns (uint256);
|
||||||
|
|
||||||
|
/// @dev Queries the Pot contract used by the Chai contract.
|
||||||
|
function pot()
|
||||||
|
external
|
||||||
|
returns (PotLike);
|
||||||
|
|
||||||
|
/// @dev Deposits Dai in exchange for Chai
|
||||||
|
/// @param dst Address to receive Chai.
|
||||||
|
/// @param wad Amount of Dai to deposit.
|
||||||
|
function join(
|
||||||
|
address dst,
|
||||||
|
uint256 wad
|
||||||
|
)
|
||||||
|
external;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-asset-proxy",
|
"name": "@0x/contracts-asset-proxy",
|
||||||
"version": "3.1.0",
|
"version": "3.1.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -51,12 +51,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
@@ -79,16 +79,16 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3",
|
"@0x/base-contract": "^6.1.2",
|
||||||
"@0x/contracts-dev-utils": "^1.0.3",
|
"@0x/contracts-dev-utils": "^1.0.6",
|
||||||
"@0x/contracts-erc1155": "^2.0.3",
|
"@0x/contracts-erc1155": "^2.0.6",
|
||||||
"@0x/contracts-erc20": "^3.0.3",
|
"@0x/contracts-erc20": "^3.0.6",
|
||||||
"@0x/contracts-erc721": "^3.0.3",
|
"@0x/contracts-erc721": "^3.0.6",
|
||||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||||
"@0x/order-utils": "^10.1.0",
|
"@0x/order-utils": "^10.1.3",
|
||||||
"@0x/typescript-typings": "^5.0.1",
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"ethereum-types": "^3.0.0",
|
"ethereum-types": "^3.0.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@@ -60,7 +60,7 @@ export class ERC1155ProxyWrapper {
|
|||||||
txDefaults,
|
txDefaults,
|
||||||
artifacts,
|
artifacts,
|
||||||
);
|
);
|
||||||
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress);
|
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
|
||||||
this._dummyTokenWrappers.push(erc1155Wrapper);
|
this._dummyTokenWrappers.push(erc1155Wrapper);
|
||||||
}
|
}
|
||||||
return this._dummyTokenWrappers;
|
return this._dummyTokenWrappers;
|
||||||
|
@@ -13,6 +13,9 @@ export {
|
|||||||
StaticCallProxyContract,
|
StaticCallProxyContract,
|
||||||
TestStaticCallTargetContract,
|
TestStaticCallTargetContract,
|
||||||
UniswapBridgeContract,
|
UniswapBridgeContract,
|
||||||
|
KyberBridgeContract,
|
||||||
|
ChaiBridgeContract,
|
||||||
|
IChaiContract,
|
||||||
} from './wrappers';
|
} from './wrappers';
|
||||||
|
|
||||||
export { ERC20Wrapper } from './erc20_wrapper';
|
export { ERC20Wrapper } from './erc20_wrapper';
|
||||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
|||||||
solc: {
|
solc: {
|
||||||
version: '0.5.9',
|
version: '0.5.9',
|
||||||
settings: {
|
settings: {
|
||||||
evmVersion: 'constantinople',
|
evmVersion: 'istanbul',
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 1000000,
|
runs: 1000000,
|
||||||
|
10
contracts/broker/.npmignore
Normal file
10
contracts/broker/.npmignore
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Blacklist all files
|
||||||
|
.*
|
||||||
|
*
|
||||||
|
# Whitelist lib
|
||||||
|
!lib/**/*
|
||||||
|
# Whitelist Solidity contracts
|
||||||
|
!contracts/src/**/*
|
||||||
|
# Blacklist tests in lib
|
||||||
|
/lib/test/*
|
||||||
|
# Package specific ignore
|
20
contracts/broker/CHANGELOG.json
Normal file
20
contracts/broker/CHANGELOG.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": 1580988106,
|
||||||
|
"version": "1.0.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Created package",
|
||||||
|
"pr": "2455"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
14
contracts/broker/CHANGELOG.md
Normal file
14
contracts/broker/CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!--
|
||||||
|
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||||
|
Edit the package's CHANGELOG.json file only.
|
||||||
|
-->
|
||||||
|
|
||||||
|
CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.1 - _February 6, 2020_
|
||||||
|
|
||||||
|
* Dependencies updated
|
||||||
|
|
||||||
|
## v1.0.0 - _Invalid date_
|
||||||
|
|
||||||
|
* Created package (#2455)
|
1
contracts/broker/DEPLOYS.json
Normal file
1
contracts/broker/DEPLOYS.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[]
|
73
contracts/broker/README.md
Normal file
73
contracts/broker/README.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
## Broker
|
||||||
|
|
||||||
|
This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
**Install**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @0x/contracts-broker --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bug bounty
|
||||||
|
|
||||||
|
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||||
|
|
||||||
|
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||||
|
|
||||||
|
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||||
|
|
||||||
|
### Install Dependencies
|
||||||
|
|
||||||
|
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn config set workspaces-experimental true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-broker yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PKG=@0x/contracts-broker yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clean
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Testing options
|
||||||
|
|
||||||
|
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
|
26
contracts/broker/compiler.json
Normal file
26
contracts/broker/compiler.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"artifactsDir": "./test/generated-artifacts",
|
||||||
|
"contractsDir": "./contracts",
|
||||||
|
"useDockerisedSolc": false,
|
||||||
|
"isOfflineMode": false,
|
||||||
|
"compilerSettings": {
|
||||||
|
"evmVersion": "istanbul",
|
||||||
|
"optimizer": {
|
||||||
|
"enabled": true,
|
||||||
|
"runs": 1000000,
|
||||||
|
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||||
|
},
|
||||||
|
"outputSelection": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"abi",
|
||||||
|
"devdoc",
|
||||||
|
"evm.bytecode.object",
|
||||||
|
"evm.bytecode.sourceMap",
|
||||||
|
"evm.deployedBytecode.object",
|
||||||
|
"evm.deployedBytecode.sourceMap"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
314
contracts/broker/contracts/src/Broker.sol
Normal file
314
contracts/broker/contracts/src/Broker.sol
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||||
|
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||||
|
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||||
|
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||||
|
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
|
import "./interfaces/IBroker.sol";
|
||||||
|
import "./interfaces/IPropertyValidator.sol";
|
||||||
|
import "./libs/LibBrokerRichErrors.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable space-after-comma, var-name-mixedcase
|
||||||
|
contract Broker is
|
||||||
|
IBroker,
|
||||||
|
MixinWethUtils
|
||||||
|
{
|
||||||
|
// Contract addresses
|
||||||
|
|
||||||
|
// Address of the 0x Exchange contract
|
||||||
|
address internal EXCHANGE;
|
||||||
|
// Address of the 0x ERC1155 Asset Proxy contract
|
||||||
|
address internal ERC1155_PROXY;
|
||||||
|
|
||||||
|
// The following storage variables are used to cache data for the duration of the transcation.
|
||||||
|
// They should always cleared at the end of the transaction.
|
||||||
|
|
||||||
|
// Token IDs specified by the taker to be used to fill property-based orders.
|
||||||
|
uint256[] internal _cachedTokenIds;
|
||||||
|
// An index to the above array keeping track of which assets have been transferred.
|
||||||
|
uint256 internal _cacheIndex;
|
||||||
|
// The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to
|
||||||
|
// and from this address as the effectual taker of the orders.
|
||||||
|
address internal _sender;
|
||||||
|
|
||||||
|
using LibSafeMath for uint256;
|
||||||
|
using LibBytes for bytes;
|
||||||
|
using LibAssetDataTransfer for bytes;
|
||||||
|
|
||||||
|
/// @param exchange Address of the 0x Exchange contract.
|
||||||
|
/// @param exchange Address of the Wrapped Ether contract.
|
||||||
|
/// @param exchange Address of the 0x ERC1155 Asset Proxy contract.
|
||||||
|
constructor (
|
||||||
|
address exchange,
|
||||||
|
address weth
|
||||||
|
)
|
||||||
|
public
|
||||||
|
MixinWethUtils(
|
||||||
|
exchange,
|
||||||
|
weth
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EXCHANGE = exchange;
|
||||||
|
ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
|
||||||
|
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
|
||||||
|
/// @param to This should be the maker of the order.
|
||||||
|
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
|
||||||
|
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
|
||||||
|
function safeBatchTransferFrom(
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256[] calldata /* ids */,
|
||||||
|
uint256[] calldata amounts,
|
||||||
|
bytes calldata data
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
// Only the ERC1155 asset proxy contract should be calling this function.
|
||||||
|
if (msg.sender != ERC1155_PROXY) {
|
||||||
|
LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError(
|
||||||
|
msg.sender
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// Only `takerAssetData` should be using Broker assets
|
||||||
|
if (from != address(this)) {
|
||||||
|
LibRichErrors.rrevert(
|
||||||
|
LibBrokerRichErrors.InvalidFromAddressError(from)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Only one asset amount should be specified.
|
||||||
|
if (amounts.length != 1) {
|
||||||
|
LibRichErrors.rrevert(
|
||||||
|
LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 cacheIndex = _cacheIndex;
|
||||||
|
uint256 remainingAmount = amounts[0];
|
||||||
|
|
||||||
|
// Verify that there are enough broker assets to transfer
|
||||||
|
if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) {
|
||||||
|
LibRichErrors.rrevert(
|
||||||
|
LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode validator and params from `data`
|
||||||
|
(address tokenAddress, address validator, bytes memory propertyData) = abi.decode(
|
||||||
|
data,
|
||||||
|
(address, address, bytes)
|
||||||
|
);
|
||||||
|
|
||||||
|
while (remainingAmount != 0) {
|
||||||
|
uint256 tokenId = _cachedTokenIds[cacheIndex];
|
||||||
|
cacheIndex++;
|
||||||
|
|
||||||
|
// Validate asset properties
|
||||||
|
IPropertyValidator(validator).checkBrokerAsset(
|
||||||
|
tokenId,
|
||||||
|
propertyData
|
||||||
|
);
|
||||||
|
|
||||||
|
// Perform the transfer
|
||||||
|
IERC721Token(tokenAddress).transferFrom(
|
||||||
|
_sender,
|
||||||
|
to,
|
||||||
|
tokenId
|
||||||
|
);
|
||||||
|
|
||||||
|
remainingAmount--;
|
||||||
|
}
|
||||||
|
// Update cache index in storage
|
||||||
|
_cacheIndex = cacheIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Fills a single property-based order by the given amount using the given assets.
|
||||||
|
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||||
|
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||||
|
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||||
|
/// @param order The property-based order to fill. The format of a property-based order is the
|
||||||
|
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||||
|
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||||
|
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||||
|
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||||
|
/// WETH (or zero).
|
||||||
|
/// @param takerAssetFillAmount The amount to fill the order by.
|
||||||
|
/// @param signature The maker's signature of the given order.
|
||||||
|
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return fillResults Amounts filled and fees paid by the maker and taker.
|
||||||
|
function brokerTrade(
|
||||||
|
uint256[] memory brokeredTokenIds,
|
||||||
|
LibOrder.Order memory order,
|
||||||
|
uint256 takerAssetFillAmount,
|
||||||
|
bytes memory signature,
|
||||||
|
bytes4 fillFunctionSelector,
|
||||||
|
uint256[] memory ethFeeAmounts,
|
||||||
|
address payable[] memory feeRecipients
|
||||||
|
)
|
||||||
|
public
|
||||||
|
payable
|
||||||
|
returns (LibFillResults.FillResults memory fillResults)
|
||||||
|
{
|
||||||
|
// Cache the taker-supplied asset data
|
||||||
|
_cachedTokenIds = brokeredTokenIds;
|
||||||
|
// Cache the sender's address
|
||||||
|
_sender = msg.sender;
|
||||||
|
|
||||||
|
// Sanity-check the provided function selector
|
||||||
|
if (
|
||||||
|
fillFunctionSelector != IExchange(address(0)).fillOrder.selector &&
|
||||||
|
fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector
|
||||||
|
) {
|
||||||
|
LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||||
|
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
|
||||||
|
|
||||||
|
// Perform the fill
|
||||||
|
bytes memory fillCalldata = abi.encodeWithSelector(
|
||||||
|
fillFunctionSelector,
|
||||||
|
order,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
// solhint-disable-next-line avoid-call-value
|
||||||
|
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata);
|
||||||
|
if (didSucceed) {
|
||||||
|
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||||
|
} else {
|
||||||
|
// Re-throw error
|
||||||
|
LibRichErrors.rrevert(returnData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer maker asset to taker
|
||||||
|
if (!order.makerAssetData.equals(WETH_ASSET_DATA)) {
|
||||||
|
order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refund remaining ETH to msg.sender.
|
||||||
|
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
|
||||||
|
|
||||||
|
_clearStorage();
|
||||||
|
|
||||||
|
return fillResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
|
||||||
|
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||||
|
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||||
|
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||||
|
/// @param orders The property-based orders to fill. The format of a property-based order is the
|
||||||
|
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||||
|
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||||
|
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||||
|
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||||
|
/// WETH (or zero).
|
||||||
|
/// @param takerAssetFillAmounts The amounts to fill the orders by.
|
||||||
|
/// @param signatures The makers' signatures for the given orders.
|
||||||
|
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
|
||||||
|
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return fillResults Amounts filled and fees paid by the makers and taker.
|
||||||
|
function batchBrokerTrade(
|
||||||
|
uint256[] memory brokeredTokenIds,
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256[] memory takerAssetFillAmounts,
|
||||||
|
bytes[] memory signatures,
|
||||||
|
bytes4 batchFillFunctionSelector,
|
||||||
|
uint256[] memory ethFeeAmounts,
|
||||||
|
address payable[] memory feeRecipients
|
||||||
|
)
|
||||||
|
public
|
||||||
|
payable
|
||||||
|
returns (LibFillResults.FillResults[] memory fillResults)
|
||||||
|
{
|
||||||
|
// Cache the taker-supplied asset data
|
||||||
|
_cachedTokenIds = brokeredTokenIds;
|
||||||
|
// Cache the sender's address
|
||||||
|
_sender = msg.sender;
|
||||||
|
|
||||||
|
// Sanity-check the provided function selector
|
||||||
|
if (
|
||||||
|
batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector &&
|
||||||
|
batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector &&
|
||||||
|
batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector
|
||||||
|
) {
|
||||||
|
LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||||
|
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
|
||||||
|
|
||||||
|
// Perform the batch fill
|
||||||
|
bytes memory batchFillCalldata = abi.encodeWithSelector(
|
||||||
|
batchFillFunctionSelector,
|
||||||
|
orders,
|
||||||
|
takerAssetFillAmounts,
|
||||||
|
signatures
|
||||||
|
);
|
||||||
|
// solhint-disable-next-line avoid-call-value
|
||||||
|
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata);
|
||||||
|
if (didSucceed) {
|
||||||
|
// solhint-disable-next-line indent
|
||||||
|
fillResults = abi.decode(returnData, (LibFillResults.FillResults[]));
|
||||||
|
} else {
|
||||||
|
// Re-throw error
|
||||||
|
LibRichErrors.rrevert(returnData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer maker assets to taker
|
||||||
|
for (uint256 i = 0; i < orders.length; i++) {
|
||||||
|
if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) {
|
||||||
|
orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refund remaining ETH to msg.sender.
|
||||||
|
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
|
||||||
|
|
||||||
|
_clearStorage();
|
||||||
|
|
||||||
|
return fillResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _clearStorage()
|
||||||
|
private
|
||||||
|
{
|
||||||
|
delete _cachedTokenIds;
|
||||||
|
_cacheIndex = 0;
|
||||||
|
_sender = address(0);
|
||||||
|
}
|
||||||
|
}
|
101
contracts/broker/contracts/src/interfaces/IBroker.sol
Normal file
101
contracts/broker/contracts/src/interfaces/IBroker.sol
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
|
|
||||||
|
|
||||||
|
// solhint-disable space-after-comma
|
||||||
|
interface IBroker {
|
||||||
|
|
||||||
|
/// @dev Fills a single property-based order by the given amount using the given assets.
|
||||||
|
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||||
|
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||||
|
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||||
|
/// @param order The property-based order to fill. The format of a property-based order is the
|
||||||
|
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||||
|
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||||
|
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||||
|
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||||
|
/// WETH (or zero).
|
||||||
|
/// @param takerAssetFillAmount The amount to fill the order by.
|
||||||
|
/// @param signature The maker's signature of the given order.
|
||||||
|
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return fillResults Amounts filled and fees paid by the maker and taker.
|
||||||
|
function brokerTrade(
|
||||||
|
uint256[] calldata brokeredTokenIds,
|
||||||
|
LibOrder.Order calldata order,
|
||||||
|
uint256 takerAssetFillAmount,
|
||||||
|
bytes calldata signature,
|
||||||
|
bytes4 fillFunctionSelector,
|
||||||
|
uint256[] calldata ethFeeAmounts,
|
||||||
|
address payable[] calldata feeRecipients
|
||||||
|
)
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
returns (LibFillResults.FillResults memory fillResults);
|
||||||
|
|
||||||
|
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
|
||||||
|
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
|
||||||
|
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
|
||||||
|
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
|
||||||
|
/// @param orders The property-based orders to fill. The format of a property-based order is the
|
||||||
|
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
|
||||||
|
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
|
||||||
|
/// underlying tokenAddress is this contract's address and the desired properties are
|
||||||
|
/// encoded in the extra data field. Also note that takerFees must be denominated in
|
||||||
|
/// WETH (or zero).
|
||||||
|
/// @param takerAssetFillAmounts The amounts to fill the orders by.
|
||||||
|
/// @param signatures The makers' signatures for the given orders.
|
||||||
|
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
|
||||||
|
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return fillResults Amounts filled and fees paid by the makers and taker.
|
||||||
|
function batchBrokerTrade(
|
||||||
|
uint256[] calldata brokeredTokenIds,
|
||||||
|
LibOrder.Order[] calldata orders,
|
||||||
|
uint256[] calldata takerAssetFillAmounts,
|
||||||
|
bytes[] calldata signatures,
|
||||||
|
bytes4 batchFillFunctionSelector,
|
||||||
|
uint256[] calldata ethFeeAmounts,
|
||||||
|
address payable[] calldata feeRecipients
|
||||||
|
)
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
returns (LibFillResults.FillResults[] memory fillResults);
|
||||||
|
|
||||||
|
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
|
||||||
|
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
|
||||||
|
/// @param to This should be the maker of the order.
|
||||||
|
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
|
||||||
|
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
|
||||||
|
function safeBatchTransferFrom(
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256[] calldata /* ids */,
|
||||||
|
uint256[] calldata amounts,
|
||||||
|
bytes calldata data
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
}
|
@@ -19,20 +19,15 @@
|
|||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
pragma experimental ABIEncoderV2;
|
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
|
/// @dev Returns the proto and quality for a particular card given its token id
|
||||||
contract OrderMatcher is
|
/// @param tokenId The id of the card to query.
|
||||||
MixinMatchOrders,
|
/// @return proto The proto of the given card.
|
||||||
MixinAssets
|
/// @return quality The quality of the given card
|
||||||
{
|
function getDetails(uint256 tokenId)
|
||||||
constructor (address _exchange)
|
external
|
||||||
public
|
view
|
||||||
LibConstants(_exchange)
|
returns (uint16 proto, uint8 quality);
|
||||||
Ownable()
|
|
||||||
{}
|
|
||||||
}
|
}
|
@@ -17,15 +17,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
contract IThresholdAsset {
|
interface IPropertyValidator {
|
||||||
|
|
||||||
/// @param _owner The address from which the balance will be retrieved
|
/// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`.
|
||||||
/// @return Balance of owner
|
/// Should revert if the asset does not satisfy the specified properties.
|
||||||
function balanceOf(address _owner)
|
/// @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
|
external
|
||||||
view
|
view;
|
||||||
returns (uint256);
|
|
||||||
|
|
||||||
}
|
}
|
109
contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
Normal file
109
contracts/broker/contracts/src/libs/LibBrokerRichErrors.sol
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
|
|
||||||
|
library LibBrokerRichErrors {
|
||||||
|
|
||||||
|
// bytes4(keccak256("InvalidFromAddressError(address)"))
|
||||||
|
bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR =
|
||||||
|
0x906bfb3c;
|
||||||
|
|
||||||
|
// bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)"))
|
||||||
|
bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR =
|
||||||
|
0xba9be200;
|
||||||
|
|
||||||
|
// bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)"))
|
||||||
|
bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR =
|
||||||
|
0x55272586;
|
||||||
|
|
||||||
|
// bytes4(keccak256("InvalidFunctionSelectorError(bytes4)"))
|
||||||
|
bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR =
|
||||||
|
0x540943f1;
|
||||||
|
|
||||||
|
// bytes4(keccak256("OnlyERC1155ProxyError(address)"))
|
||||||
|
bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR =
|
||||||
|
0xccc529af;
|
||||||
|
|
||||||
|
// solhint-disable func-name-mixedcase
|
||||||
|
function InvalidFromAddressError(
|
||||||
|
address from
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encodeWithSelector(
|
||||||
|
INVALID_FROM_ADDRESS_ERROR_SELECTOR,
|
||||||
|
from
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AmountsLengthMustEqualOneError(
|
||||||
|
uint256 amountsLength
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encodeWithSelector(
|
||||||
|
AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR,
|
||||||
|
amountsLength
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TooFewBrokerAssetsProvidedError(
|
||||||
|
uint256 numBrokeredAssets
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encodeWithSelector(
|
||||||
|
TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR,
|
||||||
|
numBrokeredAssets
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function InvalidFunctionSelectorError(
|
||||||
|
bytes4 selector
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encodeWithSelector(
|
||||||
|
INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR,
|
||||||
|
selector
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnlyERC1155ProxyError(
|
||||||
|
address sender
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bytes memory)
|
||||||
|
{
|
||||||
|
return abi.encodeWithSelector(
|
||||||
|
ONLY_ERC_1155_PROXY_ERROR_SELECTOR,
|
||||||
|
sender
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
|
import "../interfaces/IGodsUnchained.sol";
|
||||||
|
import "../interfaces/IPropertyValidator.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract GodsUnchainedValidator is
|
||||||
|
IPropertyValidator
|
||||||
|
{
|
||||||
|
IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase
|
||||||
|
|
||||||
|
using LibBytes for bytes;
|
||||||
|
|
||||||
|
constructor(address _godsUnchained)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
GODS_UNCHAINED = IGodsUnchained(_godsUnchained);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`.
|
||||||
|
/// Reverts if the card doesn't match the specified proto and quality.
|
||||||
|
/// @param tokenId The ERC721 tokenId of the card to check.
|
||||||
|
/// @param propertyData Encoded proto and quality that the card is expected to have.
|
||||||
|
function checkBrokerAsset(
|
||||||
|
uint256 tokenId,
|
||||||
|
bytes calldata propertyData
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
{
|
||||||
|
(uint16 expectedProto, uint8 expectedQuality) = abi.decode(
|
||||||
|
propertyData,
|
||||||
|
(uint16, uint8)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Validate card properties.
|
||||||
|
(uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId);
|
||||||
|
require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH");
|
||||||
|
require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH");
|
||||||
|
}
|
||||||
|
}
|
55
contracts/broker/contracts/test/TestGodsUnchained.sol
Normal file
55
contracts/broker/contracts/test/TestGodsUnchained.sol
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol";
|
||||||
|
import "../src/interfaces/IGodsUnchained.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract TestGodsUnchained is
|
||||||
|
IGodsUnchained,
|
||||||
|
DummyERC721Token
|
||||||
|
{
|
||||||
|
mapping (uint256 => uint16) internal _protoByTokenId;
|
||||||
|
mapping (uint256 => uint8) internal _qualityByTokenId;
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
string memory _name,
|
||||||
|
string memory _symbol
|
||||||
|
)
|
||||||
|
public
|
||||||
|
DummyERC721Token(_name, _symbol)
|
||||||
|
{} // solhint-disable-line no-empty-blocks
|
||||||
|
|
||||||
|
function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
_protoByTokenId[tokenId] = proto;
|
||||||
|
_qualityByTokenId[tokenId] = quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDetails(uint256 tokenId)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (uint16 proto, uint8 quality)
|
||||||
|
{
|
||||||
|
return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]);
|
||||||
|
}
|
||||||
|
}
|
96
contracts/broker/package.json
Normal file
96
contracts/broker/package.json
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"name": "@0x/contracts-broker",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.12"
|
||||||
|
},
|
||||||
|
"description": "Extension of 0x protocol for property-based orders",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "yarn build:contracts && yarn build:ts",
|
||||||
|
"build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||||
|
"build:ts": "tsc -b",
|
||||||
|
"build:ci": "yarn build",
|
||||||
|
"test": "yarn run_mocha",
|
||||||
|
"rebuild_and_test": "run-s build test",
|
||||||
|
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||||
|
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||||
|
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||||
|
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||||
|
"compile": "sol-compiler",
|
||||||
|
"watch": "sol-compiler -w",
|
||||||
|
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||||
|
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||||
|
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||||
|
"coverage:report:text": "istanbul report text",
|
||||||
|
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||||
|
"coverage:report:lcov": "istanbul report lcov",
|
||||||
|
"test:circleci": "yarn test",
|
||||||
|
"contracts:gen": "contracts-gen generate",
|
||||||
|
"contracts:copy": "contracts-gen copy",
|
||||||
|
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||||
|
"compile:truffle": "truffle compile",
|
||||||
|
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
|
||||||
|
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||||
|
"abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"@0x/abi-gen": "^5.1.2",
|
||||||
|
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||||
|
"@0x/contracts-erc20": "^3.0.6",
|
||||||
|
"@0x/contracts-erc721": "^3.0.6",
|
||||||
|
"@0x/contracts-exchange": "^3.1.2",
|
||||||
|
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||||
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
|
"@0x/tslint-config": "^4.0.0",
|
||||||
|
"@0x/types": "^3.1.1",
|
||||||
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
|
"@types/lodash": "4.14.104",
|
||||||
|
"@types/mocha": "^5.2.7",
|
||||||
|
"@types/node": "*",
|
||||||
|
"chai": "^4.0.1",
|
||||||
|
"chai-as-promised": "^7.1.0",
|
||||||
|
"chai-bignumber": "^3.0.0",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"make-promises-safe": "^1.1.0",
|
||||||
|
"mocha": "^6.2.0",
|
||||||
|
"npm-run-all": "^4.1.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"solhint": "^1.4.1",
|
||||||
|
"truffle": "^5.0.32",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"typedoc": "^0.15.0",
|
||||||
|
"typescript": "3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@0x/base-contract": "^6.1.2",
|
||||||
|
"@0x/order-utils": "^10.1.3",
|
||||||
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
|
"@0x/utils": "^5.3.0",
|
||||||
|
"ethereum-types": "^3.0.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
23
contracts/broker/src/artifacts.ts
Normal file
23
contracts/broker/src/artifacts.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as Broker from '../generated-artifacts/Broker.json';
|
||||||
|
import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json';
|
||||||
|
import * as IBroker from '../generated-artifacts/IBroker.json';
|
||||||
|
import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json';
|
||||||
|
import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json';
|
||||||
|
import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json';
|
||||||
|
import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json';
|
||||||
|
export const artifacts = {
|
||||||
|
Broker: Broker as ContractArtifact,
|
||||||
|
IBroker: IBroker as ContractArtifact,
|
||||||
|
IGodsUnchained: IGodsUnchained as ContractArtifact,
|
||||||
|
IPropertyValidator: IPropertyValidator as ContractArtifact,
|
||||||
|
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
|
||||||
|
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
|
||||||
|
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
|
||||||
|
};
|
42
contracts/broker/src/gods_unchained_utils.ts
Normal file
42
contracts/broker/src/gods_unchained_utils.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { assetDataUtils } from '@0x/order-utils';
|
||||||
|
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
export const godsUnchainedUtils = {
|
||||||
|
/**
|
||||||
|
* Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator.
|
||||||
|
*/
|
||||||
|
encodePropertyData(proto: BigNumber, quality: BigNumber): string {
|
||||||
|
return AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]).encode({
|
||||||
|
proto,
|
||||||
|
quality,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData
|
||||||
|
* of a property-based GodsUnchained order. Must also provide the addresses of the Broker,
|
||||||
|
* GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies
|
||||||
|
* how many cards are expected for each "unit" of the takerAssetAmount. For example, If the
|
||||||
|
* takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards
|
||||||
|
* with the given proto and quality to fill the order. If an odd number is provided, the fill fails.
|
||||||
|
*/
|
||||||
|
encodeBrokerAssetData(
|
||||||
|
brokerAddress: string,
|
||||||
|
godsUnchainedAddress: string,
|
||||||
|
validatorAddress: string,
|
||||||
|
proto: BigNumber,
|
||||||
|
quality: BigNumber,
|
||||||
|
bundleSize: number = 1,
|
||||||
|
): string {
|
||||||
|
const dataEncoder = AbiEncoder.create([
|
||||||
|
{ name: 'godsUnchainedAddress', type: 'address' },
|
||||||
|
{ name: 'validatorAddress', type: 'address' },
|
||||||
|
{ name: 'propertyData', type: 'bytes' },
|
||||||
|
]);
|
||||||
|
const propertyData = AbiEncoder.create([
|
||||||
|
{ name: 'proto', type: 'uint16' },
|
||||||
|
{ name: 'quality', type: 'uint8' },
|
||||||
|
]).encode({ proto, quality });
|
||||||
|
const data = dataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData });
|
||||||
|
return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], data);
|
||||||
|
},
|
||||||
|
};
|
32
contracts/broker/src/index.ts
Normal file
32
contracts/broker/src/index.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
export { artifacts } from './artifacts';
|
||||||
|
export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
|
||||||
|
export { godsUnchainedUtils } from './gods_unchained_utils';
|
||||||
|
export { BrokerRevertErrors } from '@0x/utils';
|
||||||
|
export {
|
||||||
|
ContractArtifact,
|
||||||
|
ContractChains,
|
||||||
|
CompilerOpts,
|
||||||
|
StandardContractOutput,
|
||||||
|
CompilerSettings,
|
||||||
|
ContractChainData,
|
||||||
|
ContractAbi,
|
||||||
|
DevdocOutput,
|
||||||
|
EvmOutput,
|
||||||
|
CompilerSettingsMetadata,
|
||||||
|
OptimizerSettings,
|
||||||
|
OutputField,
|
||||||
|
ParamDescription,
|
||||||
|
EvmBytecodeOutput,
|
||||||
|
AbiDefinition,
|
||||||
|
FunctionAbi,
|
||||||
|
EventAbi,
|
||||||
|
RevertErrorAbi,
|
||||||
|
EventParameter,
|
||||||
|
DataItem,
|
||||||
|
MethodAbi,
|
||||||
|
ConstructorAbi,
|
||||||
|
FallbackAbi,
|
||||||
|
ConstructorStateMutability,
|
||||||
|
TupleDataItem,
|
||||||
|
StateMutability,
|
||||||
|
} from 'ethereum-types';
|
12
contracts/broker/src/wrappers.ts
Normal file
12
contracts/broker/src/wrappers.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
export * from '../generated-wrappers/broker';
|
||||||
|
export * from '../generated-wrappers/gods_unchained_validator';
|
||||||
|
export * from '../generated-wrappers/i_broker';
|
||||||
|
export * from '../generated-wrappers/i_gods_unchained';
|
||||||
|
export * from '../generated-wrappers/i_property_validator';
|
||||||
|
export * from '../generated-wrappers/lib_broker_rich_errors';
|
||||||
|
export * from '../generated-wrappers/test_gods_unchained';
|
23
contracts/broker/test/artifacts.ts
Normal file
23
contracts/broker/test/artifacts.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
import { ContractArtifact } from 'ethereum-types';
|
||||||
|
|
||||||
|
import * as Broker from '../test/generated-artifacts/Broker.json';
|
||||||
|
import * as GodsUnchainedValidator from '../test/generated-artifacts/GodsUnchainedValidator.json';
|
||||||
|
import * as IBroker from '../test/generated-artifacts/IBroker.json';
|
||||||
|
import * as IGodsUnchained from '../test/generated-artifacts/IGodsUnchained.json';
|
||||||
|
import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json';
|
||||||
|
import * as LibBrokerRichErrors from '../test/generated-artifacts/LibBrokerRichErrors.json';
|
||||||
|
import * as TestGodsUnchained from '../test/generated-artifacts/TestGodsUnchained.json';
|
||||||
|
export const artifacts = {
|
||||||
|
Broker: Broker as ContractArtifact,
|
||||||
|
IBroker: IBroker as ContractArtifact,
|
||||||
|
IGodsUnchained: IGodsUnchained as ContractArtifact,
|
||||||
|
IPropertyValidator: IPropertyValidator as ContractArtifact,
|
||||||
|
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
|
||||||
|
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
|
||||||
|
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
|
||||||
|
};
|
56
contracts/broker/test/gods_unchained_validator_test.ts
Normal file
56
contracts/broker/test/gods_unchained_validator_test.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contracts-test-utils';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { godsUnchainedUtils } from '../src/gods_unchained_utils';
|
||||||
|
|
||||||
|
import { artifacts } from './artifacts';
|
||||||
|
import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
|
||||||
|
|
||||||
|
blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
|
||||||
|
let godsUnchained: TestGodsUnchainedContract;
|
||||||
|
let validator: GodsUnchainedValidatorContract;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.TestGodsUnchained,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
'Gods Unchained Cards',
|
||||||
|
'GU',
|
||||||
|
);
|
||||||
|
|
||||||
|
validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync(
|
||||||
|
artifacts.GodsUnchainedValidator,
|
||||||
|
env.provider,
|
||||||
|
env.txDefaults,
|
||||||
|
artifacts,
|
||||||
|
godsUnchained.address,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkBrokerAsset', () => {
|
||||||
|
const proto = new BigNumber(42);
|
||||||
|
const quality = new BigNumber(7);
|
||||||
|
const propertyData = godsUnchainedUtils.encodePropertyData(proto, quality);
|
||||||
|
|
||||||
|
it('succeeds if assetData proto and quality match propertyData', async () => {
|
||||||
|
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||||
|
await godsUnchained.setTokenProperties(tokenId, proto, quality).awaitTransactionSuccessAsync();
|
||||||
|
await validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||||
|
});
|
||||||
|
it("reverts if assetData proto doesn't match propertyData", async () => {
|
||||||
|
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||||
|
await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync();
|
||||||
|
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||||
|
expect(tx).to.revertWith('PROTO_MISMATCH');
|
||||||
|
});
|
||||||
|
it("reverts if assetData quality doesn't match proeprtyData", async () => {
|
||||||
|
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||||
|
await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync();
|
||||||
|
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||||
|
expect(tx).to.revertWith('QUALITY_MISMATCH');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
12
contracts/broker/test/wrappers.ts
Normal file
12
contracts/broker/test/wrappers.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
export * from '../test/generated-wrappers/broker';
|
||||||
|
export * from '../test/generated-wrappers/gods_unchained_validator';
|
||||||
|
export * from '../test/generated-wrappers/i_broker';
|
||||||
|
export * from '../test/generated-wrappers/i_gods_unchained';
|
||||||
|
export * from '../test/generated-wrappers/i_property_validator';
|
||||||
|
export * from '../test/generated-wrappers/lib_broker_rich_errors';
|
||||||
|
export * from '../test/generated-wrappers/test_gods_unchained';
|
96
contracts/broker/truffle-config.js
Normal file
96
contracts/broker/truffle-config.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Use this file to configure your truffle project. It's seeded with some
|
||||||
|
* common settings for different networks and features like migrations,
|
||||||
|
* compilation and testing. Uncomment the ones you need or modify
|
||||||
|
* them to suit your project as necessary.
|
||||||
|
*
|
||||||
|
* More information about configuration can be found at:
|
||||||
|
*
|
||||||
|
* truffleframework.com/docs/advanced/configuration
|
||||||
|
*
|
||||||
|
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||||
|
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||||
|
* are available for free at: infura.io/register.
|
||||||
|
*
|
||||||
|
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||||
|
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||||
|
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||||
|
// const infuraKey = "fj4jll3k.....";
|
||||||
|
//
|
||||||
|
// const fs = require('fs');
|
||||||
|
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Networks define how you connect to your ethereum client and let you set the
|
||||||
|
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||||
|
* will spin up a development blockchain for you on port 9545 when you
|
||||||
|
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||||
|
* network from the command line, e.g
|
||||||
|
*
|
||||||
|
* $ truffle test --network <network-name>
|
||||||
|
*/
|
||||||
|
|
||||||
|
networks: {
|
||||||
|
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||||
|
// if it's defined here and no other network is specified at the command line.
|
||||||
|
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||||
|
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||||
|
// options below to some value.
|
||||||
|
//
|
||||||
|
// development: {
|
||||||
|
// host: "127.0.0.1", // Localhost (default: none)
|
||||||
|
// port: 8545, // Standard Ethereum port (default: none)
|
||||||
|
// network_id: "*", // Any network (default: none)
|
||||||
|
// },
|
||||||
|
// Another network with more advanced options...
|
||||||
|
// advanced: {
|
||||||
|
// port: 8777, // Custom port
|
||||||
|
// network_id: 1342, // Custom network
|
||||||
|
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||||
|
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||||
|
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||||
|
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||||
|
// },
|
||||||
|
// Useful for deploying to a public network.
|
||||||
|
// NB: It's important to wrap the provider as a function.
|
||||||
|
// ropsten: {
|
||||||
|
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||||
|
// network_id: 3, // Ropsten's id
|
||||||
|
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||||
|
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||||
|
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||||
|
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||||
|
// },
|
||||||
|
// Useful for private networks
|
||||||
|
// private: {
|
||||||
|
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||||
|
// network_id: 2111, // This network is yours, in the cloud.
|
||||||
|
// production: true // Treats this network as if it was a public net. (default: false)
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
|
||||||
|
// Set default mocha options here, use special reporters etc.
|
||||||
|
mocha: {
|
||||||
|
// timeout: 100000
|
||||||
|
},
|
||||||
|
|
||||||
|
// Configure your compilers
|
||||||
|
compilers: {
|
||||||
|
solc: {
|
||||||
|
version: '0.5.9',
|
||||||
|
settings: {
|
||||||
|
evmVersion: 'istanbul',
|
||||||
|
optimizer: {
|
||||||
|
enabled: true,
|
||||||
|
runs: 1000000,
|
||||||
|
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
22
contracts/broker/tsconfig.json
Normal file
22
contracts/broker/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig",
|
||||||
|
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||||
|
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||||
|
"files": [
|
||||||
|
"generated-artifacts/Broker.json",
|
||||||
|
"generated-artifacts/GodsUnchainedValidator.json",
|
||||||
|
"generated-artifacts/IBroker.json",
|
||||||
|
"generated-artifacts/IGodsUnchained.json",
|
||||||
|
"generated-artifacts/IPropertyValidator.json",
|
||||||
|
"generated-artifacts/LibBrokerRichErrors.json",
|
||||||
|
"generated-artifacts/TestGodsUnchained.json",
|
||||||
|
"test/generated-artifacts/Broker.json",
|
||||||
|
"test/generated-artifacts/GodsUnchainedValidator.json",
|
||||||
|
"test/generated-artifacts/IBroker.json",
|
||||||
|
"test/generated-artifacts/IGodsUnchained.json",
|
||||||
|
"test/generated-artifacts/IPropertyValidator.json",
|
||||||
|
"test/generated-artifacts/LibBrokerRichErrors.json",
|
||||||
|
"test/generated-artifacts/TestGodsUnchained.json"
|
||||||
|
],
|
||||||
|
"exclude": ["./deploy/solc/solc_bin"]
|
||||||
|
}
|
6
contracts/broker/tslint.json
Normal file
6
contracts/broker/tslint.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": ["@0x/tslint-config"],
|
||||||
|
"rules": {
|
||||||
|
"custom-no-magic-numbers": false
|
||||||
|
}
|
||||||
|
}
|
7
contracts/broker/typedoc-tsconfig.json
Normal file
7
contracts/broker/typedoc-tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../typedoc-tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": ["./src/**/*", "./test/**/*"]
|
||||||
|
}
|
@@ -1,4 +1,31 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1578272714,
|
"timestamp": 1578272714,
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v3.0.3 - _January 6, 2020_
|
## v3.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"contractsDir": "./contracts",
|
"contractsDir": "./contracts",
|
||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-coordinator",
|
"name": "@0x/contracts-coordinator",
|
||||||
"version": "3.0.3",
|
"version": "3.0.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -52,19 +52,19 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||||
"@0x/contracts-dev-utils": "^1.0.3",
|
"@0x/contracts-dev-utils": "^1.0.6",
|
||||||
"@0x/contracts-erc20": "^3.0.3",
|
"@0x/contracts-erc20": "^3.0.6",
|
||||||
"@0x/contracts-exchange": "^3.0.3",
|
"@0x/contracts-exchange": "^3.1.2",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/order-utils": "^10.1.0",
|
"@0x/order-utils": "^10.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -84,14 +84,14 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/assert": "^3.0.3",
|
"@0x/assert": "^3.0.5",
|
||||||
"@0x/base-contract": "^6.0.3",
|
"@0x/base-contract": "^6.1.2",
|
||||||
"@0x/contract-addresses": "^4.2.0",
|
"@0x/contract-addresses": "^4.4.0",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/json-schemas": "^5.0.3",
|
"@0x/json-schemas": "^5.0.5",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
"@0x/typescript-typings": "^5.0.1",
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"ethereum-types": "^3.0.0",
|
"ethereum-types": "^3.0.0",
|
||||||
"http-status-codes": "^1.3.2"
|
"http-status-codes": "^1.3.2"
|
||||||
},
|
},
|
||||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
|||||||
solc: {
|
solc: {
|
||||||
version: '0.5.9',
|
version: '0.5.9',
|
||||||
settings: {
|
settings: {
|
||||||
evmVersion: 'constantinople',
|
evmVersion: 'istanbul',
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 1000000,
|
runs: 1000000,
|
||||||
|
@@ -1,4 +1,31 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v1.0.3 - _January 6, 2020_
|
## v1.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Fixed ERC721 duplicate token ID bug (#2400)
|
* Fixed ERC721 duplicate token ID bug (#2400)
|
||||||
|
@@ -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:
|
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PKG=@0x/contracts-extensions yarn build
|
PKG=@0x/contracts-dev-utils yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
Or continuously rebuild on change:
|
Or continuously rebuild on change:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PKG=@0x/contracts-extensions yarn watch
|
PKG=@0x/contracts-dev-utils yarn watch
|
||||||
```
|
```
|
||||||
|
|
||||||
### Clean
|
### Clean
|
||||||
|
@@ -4,10 +4,10 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 200,
|
"runs": 5000,
|
||||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||||
},
|
},
|
||||||
"outputSelection": {
|
"outputSelection": {
|
||||||
|
@@ -26,25 +26,33 @@ import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
|
|||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "./OrderValidationUtils.sol";
|
import "./OrderValidationUtils.sol";
|
||||||
import "./OrderTransferSimulationUtils.sol";
|
import "./OrderTransferSimulationUtils.sol";
|
||||||
import "./LibTransactionDecoder.sol";
|
|
||||||
import "./EthBalanceChecker.sol";
|
import "./EthBalanceChecker.sol";
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable no-empty-blocks
|
// solhint-disable no-empty-blocks
|
||||||
contract DevUtils is
|
contract DevUtils is
|
||||||
OrderValidationUtils,
|
OrderValidationUtils,
|
||||||
LibTransactionDecoder,
|
|
||||||
LibEIP712ExchangeDomain,
|
LibEIP712ExchangeDomain,
|
||||||
EthBalanceChecker
|
EthBalanceChecker
|
||||||
{
|
{
|
||||||
constructor (address _exchange)
|
constructor (
|
||||||
|
address _exchange,
|
||||||
|
address _chaiBridge
|
||||||
|
)
|
||||||
public
|
public
|
||||||
OrderValidationUtils(_exchange)
|
OrderValidationUtils(
|
||||||
|
_exchange,
|
||||||
|
_chaiBridge
|
||||||
|
)
|
||||||
OrderTransferSimulationUtils(_exchange)
|
OrderTransferSimulationUtils(_exchange)
|
||||||
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
|
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
|
||||||
{}
|
{}
|
||||||
|
|
||||||
function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange)
|
function getOrderHash(
|
||||||
|
LibOrder.Order memory order,
|
||||||
|
uint256 chainId,
|
||||||
|
address exchange
|
||||||
|
)
|
||||||
public
|
public
|
||||||
pure
|
pure
|
||||||
returns (bytes32 orderHash)
|
returns (bytes32 orderHash)
|
||||||
|
@@ -26,10 +26,14 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
|
|||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||||
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
|
||||||
|
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||||
|
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||||
|
|
||||||
|
|
||||||
contract LibAssetData {
|
contract LibAssetData is
|
||||||
|
DeploymentConstants
|
||||||
|
{
|
||||||
// 2^256 - 1
|
// 2^256 - 1
|
||||||
uint256 constant internal _MAX_UINT256 = uint256(-1);
|
uint256 constant internal _MAX_UINT256 = uint256(-1);
|
||||||
|
|
||||||
@@ -41,9 +45,13 @@ contract LibAssetData {
|
|||||||
address internal _ERC721_PROXY_ADDRESS;
|
address internal _ERC721_PROXY_ADDRESS;
|
||||||
address internal _ERC1155_PROXY_ADDRESS;
|
address internal _ERC1155_PROXY_ADDRESS;
|
||||||
address internal _STATIC_CALL_PROXY_ADDRESS;
|
address internal _STATIC_CALL_PROXY_ADDRESS;
|
||||||
|
address internal _CHAI_BRIDGE_ADDRESS;
|
||||||
// solhint-enable var-name-mixedcase
|
// solhint-enable var-name-mixedcase
|
||||||
|
|
||||||
constructor (address _exchange)
|
constructor (
|
||||||
|
address _exchange,
|
||||||
|
address _chaiBridge
|
||||||
|
)
|
||||||
public
|
public
|
||||||
{
|
{
|
||||||
_EXCHANGE = IExchange(_exchange);
|
_EXCHANGE = IExchange(_exchange);
|
||||||
@@ -51,6 +59,7 @@ contract LibAssetData {
|
|||||||
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
|
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
|
||||||
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
||||||
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
|
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
|
||||||
|
_CHAI_BRIDGE_ADDRESS = _chaiBridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Returns the owner's balance of the assets(s) specified in
|
/// @dev Returns the owner's balance of the assets(s) specified in
|
||||||
@@ -62,7 +71,6 @@ contract LibAssetData {
|
|||||||
/// @return Number of assets (or asset baskets) held by owner.
|
/// @return Number of assets (or asset baskets) held by owner.
|
||||||
function getBalance(address ownerAddress, bytes memory assetData)
|
function getBalance(address ownerAddress, bytes memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256 balance)
|
returns (uint256 balance)
|
||||||
{
|
{
|
||||||
// Get id of AssetProxy contract
|
// Get id of AssetProxy contract
|
||||||
@@ -71,16 +79,8 @@ contract LibAssetData {
|
|||||||
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
|
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
|
||||||
// Get ERC20 token address
|
// Get ERC20 token address
|
||||||
address tokenAddress = assetData.readAddress(16);
|
address tokenAddress = assetData.readAddress(16);
|
||||||
|
balance = _erc20BalanceOf(tokenAddress, ownerAddress);
|
||||||
|
|
||||||
// Encode data for `balanceOf(ownerAddress)`
|
|
||||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
|
||||||
IERC20Token(address(0)).balanceOf.selector,
|
|
||||||
ownerAddress
|
|
||||||
);
|
|
||||||
|
|
||||||
// Query balance
|
|
||||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
|
||||||
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||||
// Get ERC721 token address and id
|
// Get ERC721 token address and id
|
||||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||||
@@ -94,12 +94,18 @@ contract LibAssetData {
|
|||||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
||||||
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||||
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
|
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
|
||||||
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||||
// Get ERC1155 token address, array of ids, and array of values
|
// Get ERC1155 token address, array of ids, and array of values
|
||||||
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
|
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
|
||||||
|
|
||||||
uint256 length = tokenIds.length;
|
uint256 length = tokenIds.length;
|
||||||
for (uint256 i = 0; i != length; i++) {
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// Skip over the token if the corresponding value is 0.
|
||||||
|
if (tokenValues[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
|
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
|
||||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||||
IERC1155(address(0)).balanceOf.selector,
|
IERC1155(address(0)).balanceOf.selector,
|
||||||
@@ -113,10 +119,14 @@ contract LibAssetData {
|
|||||||
|
|
||||||
// Scale total balance down by corresponding value in assetData
|
// Scale total balance down by corresponding value in assetData
|
||||||
uint256 scaledBalance = totalBalance / tokenValues[i];
|
uint256 scaledBalance = totalBalance / tokenValues[i];
|
||||||
|
if (scaledBalance == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (scaledBalance < balance || balance == 0) {
|
if (scaledBalance < balance || balance == 0) {
|
||||||
balance = scaledBalance;
|
balance = scaledBalance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||||
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
|
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
|
||||||
bytes memory transferFromData = abi.encodeWithSelector(
|
bytes memory transferFromData = abi.encodeWithSelector(
|
||||||
@@ -132,17 +142,36 @@ contract LibAssetData {
|
|||||||
|
|
||||||
// Success means that the staticcall can be made an unlimited amount of times
|
// Success means that the staticcall can be made an unlimited amount of times
|
||||||
balance = success ? _MAX_UINT256 : 0;
|
balance = success ? _MAX_UINT256 : 0;
|
||||||
|
|
||||||
|
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
|
||||||
|
// Get address of ERC20 token and bridge contract
|
||||||
|
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
|
||||||
|
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
|
||||||
|
uint256 chaiBalance = _erc20BalanceOf(_getChaiAddress(), ownerAddress);
|
||||||
|
// Calculate Dai balance
|
||||||
|
balance = _convertChaiToDaiAmount(chaiBalance);
|
||||||
|
}
|
||||||
|
// Balance will be 0 if bridge is not supported
|
||||||
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
|
||||||
// Get array of values and array of assetDatas
|
// Get array of values and array of assetDatas
|
||||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||||
|
|
||||||
uint256 length = nestedAssetData.length;
|
uint256 length = nestedAssetData.length;
|
||||||
for (uint256 i = 0; i != length; i++) {
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// Skip over the asset if the corresponding amount is 0.
|
||||||
|
if (assetAmounts[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Query balance of individual assetData
|
// Query balance of individual assetData
|
||||||
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
|
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
|
||||||
|
|
||||||
// Scale total balance down by corresponding value in assetData
|
// Scale total balance down by corresponding value in assetData
|
||||||
uint256 scaledBalance = totalBalance / assetAmounts[i];
|
uint256 scaledBalance = totalBalance / assetAmounts[i];
|
||||||
|
if (scaledBalance == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (scaledBalance < balance || balance == 0) {
|
if (scaledBalance < balance || balance == 0) {
|
||||||
balance = scaledBalance;
|
balance = scaledBalance;
|
||||||
}
|
}
|
||||||
@@ -160,7 +189,6 @@ contract LibAssetData {
|
|||||||
/// corresponding to the same-indexed element in the assetData input.
|
/// corresponding to the same-indexed element in the assetData input.
|
||||||
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
|
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256[] memory balances)
|
returns (uint256[] memory balances)
|
||||||
{
|
{
|
||||||
uint256 length = assetData.length;
|
uint256 length = assetData.length;
|
||||||
@@ -181,7 +209,6 @@ contract LibAssetData {
|
|||||||
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
||||||
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256 allowance)
|
returns (uint256 allowance)
|
||||||
{
|
{
|
||||||
// Get id of AssetProxy contract
|
// Get id of AssetProxy contract
|
||||||
@@ -193,11 +220,19 @@ contract LibAssetData {
|
|||||||
|
|
||||||
uint256 length = nestedAssetData.length;
|
uint256 length = nestedAssetData.length;
|
||||||
for (uint256 i = 0; i != length; i++) {
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// Skip over the asset if the corresponding amount is 0.
|
||||||
|
if (amounts[i] == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Query allowance of individual assetData
|
// Query allowance of individual assetData
|
||||||
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
|
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
|
||||||
|
|
||||||
// Scale total allowance down by corresponding value in assetData
|
// Scale total allowance down by corresponding value in assetData
|
||||||
uint256 scaledAllowance = totalAllowance / amounts[i];
|
uint256 scaledAllowance = totalAllowance / amounts[i];
|
||||||
|
if (scaledAllowance == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (scaledAllowance < allowance || allowance == 0) {
|
if (scaledAllowance < allowance || allowance == 0) {
|
||||||
allowance = scaledAllowance;
|
allowance = scaledAllowance;
|
||||||
}
|
}
|
||||||
@@ -219,6 +254,7 @@ contract LibAssetData {
|
|||||||
// Query allowance
|
// Query allowance
|
||||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
|
||||||
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||||
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||||
// Get ERC721 token address and id
|
// Get ERC721 token address and id
|
||||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||||
@@ -244,6 +280,7 @@ contract LibAssetData {
|
|||||||
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
|
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
|
||||||
allowance = _MAX_UINT256;
|
allowance = _MAX_UINT256;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||||
// Get ERC1155 token address
|
// Get ERC1155 token address
|
||||||
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||||
@@ -258,9 +295,26 @@ contract LibAssetData {
|
|||||||
// Query allowance
|
// Query allowance
|
||||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
||||||
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
||||||
|
|
||||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||||
// The StaticCallProxy does not require any approvals
|
// The StaticCallProxy does not require any approvals
|
||||||
allowance = _MAX_UINT256;
|
allowance = _MAX_UINT256;
|
||||||
|
|
||||||
|
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
|
||||||
|
// Get address of ERC20 token and bridge contract
|
||||||
|
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
|
||||||
|
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
|
||||||
|
bytes memory allowanceData = abi.encodeWithSelector(
|
||||||
|
IERC20Token(address(0)).allowance.selector,
|
||||||
|
ownerAddress,
|
||||||
|
_CHAI_BRIDGE_ADDRESS
|
||||||
|
);
|
||||||
|
(bool success, bytes memory returnData) = _getChaiAddress().staticcall(allowanceData);
|
||||||
|
uint256 chaiAllowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||||
|
// Dai allowance is unlimited if Chai allowance is unlimited
|
||||||
|
allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
|
||||||
|
}
|
||||||
|
// Allowance will be 0 if bridge is not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allowance will be 0 if the assetProxyId is unknown
|
// Allowance will be 0 if the assetProxyId is unknown
|
||||||
@@ -274,7 +328,6 @@ contract LibAssetData {
|
|||||||
/// element corresponding to the same-indexed element in the assetData input.
|
/// element corresponding to the same-indexed element in the assetData input.
|
||||||
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256[] memory allowances)
|
returns (uint256[] memory allowances)
|
||||||
{
|
{
|
||||||
uint256 length = assetData.length;
|
uint256 length = assetData.length;
|
||||||
@@ -292,7 +345,6 @@ contract LibAssetData {
|
|||||||
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
||||||
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256 balance, uint256 allowance)
|
returns (uint256 balance, uint256 allowance)
|
||||||
{
|
{
|
||||||
balance = getBalance(ownerAddress, assetData);
|
balance = getBalance(ownerAddress, assetData);
|
||||||
@@ -308,7 +360,6 @@ contract LibAssetData {
|
|||||||
/// corresponding to the same-indexed element in the assetData input.
|
/// corresponding to the same-indexed element in the assetData input.
|
||||||
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256[] memory balances, uint256[] memory allowances)
|
returns (uint256[] memory balances, uint256[] memory allowances)
|
||||||
{
|
{
|
||||||
balances = getBatchBalances(ownerAddress, assetData);
|
balances = getBatchBalances(ownerAddress, assetData);
|
||||||
@@ -589,6 +640,35 @@ contract LibAssetData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
|
||||||
|
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
|
||||||
|
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
|
||||||
|
/// of the bridge contract, and extra data to be passed to the bridge contract.
|
||||||
|
function decodeERC20BridgeAssetData(bytes memory assetData)
|
||||||
|
public
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
bytes4 assetProxyId,
|
||||||
|
address tokenAddress,
|
||||||
|
address bridgeAddress,
|
||||||
|
bytes memory bridgeData
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assetProxyId = assetData.readBytes4(0);
|
||||||
|
|
||||||
|
require(
|
||||||
|
assetProxyId == IAssetData(address(0)).ERC20Bridge.selector,
|
||||||
|
"WRONG_PROXY_ID"
|
||||||
|
);
|
||||||
|
|
||||||
|
(tokenAddress, bridgeAddress, bridgeData) = abi.decode(
|
||||||
|
assetData.slice(4, assetData.length),
|
||||||
|
(address, address, bytes)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Reverts if assetData is not of a valid format for its given proxy id.
|
||||||
|
/// @param assetData AssetProxy compliant asset data.
|
||||||
function revertIfInvalidAssetData(bytes memory assetData)
|
function revertIfInvalidAssetData(bytes memory assetData)
|
||||||
public
|
public
|
||||||
pure
|
pure
|
||||||
@@ -605,8 +685,50 @@ contract LibAssetData {
|
|||||||
decodeMultiAssetData(assetData);
|
decodeMultiAssetData(assetData);
|
||||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||||
decodeStaticCallAssetData(assetData);
|
decodeStaticCallAssetData(assetData);
|
||||||
|
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
|
||||||
|
decodeERC20BridgeAssetData(assetData);
|
||||||
} else {
|
} else {
|
||||||
revert("WRONG_PROXY_ID");
|
revert("WRONG_PROXY_ID");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Queries balance of an ERC20 token. Returns 0 if call was unsuccessful.
|
||||||
|
/// @param tokenAddress Address of ERC20 token.
|
||||||
|
/// @param ownerAddress Address of owner of ERC20 token.
|
||||||
|
/// @return balance ERC20 token balance of owner.
|
||||||
|
function _erc20BalanceOf(
|
||||||
|
address tokenAddress,
|
||||||
|
address ownerAddress
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint256 balance)
|
||||||
|
{
|
||||||
|
// Encode data for `balanceOf(ownerAddress)`
|
||||||
|
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||||
|
IERC20Token(address(0)).balanceOf.selector,
|
||||||
|
ownerAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query balance
|
||||||
|
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
||||||
|
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Converts an amount of Chai into its equivalent Dai amount.
|
||||||
|
/// Also accumulates Dai from DSR if called after the last time it was collected.
|
||||||
|
/// @param chaiAmount Amount of Chai to converts.
|
||||||
|
function _convertChaiToDaiAmount(uint256 chaiAmount)
|
||||||
|
internal
|
||||||
|
returns (uint256 daiAmount)
|
||||||
|
{
|
||||||
|
PotLike pot = IChai(_getChaiAddress()).pot();
|
||||||
|
// Accumulate savings if called after last time savings were collected
|
||||||
|
uint256 chiMultiplier = (now > pot.rho())
|
||||||
|
? pot.drip()
|
||||||
|
: pot.chi();
|
||||||
|
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
|
||||||
|
return daiAmount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,6 +41,10 @@ contract OrderTransferSimulationUtils is
|
|||||||
TransfersSuccessful // All transfers in the order were successful
|
TransfersSuccessful // All transfers in the order were successful
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)`
|
||||||
|
// may cause later.
|
||||||
|
address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332);
|
||||||
|
|
||||||
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
|
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
|
||||||
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
|
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
|
||||||
|
|
||||||
@@ -82,13 +86,13 @@ contract OrderTransferSimulationUtils is
|
|||||||
// Transfer `makerAsset` from maker to taker
|
// Transfer `makerAsset` from maker to taker
|
||||||
assetData[0] = order.makerAssetData;
|
assetData[0] = order.makerAssetData;
|
||||||
fromAddresses[0] = order.makerAddress;
|
fromAddresses[0] = order.makerAddress;
|
||||||
toAddresses[0] = takerAddress;
|
toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
|
||||||
amounts[0] = fillResults.makerAssetFilledAmount;
|
amounts[0] = fillResults.makerAssetFilledAmount;
|
||||||
|
|
||||||
// Transfer `makerFeeAsset` from maker to feeRecipient
|
// Transfer `makerFeeAsset` from maker to feeRecipient
|
||||||
assetData[1] = order.makerFeeAssetData;
|
assetData[1] = order.makerFeeAssetData;
|
||||||
fromAddresses[1] = order.makerAddress;
|
fromAddresses[1] = order.makerAddress;
|
||||||
toAddresses[1] = order.feeRecipientAddress;
|
toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
|
||||||
amounts[1] = fillResults.makerFeePaid;
|
amounts[1] = fillResults.makerFeePaid;
|
||||||
|
|
||||||
return _simulateTransferFromCalls(
|
return _simulateTransferFromCalls(
|
||||||
@@ -134,19 +138,19 @@ contract OrderTransferSimulationUtils is
|
|||||||
// Transfer `makerAsset` from maker to taker
|
// Transfer `makerAsset` from maker to taker
|
||||||
assetData[1] = order.makerAssetData;
|
assetData[1] = order.makerAssetData;
|
||||||
fromAddresses[1] = order.makerAddress;
|
fromAddresses[1] = order.makerAddress;
|
||||||
toAddresses[1] = takerAddress;
|
toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
|
||||||
amounts[1] = fillResults.makerAssetFilledAmount;
|
amounts[1] = fillResults.makerAssetFilledAmount;
|
||||||
|
|
||||||
// Transfer `takerFeeAsset` from taker to feeRecipient
|
// Transfer `takerFeeAsset` from taker to feeRecipient
|
||||||
assetData[2] = order.takerFeeAssetData;
|
assetData[2] = order.takerFeeAssetData;
|
||||||
fromAddresses[2] = takerAddress;
|
fromAddresses[2] = takerAddress;
|
||||||
toAddresses[2] = order.feeRecipientAddress;
|
toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
|
||||||
amounts[2] = fillResults.takerFeePaid;
|
amounts[2] = fillResults.takerFeePaid;
|
||||||
|
|
||||||
// Transfer `makerFeeAsset` from maker to feeRecipient
|
// Transfer `makerFeeAsset` from maker to feeRecipient
|
||||||
assetData[3] = order.makerFeeAssetData;
|
assetData[3] = order.makerFeeAssetData;
|
||||||
fromAddresses[3] = order.makerAddress;
|
fromAddresses[3] = order.makerAddress;
|
||||||
toAddresses[3] = order.feeRecipientAddress;
|
toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
|
||||||
amounts[3] = fillResults.makerFeePaid;
|
amounts[3] = fillResults.makerFeePaid;
|
||||||
|
|
||||||
return _simulateTransferFromCalls(
|
return _simulateTransferFromCalls(
|
||||||
|
@@ -35,9 +35,15 @@ contract OrderValidationUtils is
|
|||||||
using LibBytes for bytes;
|
using LibBytes for bytes;
|
||||||
using LibSafeMath for uint256;
|
using LibSafeMath for uint256;
|
||||||
|
|
||||||
constructor (address _exchange)
|
constructor (
|
||||||
|
address _exchange,
|
||||||
|
address _chaiBridge
|
||||||
|
)
|
||||||
public
|
public
|
||||||
LibAssetData(_exchange)
|
LibAssetData(
|
||||||
|
_exchange,
|
||||||
|
_chaiBridge
|
||||||
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||||
@@ -127,6 +133,18 @@ contract OrderValidationUtils is
|
|||||||
fillableTakerAssetAmount
|
fillableTakerAssetAmount
|
||||||
) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
|
) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
|
||||||
|
|
||||||
|
if (!_isAssetDataValid(order.takerAssetData)) {
|
||||||
|
fillableTakerAssetAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order.takerFee != 0 && !_isAssetDataValid(order.takerFeeAssetData)) {
|
||||||
|
fillableTakerAssetAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
|
||||||
|
fillableTakerAssetAmount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
|
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,11 +191,69 @@ contract OrderValidationUtils is
|
|||||||
/// the individual asset amounts located within the `assetData`.
|
/// the individual asset amounts located within the `assetData`.
|
||||||
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
|
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
|
||||||
public
|
public
|
||||||
view
|
|
||||||
returns (uint256 transferableAssetAmount)
|
returns (uint256 transferableAssetAmount)
|
||||||
{
|
{
|
||||||
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
|
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
|
||||||
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
|
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
|
||||||
return transferableAssetAmount;
|
return transferableAssetAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev This function handles the edge cases around taker validation. This function
|
||||||
|
/// currently attempts to find duplicate ERC721 token's in the taker
|
||||||
|
/// multiAssetData.
|
||||||
|
/// @param assetData The asset data that should be validated.
|
||||||
|
/// @return Whether or not the order should be considered valid.
|
||||||
|
function _isAssetDataValid(bytes memory assetData)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
// Asset data must be composed of an asset proxy Id and a bytes segment with
|
||||||
|
// a length divisible by 32.
|
||||||
|
if (assetData.length % 32 != 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only process the taker asset data if it is multiAssetData.
|
||||||
|
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||||
|
if (assetProxyId != IAssetData(address(0)).MultiAsset.selector) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get array of values and array of assetDatas
|
||||||
|
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||||
|
|
||||||
|
uint256 length = nestedAssetData.length;
|
||||||
|
for (uint256 i = 0; i != length; i++) {
|
||||||
|
// TODO(jalextowle): Implement similar validation for non-fungible ERC1155 asset data.
|
||||||
|
bytes4 nestedAssetProxyId = nestedAssetData[i].readBytes4(0);
|
||||||
|
if (nestedAssetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||||
|
if (_isAssetDataDuplicated(nestedAssetData, i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether or not asset data is duplicated later in the nested asset data.
|
||||||
|
/// @param nestedAssetData The asset data to scan for duplication.
|
||||||
|
/// @param startIdx The index where the scan should begin.
|
||||||
|
/// @return A boolean reflecting whether or not the starting asset data was duplicated.
|
||||||
|
function _isAssetDataDuplicated(
|
||||||
|
bytes[] memory nestedAssetData,
|
||||||
|
uint256 startIdx
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
uint256 length = nestedAssetData.length;
|
||||||
|
for (uint256 i = startIdx + 1; i < length; i++) {
|
||||||
|
if (nestedAssetData[startIdx].equals(nestedAssetData[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-dev-utils",
|
"name": "@0x/contracts-dev-utils",
|
||||||
"version": "1.0.3",
|
"version": "1.0.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -41,10 +41,10 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/assert": "^3.0.3",
|
"@0x/assert": "^3.0.5",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3"
|
"@0x/base-contract": "^6.1.2"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
|||||||
solc: {
|
solc: {
|
||||||
version: '0.5.9',
|
version: '0.5.9',
|
||||||
settings: {
|
settings: {
|
||||||
evmVersion: 'constantinople',
|
evmVersion: 'istanbul',
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 1000000,
|
runs: 1000000,
|
||||||
|
@@ -1,4 +1,31 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1578272714,
|
"timestamp": 1578272714,
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v2.0.3 - _January 6, 2020_
|
## v2.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibAddress.sol";
|
import "@0x/contracts-utils/contracts/src/LibAddress.sol";
|
||||||
|
@@ -1,4 +1,23 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
import "./ERC1155.sol";
|
import "./ERC1155.sol";
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
contract MixinNonFungibleToken {
|
contract MixinNonFungibleToken {
|
||||||
@@ -64,7 +65,7 @@ contract MixinNonFungibleToken {
|
|||||||
// A base type has the NF bit but does has an index.
|
// A base type has the NF bit but does has an index.
|
||||||
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
|
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev returns owner of a non-fungible token
|
/// @dev returns owner of a non-fungible token
|
||||||
function ownerOf(uint256 id) public view returns (address) {
|
function ownerOf(uint256 id) public view returns (address) {
|
||||||
return nfOwners[id];
|
return nfOwners[id];
|
||||||
|
@@ -17,13 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
/// @title ERC-1155 Multi Token Standard
|
/// @title ERC-1155 Multi Token Standard
|
||||||
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
|
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
|
||||||
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
|
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
|
||||||
interface IERC1155 {
|
interface IERC1155 {
|
||||||
|
|
||||||
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
|
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
|
||||||
/// including zero value transfers as well as minting or burning.
|
/// including zero value transfers as well as minting or burning.
|
||||||
/// Operator will always be msg.sender.
|
/// Operator will always be msg.sender.
|
||||||
|
@@ -1,4 +1,23 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./IERC1155.sol";
|
import "./IERC1155.sol";
|
||||||
|
|
||||||
|
@@ -17,10 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
interface IERC1155Receiver {
|
interface IERC1155Receiver {
|
||||||
|
|
||||||
/// @notice Handle the receipt of a single ERC1155 token type
|
/// @notice Handle the receipt of a single ERC1155 token type
|
||||||
/// @dev The smart contract calls this function on the recipient
|
/// @dev The smart contract calls this function on the recipient
|
||||||
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc1155",
|
"name": "@0x/contracts-erc1155",
|
||||||
"version": "2.0.3",
|
"version": "2.0.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -52,11 +52,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
@@ -80,10 +80,10 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3",
|
"@0x/base-contract": "^6.1.2",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers';
|
import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers';
|
||||||
@@ -8,7 +8,7 @@ export class Erc1155Wrapper {
|
|||||||
private readonly _erc1155Contract: ERC1155MintableContract;
|
private readonly _erc1155Contract: ERC1155MintableContract;
|
||||||
private readonly _contractOwner: string;
|
private readonly _contractOwner: string;
|
||||||
|
|
||||||
constructor(contractInstance: ERC1155MintableContract, provider: Provider, contractOwner: string) {
|
constructor(contractInstance: ERC1155MintableContract, contractOwner: string) {
|
||||||
this._erc1155Contract = contractInstance;
|
this._erc1155Contract = contractInstance;
|
||||||
this._contractOwner = contractOwner;
|
this._contractOwner = contractOwner;
|
||||||
}
|
}
|
||||||
|
@@ -5,21 +5,18 @@ export {
|
|||||||
IERC1155ReceiverContract,
|
IERC1155ReceiverContract,
|
||||||
DummyERC1155ReceiverBatchTokenReceivedEventArgs,
|
DummyERC1155ReceiverBatchTokenReceivedEventArgs,
|
||||||
ERC1155TransferSingleEventArgs,
|
ERC1155TransferSingleEventArgs,
|
||||||
|
ERC1155TransferBatchEventArgs,
|
||||||
|
ERC1155Events,
|
||||||
} from './wrappers';
|
} from './wrappers';
|
||||||
export { artifacts } from './artifacts';
|
export { artifacts } from './artifacts';
|
||||||
export { Erc1155Wrapper } from './erc1155_wrapper';
|
export { Erc1155Wrapper } from './erc1155_wrapper';
|
||||||
export {
|
export {
|
||||||
Provider,
|
|
||||||
TransactionReceiptWithDecodedLogs,
|
TransactionReceiptWithDecodedLogs,
|
||||||
JSONRPCRequestPayload,
|
|
||||||
JSONRPCResponsePayload,
|
|
||||||
JSONRPCResponseError,
|
|
||||||
JSONRPCErrorCallback,
|
|
||||||
TransactionReceiptStatus,
|
TransactionReceiptStatus,
|
||||||
ContractArtifact,
|
|
||||||
ContractChains,
|
ContractChains,
|
||||||
CompilerOpts,
|
CompilerOpts,
|
||||||
StandardContractOutput,
|
StandardContractOutput,
|
||||||
|
ContractArtifact,
|
||||||
CompilerSettings,
|
CompilerSettings,
|
||||||
ContractChainData,
|
ContractChainData,
|
||||||
ContractAbi,
|
ContractAbi,
|
||||||
|
@@ -67,7 +67,7 @@ describe('ERC1155Token', () => {
|
|||||||
);
|
);
|
||||||
receiver = erc1155Receiver.address;
|
receiver = erc1155Receiver.address;
|
||||||
// create wrapper & mint erc1155 tokens
|
// create wrapper & mint erc1155 tokens
|
||||||
erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, provider, owner);
|
erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, owner);
|
||||||
fungibleToken = await erc1155Wrapper.mintFungibleTokensAsync([spender], spenderInitialFungibleBalance);
|
fungibleToken = await erc1155Wrapper.mintFungibleTokensAsync([spender], spenderInitialFungibleBalance);
|
||||||
let nonFungibleTokens: BigNumber[];
|
let nonFungibleTokens: BigNumber[];
|
||||||
[, nonFungibleTokens] = await erc1155Wrapper.mintNonFungibleTokensAsync([spender]);
|
[, nonFungibleTokens] = await erc1155Wrapper.mintNonFungibleTokensAsync([spender]);
|
||||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
|||||||
solc: {
|
solc: {
|
||||||
version: '0.5.9',
|
version: '0.5.9',
|
||||||
settings: {
|
settings: {
|
||||||
evmVersion: 'constantinople',
|
evmVersion: 'istanbul',
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 1000000,
|
runs: 1000000,
|
||||||
|
@@ -1,4 +1,37 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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": [
|
||||||
|
{
|
||||||
|
"note": "Add batch functions to query quotes",
|
||||||
|
"pr": 2427
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Early exit if a DEX sample fails",
|
||||||
|
"pr": 2427
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1579682890
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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)
|
||||||
|
* Early exit if a DEX sample fails (#2427)
|
||||||
|
|
||||||
## v1.0.3 - _January 6, 2020_
|
## v1.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Add gas limits to external quote calls. (#2405)
|
* Add gas limits to external quote calls. (#2405)
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -37,9 +37,76 @@ contract ERC20BridgeSampler is
|
|||||||
DeploymentConstants
|
DeploymentConstants
|
||||||
{
|
{
|
||||||
bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)"));
|
bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)"));
|
||||||
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 600e3;
|
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 1500e3;
|
||||||
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
|
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
|
||||||
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 250e3;
|
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.
|
||||||
|
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||||
|
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||||
|
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
|
||||||
|
/// @return ordersAndSamples How much taker asset can be filled
|
||||||
|
/// by each order in `orders`. Maker amounts bought for each source at
|
||||||
|
/// each taker token amount. First indexed by source index, then sample
|
||||||
|
/// index.
|
||||||
|
function queryBatchOrdersAndSampleSells(
|
||||||
|
LibOrder.Order[][] memory orders,
|
||||||
|
bytes[][] memory orderSignatures,
|
||||||
|
address[] memory sources,
|
||||||
|
uint256[][] memory takerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
OrdersAndSample[] memory ordersAndSamples
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ordersAndSamples = new OrdersAndSample[](orders.length);
|
||||||
|
for (uint256 i = 0; i != orders.length; i++) {
|
||||||
|
(
|
||||||
|
uint256[] memory orderFillableAssetAmounts,
|
||||||
|
uint256[][] memory tokenAmountsBySource
|
||||||
|
) = queryOrdersAndSampleSells(orders[i], orderSignatures[i], sources, takerTokenAmounts[i]);
|
||||||
|
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
|
||||||
|
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
|
||||||
|
/// @param orders Batches of Native orders to query.
|
||||||
|
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||||
|
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||||
|
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
|
||||||
|
/// @return ordersAndSamples How much taker asset can be filled
|
||||||
|
/// by each order in `orders`. Taker amounts sold for each source at
|
||||||
|
/// each maker token amount. First indexed by source index, then sample
|
||||||
|
/// index.
|
||||||
|
function queryBatchOrdersAndSampleBuys(
|
||||||
|
LibOrder.Order[][] memory orders,
|
||||||
|
bytes[][] memory orderSignatures,
|
||||||
|
address[] memory sources,
|
||||||
|
uint256[][] memory makerTokenAmounts
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
OrdersAndSample[] memory ordersAndSamples
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ordersAndSamples = new OrdersAndSample[](orders.length);
|
||||||
|
for (uint256 i = 0; i != orders.length; i++) {
|
||||||
|
(
|
||||||
|
uint256[] memory orderFillableAssetAmounts,
|
||||||
|
uint256[][] memory tokenAmountsBySource
|
||||||
|
) = queryOrdersAndSampleBuys(orders[i], orderSignatures[i], sources, makerTokenAmounts[i]);
|
||||||
|
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
|
||||||
|
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||||
/// @param orders Native orders to query.
|
/// @param orders Native orders to query.
|
||||||
@@ -281,6 +348,8 @@ contract ERC20BridgeSampler is
|
|||||||
uint256 rate = 0;
|
uint256 rate = 0;
|
||||||
if (didSucceed) {
|
if (didSucceed) {
|
||||||
rate = abi.decode(resultData, (uint256));
|
rate = abi.decode(resultData, (uint256));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
makerTokenAmounts[i] =
|
makerTokenAmounts[i] =
|
||||||
rate *
|
rate *
|
||||||
@@ -321,6 +390,8 @@ contract ERC20BridgeSampler is
|
|||||||
uint256 buyAmount = 0;
|
uint256 buyAmount = 0;
|
||||||
if (didSucceed) {
|
if (didSucceed) {
|
||||||
buyAmount = abi.decode(resultData, (uint256));
|
buyAmount = abi.decode(resultData, (uint256));
|
||||||
|
} else{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
makerTokenAmounts[i] = buyAmount;
|
makerTokenAmounts[i] = buyAmount;
|
||||||
}
|
}
|
||||||
@@ -356,6 +427,8 @@ contract ERC20BridgeSampler is
|
|||||||
uint256 sellAmount = 0;
|
uint256 sellAmount = 0;
|
||||||
if (didSucceed) {
|
if (didSucceed) {
|
||||||
sellAmount = abi.decode(resultData, (uint256));
|
sellAmount = abi.decode(resultData, (uint256));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
takerTokenAmounts[i] = sellAmount;
|
takerTokenAmounts[i] = sellAmount;
|
||||||
}
|
}
|
||||||
@@ -384,26 +457,28 @@ contract ERC20BridgeSampler is
|
|||||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||||
for (uint256 i = 0; i < numSamples; i++) {
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
bool didSucceed = true;
|
||||||
if (makerToken == _getWethAddress()) {
|
if (makerToken == _getWethAddress()) {
|
||||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(takerTokenExchange),
|
address(takerTokenExchange),
|
||||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||||
takerTokenAmounts[i]
|
takerTokenAmounts[i]
|
||||||
);
|
);
|
||||||
} else if (takerToken == _getWethAddress()) {
|
} else if (takerToken == _getWethAddress()) {
|
||||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(makerTokenExchange),
|
address(makerTokenExchange),
|
||||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||||
takerTokenAmounts[i]
|
takerTokenAmounts[i]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
uint256 ethBought = _callUniswapExchangePriceFunction(
|
uint256 ethBought;
|
||||||
|
(ethBought, didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(takerTokenExchange),
|
address(takerTokenExchange),
|
||||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||||
takerTokenAmounts[i]
|
takerTokenAmounts[i]
|
||||||
);
|
);
|
||||||
if (ethBought != 0) {
|
if (ethBought != 0) {
|
||||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(makerTokenExchange),
|
address(makerTokenExchange),
|
||||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||||
ethBought
|
ethBought
|
||||||
@@ -412,6 +487,9 @@ contract ERC20BridgeSampler is
|
|||||||
makerTokenAmounts[i] = 0;
|
makerTokenAmounts[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!didSucceed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,26 +516,28 @@ contract ERC20BridgeSampler is
|
|||||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||||
for (uint256 i = 0; i < numSamples; i++) {
|
for (uint256 i = 0; i < numSamples; i++) {
|
||||||
|
bool didSucceed = true;
|
||||||
if (makerToken == _getWethAddress()) {
|
if (makerToken == _getWethAddress()) {
|
||||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(takerTokenExchange),
|
address(takerTokenExchange),
|
||||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||||
makerTokenAmounts[i]
|
makerTokenAmounts[i]
|
||||||
);
|
);
|
||||||
} else if (takerToken == _getWethAddress()) {
|
} else if (takerToken == _getWethAddress()) {
|
||||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(makerTokenExchange),
|
address(makerTokenExchange),
|
||||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||||
makerTokenAmounts[i]
|
makerTokenAmounts[i]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
uint256 ethSold = _callUniswapExchangePriceFunction(
|
uint256 ethSold;
|
||||||
|
(ethSold, didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(makerTokenExchange),
|
address(makerTokenExchange),
|
||||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||||
makerTokenAmounts[i]
|
makerTokenAmounts[i]
|
||||||
);
|
);
|
||||||
if (ethSold != 0) {
|
if (ethSold != 0) {
|
||||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||||
address(takerTokenExchange),
|
address(takerTokenExchange),
|
||||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||||
ethSold
|
ethSold
|
||||||
@@ -466,6 +546,9 @@ contract ERC20BridgeSampler is
|
|||||||
takerTokenAmounts[i] = 0;
|
takerTokenAmounts[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!didSucceed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,12 +576,13 @@ contract ERC20BridgeSampler is
|
|||||||
)
|
)
|
||||||
private
|
private
|
||||||
view
|
view
|
||||||
returns (uint256 outputAmount)
|
returns (uint256 outputAmount, bool didSucceed)
|
||||||
{
|
{
|
||||||
if (uniswapExchangeAddress == address(0)) {
|
if (uniswapExchangeAddress == address(0)) {
|
||||||
return 0;
|
return (outputAmount, didSucceed);
|
||||||
}
|
}
|
||||||
(bool didSucceed, bytes memory resultData) =
|
bytes memory resultData;
|
||||||
|
(didSucceed, resultData) =
|
||||||
uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)(
|
uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)(
|
||||||
abi.encodeWithSelector(
|
abi.encodeWithSelector(
|
||||||
functionSelector,
|
functionSelector,
|
||||||
@@ -525,13 +609,13 @@ contract ERC20BridgeSampler is
|
|||||||
view
|
view
|
||||||
returns (uint256[] memory makerTokenAmounts)
|
returns (uint256[] memory makerTokenAmounts)
|
||||||
{
|
{
|
||||||
if (source == _getEth2DaiAddress()) {
|
if (source == ETH2DAI_SOURCE) {
|
||||||
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
||||||
}
|
}
|
||||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
if (source == UNISWAP_SOURCE) {
|
||||||
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
||||||
}
|
}
|
||||||
if (source == _getKyberNetworkProxyAddress()) {
|
if (source == KYBER_SOURCE) {
|
||||||
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
||||||
}
|
}
|
||||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||||
@@ -553,10 +637,10 @@ contract ERC20BridgeSampler is
|
|||||||
view
|
view
|
||||||
returns (uint256[] memory takerTokenAmounts)
|
returns (uint256[] memory takerTokenAmounts)
|
||||||
{
|
{
|
||||||
if (source == _getEth2DaiAddress()) {
|
if (source == ETH2DAI_SOURCE) {
|
||||||
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
||||||
}
|
}
|
||||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
if (source == UNISWAP_SOURCE) {
|
||||||
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
||||||
}
|
}
|
||||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||||
|
@@ -23,6 +23,52 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
|||||||
|
|
||||||
|
|
||||||
interface IERC20BridgeSampler {
|
interface IERC20BridgeSampler {
|
||||||
|
struct OrdersAndSample {
|
||||||
|
uint256[] orderFillableAssetAmounts;
|
||||||
|
uint256[][] tokenAmountsBySource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
|
||||||
|
/// @param orders Batches of Native orders to query.
|
||||||
|
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||||
|
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||||
|
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
|
||||||
|
/// @return ordersAndSamples How much taker asset can be filled
|
||||||
|
/// by each order in `orders`. Maker amounts bought for each source at
|
||||||
|
/// each taker token amount. First indexed by source index, then sample
|
||||||
|
/// index.
|
||||||
|
function queryBatchOrdersAndSampleSells(
|
||||||
|
LibOrder.Order[][] calldata orders,
|
||||||
|
bytes[][] calldata orderSignatures,
|
||||||
|
address[] calldata sources,
|
||||||
|
uint256[][] calldata takerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
OrdersAndSample[] memory ordersAndSamples
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
|
||||||
|
/// @param orders Batches of Native orders to query.
|
||||||
|
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||||
|
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||||
|
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
|
||||||
|
/// @return ordersAndSamples How much taker asset can be filled
|
||||||
|
/// by each order in `orders`. Taker amounts sold for each source at
|
||||||
|
/// each maker token amount. First indexed by source index, then sample
|
||||||
|
/// index
|
||||||
|
function queryBatchOrdersAndSampleBuys(
|
||||||
|
LibOrder.Order[][] calldata orders,
|
||||||
|
bytes[][] calldata orderSignatures,
|
||||||
|
address[] calldata sources,
|
||||||
|
uint256[][] calldata makerTokenAmounts
|
||||||
|
)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
OrdersAndSample[] memory ordersAndSamples
|
||||||
|
);
|
||||||
|
|
||||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||||
/// @param orders Native orders to query.
|
/// @param orders Native orders to query.
|
||||||
|
@@ -338,7 +338,11 @@ contract TestERC20BridgeSampler is
|
|||||||
bytes32 orderHash = keccak256(abi.encode(order.salt));
|
bytes32 orderHash = keccak256(abi.encode(order.salt));
|
||||||
// Everything else is derived from the hash.
|
// Everything else is derived from the hash.
|
||||||
orderInfo.orderHash = orderHash;
|
orderInfo.orderHash = orderHash;
|
||||||
orderInfo.orderStatus = LibOrder.OrderStatus(uint256(orderHash) % MAX_ORDER_STATUS);
|
if (uint256(orderHash) % 100 > 90) {
|
||||||
|
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
|
||||||
|
} else {
|
||||||
|
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
|
||||||
|
}
|
||||||
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
|
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
|
||||||
fillableTakerAssetAmount =
|
fillableTakerAssetAmount =
|
||||||
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
|
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||||
"version": "1.0.3",
|
"version": "1.2.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -50,18 +50,18 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||||
"@0x/contracts-erc20": "^3.0.3",
|
"@0x/contracts-erc20": "^3.0.6",
|
||||||
"@0x/contracts-exchange": "^3.0.3",
|
"@0x/contracts-exchange": "^3.1.2",
|
||||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -79,10 +79,10 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3",
|
"@0x/base-contract": "^6.1.2",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
"@0x/typescript-typings": "^5.0.1",
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"ethereum-types": "^3.0.0",
|
"ethereum-types": "^3.0.0",
|
||||||
"lodash": "^4.17.11"
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
|
@@ -15,7 +15,6 @@ import { TestERC20BridgeSamplerContract } from './wrappers';
|
|||||||
|
|
||||||
blockchainTests('erc20-bridge-sampler', env => {
|
blockchainTests('erc20-bridge-sampler', env => {
|
||||||
let testContract: TestERC20BridgeSamplerContract;
|
let testContract: TestERC20BridgeSamplerContract;
|
||||||
let allSources: { [name: string]: string };
|
|
||||||
const RATE_DENOMINATOR = constants.ONE_ETHER;
|
const RATE_DENOMINATOR = constants.ONE_ETHER;
|
||||||
const MIN_RATE = new BigNumber('0.01');
|
const MIN_RATE = new BigNumber('0.01');
|
||||||
const MAX_RATE = new BigNumber('100');
|
const MAX_RATE = new BigNumber('100');
|
||||||
@@ -30,6 +29,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const INVALID_ASSET_DATA = hexUtils.random(37);
|
const INVALID_ASSET_DATA = hexUtils.random(37);
|
||||||
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
|
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
|
||||||
const BUY_SOURCES = ['Eth2Dai', '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 EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
|
||||||
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
|
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
|
||||||
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
|
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
|
||||||
@@ -45,14 +49,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
env.txDefaults,
|
env.txDefaults,
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
allSources = _.zipObject(
|
|
||||||
['Uniswap', 'Eth2Dai', 'Kyber'],
|
|
||||||
[
|
|
||||||
await testContract.uniswap().callAsync(),
|
|
||||||
await testContract.eth2Dai().callAsync(),
|
|
||||||
await testContract.kyber().callAsync(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function getPackedHash(...args: string[]): string {
|
function getPackedHash(...args: string[]): string {
|
||||||
@@ -195,7 +191,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
|
|
||||||
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
||||||
const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
|
const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
|
||||||
const orderStatus = new BigNumber(hash).mod(255).toNumber();
|
const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
|
||||||
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
|
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
|
||||||
if (orderStatus !== 3 || !isValidSignature) {
|
if (orderStatus !== 3 || !isValidSignature) {
|
||||||
return constants.ZERO_AMOUNT;
|
return constants.ZERO_AMOUNT;
|
||||||
@@ -208,7 +204,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
return order.makerAssetAmount
|
return order.makerAssetAmount
|
||||||
.times(takerAmount)
|
.times(takerAmount)
|
||||||
.div(order.takerAssetAmount)
|
.div(order.takerAssetAmount)
|
||||||
.integerValue(BigNumber.ROUND_DOWN);
|
.integerValue(BigNumber.ROUND_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getERC20AssetData(tokenAddress: string): string {
|
function getERC20AssetData(tokenAddress: string): string {
|
||||||
@@ -255,7 +251,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
describe('getOrderFillableTakerAssetAmounts()', () => {
|
describe('getOrderFillableTakerAssetAmounts()', () => {
|
||||||
it('returns the expected amount for each order', async () => {
|
it('returns the expected amount for each order', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||||
expect(actual).to.deep.eq(expected);
|
expect(actual).to.deep.eq(expected);
|
||||||
@@ -269,7 +265,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('returns zero for an order with zero maker asset amount', async () => {
|
it('returns zero for an order with zero maker asset amount', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||||
});
|
});
|
||||||
@@ -277,7 +273,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('returns zero for an order with zero taker asset amount', async () => {
|
it('returns zero for an order with zero taker asset amount', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||||
});
|
});
|
||||||
@@ -293,7 +289,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
describe('getOrderFillableMakerAssetAmounts()', () => {
|
describe('getOrderFillableMakerAssetAmounts()', () => {
|
||||||
it('returns the expected amount for each order', async () => {
|
it('returns the expected amount for each order', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||||
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
|
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
|
||||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||||
expect(actual).to.deep.eq(expected);
|
expect(actual).to.deep.eq(expected);
|
||||||
@@ -307,7 +303,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('returns zero for an order with zero maker asset amount', async () => {
|
it('returns zero for an order with zero maker asset amount', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||||
});
|
});
|
||||||
@@ -315,7 +311,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('returns zero for an order with zero taker asset amount', async () => {
|
it('returns zero for an order with zero taker asset amount', async () => {
|
||||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||||
});
|
});
|
||||||
@@ -330,7 +326,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
|
|
||||||
describe('queryOrdersAndSampleSells()', () => {
|
describe('queryOrdersAndSampleSells()', () => {
|
||||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||||
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
|
const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||||
@@ -340,7 +336,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
|
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
|
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
|
||||||
const [orderInfos] = await testContract
|
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();
|
.callAsync();
|
||||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||||
});
|
});
|
||||||
@@ -349,14 +345,14 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||||
const [, quotes] = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if no orders are passed in', async () => {
|
it('throws if no orders are passed in', async () => {
|
||||||
const tx = testContract
|
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();
|
.callAsync();
|
||||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||||
});
|
});
|
||||||
@@ -366,7 +362,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
.queryOrdersAndSampleSells(
|
.queryOrdersAndSampleSells(
|
||||||
ORDERS,
|
ORDERS,
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||||
getSampleAmounts(TAKER_TOKEN),
|
getSampleAmounts(TAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -381,7 +377,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
SELL_SOURCES.map(n => allSources[n]),
|
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(TAKER_TOKEN),
|
getSampleAmounts(TAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -396,7 +392,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
SELL_SOURCES.map(n => allSources[n]),
|
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(TAKER_TOKEN),
|
getSampleAmounts(TAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -411,7 +407,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
makerAssetData: INVALID_ASSET_DATA,
|
makerAssetData: INVALID_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
SELL_SOURCES.map(n => allSources[n]),
|
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(TAKER_TOKEN),
|
getSampleAmounts(TAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -426,7 +422,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
takerAssetData: INVALID_ASSET_DATA,
|
takerAssetData: INVALID_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
SELL_SOURCES.map(n => allSources[n]),
|
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(TAKER_TOKEN),
|
getSampleAmounts(TAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -436,7 +432,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
|
|
||||||
describe('queryOrdersAndSampleBuys()', () => {
|
describe('queryOrdersAndSampleBuys()', () => {
|
||||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||||
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
|
const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||||
@@ -446,7 +442,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
|
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
|
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
|
||||||
const [orderInfos] = await testContract
|
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();
|
.callAsync();
|
||||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||||
});
|
});
|
||||||
@@ -455,14 +451,14 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||||
const [, quotes] = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws if no orders are passed in', async () => {
|
it('throws if no orders are passed in', async () => {
|
||||||
const tx = testContract
|
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();
|
.callAsync();
|
||||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||||
});
|
});
|
||||||
@@ -472,7 +468,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
.queryOrdersAndSampleBuys(
|
.queryOrdersAndSampleBuys(
|
||||||
ORDERS,
|
ORDERS,
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||||
getSampleAmounts(MAKER_TOKEN),
|
getSampleAmounts(MAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -485,7 +481,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
.queryOrdersAndSampleBuys(
|
.queryOrdersAndSampleBuys(
|
||||||
ORDERS,
|
ORDERS,
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
sources.map(n => allSources[n]),
|
sources.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(MAKER_TOKEN),
|
getSampleAmounts(MAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -500,7 +496,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
BUY_SOURCES.map(n => allSources[n]),
|
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(MAKER_TOKEN),
|
getSampleAmounts(MAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -515,7 +511,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
BUY_SOURCES.map(n => allSources[n]),
|
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(MAKER_TOKEN),
|
getSampleAmounts(MAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -530,7 +526,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
makerAssetData: INVALID_ASSET_DATA,
|
makerAssetData: INVALID_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
BUY_SOURCES.map(n => allSources[n]),
|
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(MAKER_TOKEN),
|
getSampleAmounts(MAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -545,7 +541,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
takerAssetData: INVALID_ASSET_DATA,
|
takerAssetData: INVALID_ASSET_DATA,
|
||||||
})),
|
})),
|
||||||
SIGNATURES,
|
SIGNATURES,
|
||||||
BUY_SOURCES.map(n => allSources[n]),
|
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||||
getSampleAmounts(MAKER_TOKEN),
|
getSampleAmounts(MAKER_TOKEN),
|
||||||
)
|
)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
@@ -561,7 +557,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('returns empty quotes with no sample amounts', async () => {
|
it('returns empty quotes with no sample amounts', async () => {
|
||||||
const emptyQuotes = _.times(SELL_SOURCES.length, () => []);
|
const emptyQuotes = _.times(SELL_SOURCES.length, () => []);
|
||||||
const quotes = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(emptyQuotes);
|
expect(quotes).to.deep.eq(emptyQuotes);
|
||||||
});
|
});
|
||||||
@@ -570,7 +566,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||||
const quotes = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@@ -580,7 +576,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sources = _.sampleSize(SELL_SOURCES, 1);
|
const sources = _.sampleSize(SELL_SOURCES, 1);
|
||||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||||
const quotes = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@@ -588,7 +584,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('throws with an unsupported source', async () => {
|
it('throws with an unsupported source', async () => {
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.sampleSells(
|
.sampleSells(
|
||||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||||
TAKER_TOKEN,
|
TAKER_TOKEN,
|
||||||
MAKER_TOKEN,
|
MAKER_TOKEN,
|
||||||
getSampleAmounts(TAKER_TOKEN),
|
getSampleAmounts(TAKER_TOKEN),
|
||||||
@@ -606,7 +602,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('returns empty quotes with no sample amounts', async () => {
|
it('returns empty quotes with no sample amounts', async () => {
|
||||||
const emptyQuotes = _.times(BUY_SOURCES.length, () => []);
|
const emptyQuotes = _.times(BUY_SOURCES.length, () => []);
|
||||||
const quotes = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(emptyQuotes);
|
expect(quotes).to.deep.eq(emptyQuotes);
|
||||||
});
|
});
|
||||||
@@ -615,7 +611,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||||
const quotes = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@@ -625,7 +621,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
const sources = _.sampleSize(BUY_SOURCES, 1);
|
const sources = _.sampleSize(BUY_SOURCES, 1);
|
||||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||||
const quotes = await testContract
|
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();
|
.callAsync();
|
||||||
expect(quotes).to.deep.eq(expectedQuotes);
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
});
|
});
|
||||||
@@ -633,7 +629,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
|||||||
it('throws with an unsupported source', async () => {
|
it('throws with an unsupported source', async () => {
|
||||||
const tx = testContract
|
const tx = testContract
|
||||||
.sampleBuys(
|
.sampleBuys(
|
||||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||||
TAKER_TOKEN,
|
TAKER_TOKEN,
|
||||||
MAKER_TOKEN,
|
MAKER_TOKEN,
|
||||||
getSampleAmounts(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 () => {
|
it('throws if kyber is passed in as a source', async () => {
|
||||||
const sources = [...BUY_SOURCES, 'Kyber'];
|
const sources = [...BUY_SOURCES, 'Kyber'];
|
||||||
const tx = testContract
|
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();
|
.callAsync();
|
||||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||||
});
|
});
|
||||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
|||||||
solc: {
|
solc: {
|
||||||
version: '0.5.9',
|
version: '0.5.9',
|
||||||
settings: {
|
settings: {
|
||||||
evmVersion: 'constantinople',
|
evmVersion: 'istanbul',
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 1000000,
|
runs: 1000000,
|
||||||
|
@@ -1,4 +1,31 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1578272714,
|
"timestamp": 1578272714,
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v3.0.3 - _January 6, 2020_
|
## v3.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// solhint-disable
|
// solhint-disable
|
||||||
pragma solidity ^0.4.18;
|
pragma solidity ^0.5.9;
|
||||||
|
|
||||||
|
|
||||||
contract WETH9 {
|
contract WETH9 {
|
||||||
@@ -30,27 +30,27 @@ contract WETH9 {
|
|||||||
mapping (address => uint) public balanceOf;
|
mapping (address => uint) public balanceOf;
|
||||||
mapping (address => mapping (address => uint)) public allowance;
|
mapping (address => mapping (address => uint)) public allowance;
|
||||||
|
|
||||||
function() public payable {
|
function() external payable {
|
||||||
deposit();
|
deposit();
|
||||||
}
|
}
|
||||||
function deposit() public payable {
|
function deposit() public payable {
|
||||||
balanceOf[msg.sender] += msg.value;
|
balanceOf[msg.sender] += msg.value;
|
||||||
Deposit(msg.sender, msg.value);
|
emit Deposit(msg.sender, msg.value);
|
||||||
}
|
}
|
||||||
function withdraw(uint wad) public {
|
function withdraw(uint wad) public {
|
||||||
require(balanceOf[msg.sender] >= wad);
|
require(balanceOf[msg.sender] >= wad);
|
||||||
balanceOf[msg.sender] -= wad;
|
balanceOf[msg.sender] -= wad;
|
||||||
msg.sender.transfer(wad);
|
msg.sender.transfer(wad);
|
||||||
Withdrawal(msg.sender, wad);
|
emit Withdrawal(msg.sender, wad);
|
||||||
}
|
}
|
||||||
|
|
||||||
function totalSupply() public view returns (uint) {
|
function totalSupply() public view returns (uint) {
|
||||||
return this.balance;
|
return address(this).balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
function approve(address guy, uint wad) public returns (bool) {
|
function approve(address guy, uint wad) public returns (bool) {
|
||||||
allowance[msg.sender][guy] = wad;
|
allowance[msg.sender][guy] = wad;
|
||||||
Approval(msg.sender, guy, wad);
|
emit Approval(msg.sender, guy, wad);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ contract WETH9 {
|
|||||||
balanceOf[src] -= wad;
|
balanceOf[src] -= wad;
|
||||||
balanceOf[dst] += wad;
|
balanceOf[dst] += wad;
|
||||||
|
|
||||||
Transfer(src, dst, wad);
|
emit Transfer(src, dst, wad);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc20",
|
"name": "@0x/contracts-erc20",
|
||||||
"version": "3.0.3",
|
"version": "3.0.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -51,18 +51,18 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
"@0x/typescript-typings": "^5.0.1",
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3"
|
"@0x/base-contract": "^6.1.2"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@@ -1,4 +1,31 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1578272714,
|
"timestamp": 1578272714,
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v3.0.3 - _January 6, 2020_
|
## v3.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-erc721",
|
"name": "@0x/contracts-erc721",
|
||||||
"version": "3.0.3",
|
"version": "3.0.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -52,18 +52,18 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
"@0x/typescript-typings": "^5.0.1",
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3"
|
"@0x/base-contract": "^6.1.2"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
|||||||
solc: {
|
solc: {
|
||||||
version: '0.5.9',
|
version: '0.5.9',
|
||||||
settings: {
|
settings: {
|
||||||
evmVersion: 'constantinople',
|
evmVersion: 'istanbul',
|
||||||
optimizer: {
|
optimizer: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
runs: 1000000,
|
runs: 1000000,
|
||||||
|
@@ -1,4 +1,32 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Dependencies updated"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"timestamp": 1578272714,
|
"timestamp": 1578272714,
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
|
@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
|
|||||||
|
|
||||||
CHANGELOG
|
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
|
||||||
|
|
||||||
## v4.0.3 - _January 6, 2020_
|
## v4.0.3 - _January 6, 2020_
|
||||||
|
|
||||||
* Dependencies updated
|
* Dependencies updated
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"useDockerisedSolc": false,
|
"useDockerisedSolc": false,
|
||||||
"isOfflineMode": false,
|
"isOfflineMode": false,
|
||||||
"compilerSettings": {
|
"compilerSettings": {
|
||||||
"evmVersion": "constantinople",
|
"evmVersion": "istanbul",
|
||||||
"optimizer": {
|
"optimizer": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"runs": 1000000,
|
"runs": 1000000,
|
||||||
|
@@ -19,27 +19,191 @@
|
|||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./MixinForwarderCore.sol";
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||||
import "./libs/LibConstants.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
|
contract Forwarder is
|
||||||
LibConstants,
|
IForwarder,
|
||||||
MixinForwarderCore
|
Ownable,
|
||||||
|
MixinWethUtils,
|
||||||
|
MixinExchangeWrapper,
|
||||||
|
MixinReceiver
|
||||||
{
|
{
|
||||||
|
using LibBytes for bytes;
|
||||||
|
using LibAssetDataTransfer for bytes;
|
||||||
|
using LibSafeMath for uint256;
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
address _exchange,
|
address _exchange,
|
||||||
|
address _exchangeV2,
|
||||||
address _weth
|
address _weth
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
Ownable()
|
Ownable()
|
||||||
LibConstants(
|
MixinWethUtils(
|
||||||
_exchange,
|
_exchange,
|
||||||
_weth
|
_weth
|
||||||
)
|
)
|
||||||
MixinForwarderCore()
|
MixinExchangeWrapper(
|
||||||
{}
|
_exchange,
|
||||||
|
_exchangeV2
|
||||||
|
)
|
||||||
|
{} // solhint-disable-line no-empty-blocks
|
||||||
|
|
||||||
|
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
|
||||||
|
/// that were accidentally sent to this contract.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of the asset to withdraw.
|
||||||
|
function withdrawAsset(
|
||||||
|
bytes calldata assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external
|
||||||
|
onlyOwner
|
||||||
|
{
|
||||||
|
assetData.transferOut(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||||
|
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
|
||||||
|
/// Forwarder contract to the fee recipient.
|
||||||
|
/// This method needs to be called before forwarding orders of a maker asset that hasn't
|
||||||
|
/// previously been approved.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
function approveMakerAssetProxy(bytes calldata assetData)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
bytes4 proxyId = assetData.readBytes4(0);
|
||||||
|
bytes4 erc20ProxyId = IAssetData(address(0)).ERC20Token.selector;
|
||||||
|
|
||||||
|
// For now we only care about ERC20, since percentage fees on ERC721 tokens are invalid.
|
||||||
|
if (proxyId == erc20ProxyId) {
|
||||||
|
address proxyAddress = EXCHANGE.getAssetProxy(erc20ProxyId);
|
||||||
|
if (proxyAddress == address(0)) {
|
||||||
|
LibRichErrors.rrevert(LibForwarderRichErrors.UnregisteredAssetProxyError());
|
||||||
|
}
|
||||||
|
address token = assetData.readAddress(16);
|
||||||
|
LibERC20Token.approve(token, proxyAddress, MAX_UINT256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
||||||
|
/// as possible, accounting for order and forwarder fees.
|
||||||
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||||
|
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||||
|
function marketSellOrdersWithEth(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
bytes[] memory signatures,
|
||||||
|
uint256[] memory ethFeeAmounts,
|
||||||
|
address payable[] memory feeRecipients
|
||||||
|
)
|
||||||
|
public
|
||||||
|
payable
|
||||||
|
returns (
|
||||||
|
uint256 wethSpentAmount,
|
||||||
|
uint256 makerAssetAcquiredAmount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||||
|
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||||
|
ethFeeAmounts,
|
||||||
|
feeRecipients
|
||||||
|
);
|
||||||
|
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
|
||||||
|
// and pays WETH order fees.
|
||||||
|
(
|
||||||
|
wethSpentAmount,
|
||||||
|
makerAssetAcquiredAmount
|
||||||
|
) = _marketSellNoThrow(
|
||||||
|
orders,
|
||||||
|
wethRemaining,
|
||||||
|
signatures
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that no extra WETH owned by this contract has been spent.
|
||||||
|
if (wethSpentAmount > wethRemaining) {
|
||||||
|
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||||
|
wethSpentAmount,
|
||||||
|
msg.value
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate amount of WETH that hasn't been spent.
|
||||||
|
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
|
||||||
|
|
||||||
|
// Refund remaining ETH to msg.sender.
|
||||||
|
_unwrapAndTransferEth(wethRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||||
|
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||||
|
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||||
|
/// Any ETH not spent will be refunded to sender.
|
||||||
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
|
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||||
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||||
|
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||||
|
function marketBuyOrdersWithEth(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256 makerAssetBuyAmount,
|
||||||
|
bytes[] memory signatures,
|
||||||
|
uint256[] memory ethFeeAmounts,
|
||||||
|
address payable[] memory feeRecipients
|
||||||
|
)
|
||||||
|
public
|
||||||
|
payable
|
||||||
|
returns (
|
||||||
|
uint256 wethSpentAmount,
|
||||||
|
uint256 makerAssetAcquiredAmount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Pay ETH affiliate fees to all feeRecipient addresses
|
||||||
|
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
|
||||||
|
ethFeeAmounts,
|
||||||
|
feeRecipients
|
||||||
|
);
|
||||||
|
|
||||||
|
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
|
||||||
|
(
|
||||||
|
wethSpentAmount,
|
||||||
|
makerAssetAcquiredAmount
|
||||||
|
) = _marketBuyFillOrKill(
|
||||||
|
orders,
|
||||||
|
makerAssetBuyAmount,
|
||||||
|
signatures
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that no extra WETH owned by this contract has been spent.
|
||||||
|
if (wethSpentAmount > wethRemaining) {
|
||||||
|
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
|
||||||
|
wethSpentAmount,
|
||||||
|
msg.value
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate amount of WETH that hasn't been spent.
|
||||||
|
wethRemaining = wethRemaining.safeSub(wethSpentAmount);
|
||||||
|
|
||||||
|
// Refund remaining ETH to msg.sender.
|
||||||
|
_unwrapAndTransferEth(wethRemaining);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,140 +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-erc721/contracts/src/interfaces/IERC721Token.sol";
|
|
||||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
|
||||||
import "./libs/LibConstants.sol";
|
|
||||||
import "./libs/LibForwarderRichErrors.sol";
|
|
||||||
import "./interfaces/IAssets.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract MixinAssets is
|
|
||||||
Ownable,
|
|
||||||
LibConstants,
|
|
||||||
IAssets
|
|
||||||
{
|
|
||||||
using LibBytes 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
|
|
||||||
{
|
|
||||||
_transferAssetToSender(assetData, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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 == IAssetData(address(0)).ERC20Token.selector ||
|
|
||||||
proxyId == IAssetData(address(0)).ERC20Bridge.selector
|
|
||||||
) {
|
|
||||||
_transferERC20Token(assetData, amount);
|
|
||||||
} else if (proxyId == IAssetData(address(0)).ERC721Token.selector) {
|
|
||||||
_transferERC721Token(assetData, amount);
|
|
||||||
} else {
|
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
|
|
||||||
proxyId
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Decodes ERC20 or ERC20Bridge 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
|
|
||||||
{
|
|
||||||
address token = assetData.readAddress(16);
|
|
||||||
// Transfer tokens.
|
|
||||||
LibERC20Token.transfer(token, msg.sender, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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
|
|
||||||
{
|
|
||||||
if (amount != 1) {
|
|
||||||
LibRichErrors.rrevert(LibForwarderRichErrors.Erc721AmountMustEqualOneError(
|
|
||||||
amount
|
|
||||||
));
|
|
||||||
}
|
|
||||||
// Decode asset data.
|
|
||||||
address token = assetData.readAddress(16);
|
|
||||||
uint256 tokenId = assetData.readUint256(36);
|
|
||||||
|
|
||||||
// Perform transfer.
|
|
||||||
IERC721Token(token).transferFrom(
|
|
||||||
address(this),
|
|
||||||
msg.sender,
|
|
||||||
tokenId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -19,27 +19,60 @@
|
|||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.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/LibOrder.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||||
import "./libs/LibConstants.sol";
|
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||||
import "./libs/LibForwarderRichErrors.sol";
|
import "./libs/LibForwarderRichErrors.sol";
|
||||||
import "./MixinAssets.sol";
|
import "./interfaces/IExchangeV2.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinExchangeWrapper is
|
contract MixinExchangeWrapper {
|
||||||
LibConstants,
|
|
||||||
MixinAssets
|
// 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 LibBytes for bytes;
|
||||||
|
using LibAssetDataTransfer for bytes;
|
||||||
using LibSafeMath for uint256;
|
using LibSafeMath for uint256;
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
address _exchange,
|
||||||
|
address _exchangeV2
|
||||||
|
)
|
||||||
|
public
|
||||||
|
{
|
||||||
|
EXCHANGE = IExchange(_exchange);
|
||||||
|
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Fills the input order.
|
/// @dev Fills the input order.
|
||||||
/// Returns false if the transaction would otherwise revert.
|
/// Returns false if the transaction would otherwise revert.
|
||||||
/// @param order Order struct containing order specifications.
|
/// @param order Order struct containing order specifications.
|
||||||
@@ -54,23 +87,19 @@ contract MixinExchangeWrapper is
|
|||||||
internal
|
internal
|
||||||
returns (LibFillResults.FillResults memory fillResults)
|
returns (LibFillResults.FillResults memory fillResults)
|
||||||
{
|
{
|
||||||
// ABI encode calldata for `fillOrder`
|
if (_isV2Order(order)) {
|
||||||
bytes memory fillOrderCalldata = abi.encodeWithSelector(
|
return _fillV2OrderNoThrow(
|
||||||
IExchange(address(0)).fillOrder.selector,
|
order,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _fillV3OrderNoThrow(
|
||||||
order,
|
order,
|
||||||
takerAssetFillAmount,
|
takerAssetFillAmount,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
|
||||||
address exchange = address(EXCHANGE);
|
|
||||||
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
|
||||||
if (didSucceed) {
|
|
||||||
assert(returnData.length == 160);
|
|
||||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fillResults values will be 0 by default if call was unsuccessful
|
|
||||||
return fillResults;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Executes a single call of fillOrder according to the wethSellAmount and
|
/// @dev Executes a single call of fillOrder according to the wethSellAmount and
|
||||||
@@ -162,8 +191,7 @@ contract MixinExchangeWrapper is
|
|||||||
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
|
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
|
||||||
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
|
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
|
||||||
|
|
||||||
uint256 ordersLength = orders.length;
|
for (uint256 i = 0; i != orders.length; i++) {
|
||||||
for (uint256 i = 0; i != ordersLength; i++) {
|
|
||||||
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
||||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -172,7 +200,7 @@ contract MixinExchangeWrapper is
|
|||||||
// The remaining amount of WETH to sell
|
// The remaining amount of WETH to sell
|
||||||
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||||
.safeSub(totalWethSpentAmount)
|
.safeSub(totalWethSpentAmount)
|
||||||
.safeSub(protocolFee);
|
.safeSub(_isV2Order(orders[i]) ? 0 : protocolFee);
|
||||||
|
|
||||||
// If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance.
|
// If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance.
|
||||||
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
|
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
|
||||||
@@ -201,7 +229,7 @@ contract MixinExchangeWrapper is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
|
||||||
|
|
||||||
totalWethSpentAmount = totalWethSpentAmount
|
totalWethSpentAmount = totalWethSpentAmount
|
||||||
.safeAdd(wethSpentAmount);
|
.safeAdd(wethSpentAmount);
|
||||||
@@ -349,7 +377,7 @@ contract MixinExchangeWrapper is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
|
||||||
|
|
||||||
totalWethSpentAmount = totalWethSpentAmount
|
totalWethSpentAmount = totalWethSpentAmount
|
||||||
.safeAdd(wethSpentAmount);
|
.safeAdd(wethSpentAmount);
|
||||||
@@ -370,6 +398,91 @@ contract MixinExchangeWrapper is
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Fills the input ExchangeV2 order. The `makerFeeAssetData` must be
|
||||||
|
// equal to EXCHANGE_V2_ORDER_ID (0x770501f8).
|
||||||
|
/// Returns false if the transaction would otherwise revert.
|
||||||
|
/// @param order Order struct containing order specifications.
|
||||||
|
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||||
|
/// @param signature Proof that order has been created by maker.
|
||||||
|
/// @return Amounts filled and fees paid by maker and taker.
|
||||||
|
function _fillV2OrderNoThrow(
|
||||||
|
LibOrder.Order memory order,
|
||||||
|
uint256 takerAssetFillAmount,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
returns (LibFillResults.FillResults memory fillResults)
|
||||||
|
{
|
||||||
|
// Strip v3 specific fields from order
|
||||||
|
IExchangeV2.Order memory v2Order = IExchangeV2.Order({
|
||||||
|
makerAddress: order.makerAddress,
|
||||||
|
takerAddress: order.takerAddress,
|
||||||
|
feeRecipientAddress: order.feeRecipientAddress,
|
||||||
|
senderAddress: order.senderAddress,
|
||||||
|
makerAssetAmount: order.makerAssetAmount,
|
||||||
|
takerAssetAmount: order.takerAssetAmount,
|
||||||
|
// NOTE: We assume fees are 0 for all v2 orders. Orders with non-zero fees will fail to be filled.
|
||||||
|
makerFee: 0,
|
||||||
|
takerFee: 0,
|
||||||
|
expirationTimeSeconds: order.expirationTimeSeconds,
|
||||||
|
salt: order.salt,
|
||||||
|
makerAssetData: order.makerAssetData,
|
||||||
|
takerAssetData: order.takerAssetData
|
||||||
|
});
|
||||||
|
|
||||||
|
// ABI encode calldata for `fillOrder`
|
||||||
|
bytes memory fillOrderCalldata = abi.encodeWithSelector(
|
||||||
|
IExchangeV2(address(0)).fillOrder.selector,
|
||||||
|
v2Order,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
|
||||||
|
address exchange = address(EXCHANGE_V2);
|
||||||
|
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||||
|
if (didSucceed) {
|
||||||
|
assert(returnData.length == 128);
|
||||||
|
// NOTE: makerFeePaid, takerFeePaid, and protocolFeePaid will always be 0 for v2 orders
|
||||||
|
(fillResults.makerAssetFilledAmount, fillResults.takerAssetFilledAmount) = abi.decode(returnData, (uint256, uint256));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillResults values will be 0 by default if call was unsuccessful
|
||||||
|
return fillResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Fills the input ExchangeV3 order.
|
||||||
|
/// Returns false if the transaction would otherwise revert.
|
||||||
|
/// @param order Order struct containing order specifications.
|
||||||
|
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||||
|
/// @param signature Proof that order has been created by maker.
|
||||||
|
/// @return Amounts filled and fees paid by maker and taker.
|
||||||
|
function _fillV3OrderNoThrow(
|
||||||
|
LibOrder.Order memory order,
|
||||||
|
uint256 takerAssetFillAmount,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
internal
|
||||||
|
returns (LibFillResults.FillResults memory fillResults)
|
||||||
|
{
|
||||||
|
// ABI encode calldata for `fillOrder`
|
||||||
|
bytes memory fillOrderCalldata = abi.encodeWithSelector(
|
||||||
|
IExchange(address(0)).fillOrder.selector,
|
||||||
|
order,
|
||||||
|
takerAssetFillAmount,
|
||||||
|
signature
|
||||||
|
);
|
||||||
|
|
||||||
|
address exchange = address(EXCHANGE);
|
||||||
|
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||||
|
if (didSucceed) {
|
||||||
|
assert(returnData.length == 160);
|
||||||
|
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillResults values will be 0 by default if call was unsuccessful
|
||||||
|
return fillResults;
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev Checks whether one asset is effectively equal to another asset.
|
/// @dev Checks whether one asset is effectively equal to another asset.
|
||||||
/// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if
|
/// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if
|
||||||
/// one is the ERC20Bridge equivalent of the other.
|
/// one is the ERC20Bridge equivalent of the other.
|
||||||
@@ -398,7 +511,18 @@ contract MixinExchangeWrapper is
|
|||||||
address token2 = assetData2.readAddress(16);
|
address token2 = assetData2.readAddress(16);
|
||||||
return (token1 == token2);
|
return (token1 == token2);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return assetData1.equals(assetData2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @dev Checks whether an order is a v2 order.
|
||||||
|
/// @param order Order struct containing order specifications.
|
||||||
|
/// @return True if the order's `makerFeeAssetData` is set to the v2 order id.
|
||||||
|
function _isV2Order(LibOrder.Order memory order)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (bool)
|
||||||
|
{
|
||||||
|
return order.makerFeeAssetData.length > 3 && order.makerFeeAssetData.readBytes4(0) == EXCHANGE_V2_ORDER_ID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,148 +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);
|
|
||||||
}
|
|
||||||
}
|
|
76
contracts/exchange-forwarder/contracts/src/MixinReceiver.sol
Normal file
76
contracts/exchange-forwarder/contracts/src/MixinReceiver.sol
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 MixinReceiver {
|
||||||
|
|
||||||
|
bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61;
|
||||||
|
bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81;
|
||||||
|
|
||||||
|
/// @notice Handle the receipt of a single ERC1155 token type
|
||||||
|
/// @dev The smart contract calls this function on the recipient
|
||||||
|
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||||
|
/// transfer. Return of other than the magic value MUST result in the
|
||||||
|
///transaction being reverted
|
||||||
|
/// Note: the contract address is always the message sender
|
||||||
|
/// @param operator The address which called `safeTransferFrom` function
|
||||||
|
/// @param from The address which previously owned the token
|
||||||
|
/// @param id An array containing the ids of the token being transferred
|
||||||
|
/// @param value An array containing the amount of tokens being transferred
|
||||||
|
/// @param data Additional data with no specified format
|
||||||
|
/// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
|
||||||
|
function onERC1155Received(
|
||||||
|
address operator,
|
||||||
|
address from,
|
||||||
|
uint256 id,
|
||||||
|
uint256 value,
|
||||||
|
bytes calldata data
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (bytes4)
|
||||||
|
{
|
||||||
|
return ERC1155_RECEIVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Handle the receipt of multiple ERC1155 token types
|
||||||
|
/// @dev The smart contract calls this function on the recipient
|
||||||
|
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||||
|
/// transfer. Return of other than the magic value MUST result in the
|
||||||
|
/// transaction being reverted
|
||||||
|
/// Note: the contract address is always the message sender
|
||||||
|
/// @param operator The address which called `safeTransferFrom` function
|
||||||
|
/// @param from The address which previously owned the token
|
||||||
|
/// @param ids An array containing ids of each token being transferred
|
||||||
|
/// @param values An array containing amounts of each token being transferred
|
||||||
|
/// @param data Additional data with no specified format
|
||||||
|
/// @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
|
||||||
|
function onERC1155BatchReceived(
|
||||||
|
address operator,
|
||||||
|
address from,
|
||||||
|
uint256[] calldata ids,
|
||||||
|
uint256[] calldata values,
|
||||||
|
bytes calldata data
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (bytes4)
|
||||||
|
{
|
||||||
|
return ERC1155_BATCH_RECEIVED;
|
||||||
|
}
|
||||||
|
}
|
@@ -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;
|
|
||||||
}
|
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2019 ZeroEx Intl.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
|
||||||
|
contract IExchangeV2 {
|
||||||
|
|
||||||
|
// solhint-disable max-line-length
|
||||||
|
struct Order {
|
||||||
|
address makerAddress; // Address that created the order.
|
||||||
|
address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
|
||||||
|
address feeRecipientAddress; // Address that will recieve fees when order is filled.
|
||||||
|
address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.
|
||||||
|
uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0.
|
||||||
|
uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0.
|
||||||
|
uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
|
||||||
|
uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
|
||||||
|
uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires.
|
||||||
|
uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash.
|
||||||
|
bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.
|
||||||
|
bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.
|
||||||
|
}
|
||||||
|
// solhint-enable max-line-length
|
||||||
|
|
||||||
|
struct FillResults {
|
||||||
|
uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled.
|
||||||
|
uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled.
|
||||||
|
uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s).
|
||||||
|
uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s).
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OrderInfo {
|
||||||
|
uint8 orderStatus; // Status that describes order's validity and fillability.
|
||||||
|
bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash).
|
||||||
|
uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @dev Fills the input order.
|
||||||
|
/// @param order Order struct containing order specifications.
|
||||||
|
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||||
|
/// @param signature Proof that order has been created by maker.
|
||||||
|
/// @return Amounts filled and fees paid by maker and taker.
|
||||||
|
function fillOrder(
|
||||||
|
Order memory order,
|
||||||
|
uint256 takerAssetFillAmount,
|
||||||
|
bytes memory signature
|
||||||
|
)
|
||||||
|
public
|
||||||
|
returns (FillResults memory fillResults);
|
||||||
|
|
||||||
|
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||||
|
/// @param order Order to gather information on.
|
||||||
|
/// @return OrderInfo Information about the order and its state.
|
||||||
|
/// See LibOrder.OrderInfo for a complete description.
|
||||||
|
function getOrderInfo(Order memory order)
|
||||||
|
public
|
||||||
|
returns (OrderInfo memory orderInfo);
|
||||||
|
}
|
@@ -19,12 +19,77 @@
|
|||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "./IForwarderCore.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||||
import "./IAssets.sol";
|
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||||
|
|
||||||
|
|
||||||
// solhint-disable no-empty-blocks
|
contract IForwarder {
|
||||||
contract IForwarder is
|
|
||||||
IForwarderCore,
|
/// @dev Withdraws assets from this contract. The contract requires a ZRX balance in order to
|
||||||
IAssets
|
/// function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be
|
||||||
{}
|
/// used to withdraw assets that were accidentally sent to this contract.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
/// @param amount Amount of ERC20 token to withdraw.
|
||||||
|
function withdrawAsset(
|
||||||
|
bytes calldata assetData,
|
||||||
|
uint256 amount
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
|
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||||
|
/// This is necessary because an order fee denominated in the maker asset (i.e. a percentage fee) is sent by the
|
||||||
|
/// Forwarder contract to the fee recipient.
|
||||||
|
/// This method needs to be called before forwarding orders of a maker asset that hasn't
|
||||||
|
/// previously been approved.
|
||||||
|
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||||
|
function approveMakerAssetProxy(
|
||||||
|
bytes calldata assetData
|
||||||
|
)
|
||||||
|
external;
|
||||||
|
|
||||||
|
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
||||||
|
/// as possible, accounting for order and forwarder fees.
|
||||||
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||||
|
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||||
|
function marketSellOrdersWithEth(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
bytes[] memory signatures,
|
||||||
|
uint256[] memory ethFeeAmounts,
|
||||||
|
address payable[] memory feeRecipients
|
||||||
|
)
|
||||||
|
public
|
||||||
|
payable
|
||||||
|
returns (
|
||||||
|
uint256 wethSpentAmount,
|
||||||
|
uint256 makerAssetAcquiredAmount
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
||||||
|
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
||||||
|
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
||||||
|
/// Any ETH not spent will be refunded to sender.
|
||||||
|
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
||||||
|
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
||||||
|
/// @param signatures Proofs that orders have been created by makers.
|
||||||
|
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
||||||
|
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
||||||
|
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
||||||
|
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
||||||
|
function marketBuyOrdersWithEth(
|
||||||
|
LibOrder.Order[] memory orders,
|
||||||
|
uint256 makerAssetBuyAmount,
|
||||||
|
bytes[] memory signatures,
|
||||||
|
uint256[] memory ethFeeAmounts,
|
||||||
|
address payable[] memory feeRecipients
|
||||||
|
)
|
||||||
|
public
|
||||||
|
payable
|
||||||
|
returns (
|
||||||
|
uint256 wethSpentAmount,
|
||||||
|
uint256 makerAssetAcquiredAmount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
Copyright 2019 ZeroEx Intl.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
|
||||||
pragma experimental ABIEncoderV2;
|
|
||||||
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
|
||||||
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract IForwarderCore {
|
|
||||||
|
|
||||||
/// @dev Purchases as much of orders' makerAssets as possible by selling as much of the ETH value sent
|
|
||||||
/// as possible, accounting for order and forwarder fees.
|
|
||||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
|
||||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
|
||||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
|
||||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
|
||||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
|
||||||
function marketSellOrdersWithEth(
|
|
||||||
LibOrder.Order[] memory orders,
|
|
||||||
bytes[] memory signatures,
|
|
||||||
uint256[] memory ethFeeAmounts,
|
|
||||||
address payable[] memory feeRecipients
|
|
||||||
)
|
|
||||||
public
|
|
||||||
payable
|
|
||||||
returns (
|
|
||||||
uint256 wethSpentAmount,
|
|
||||||
uint256 makerAssetAcquiredAmount
|
|
||||||
);
|
|
||||||
|
|
||||||
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
|
|
||||||
/// The Forwarder may *fill* more than makerAssetBuyAmount of the makerAsset so that it can
|
|
||||||
/// pay takerFees where takerFeeAssetData == makerAssetData (i.e. percentage fees).
|
|
||||||
/// Any ETH not spent will be refunded to sender.
|
|
||||||
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
|
|
||||||
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
|
|
||||||
/// @param signatures Proofs that orders have been created by makers.
|
|
||||||
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
|
|
||||||
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
|
|
||||||
/// @return wethSpentAmount Amount of WETH spent on the given set of orders.
|
|
||||||
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
|
|
||||||
function marketBuyOrdersWithEth(
|
|
||||||
LibOrder.Order[] memory orders,
|
|
||||||
uint256 makerAssetBuyAmount,
|
|
||||||
bytes[] memory signatures,
|
|
||||||
uint256[] memory ethFeeAmounts,
|
|
||||||
address payable[] memory feeRecipients
|
|
||||||
)
|
|
||||||
public
|
|
||||||
payable
|
|
||||||
returns (
|
|
||||||
uint256 wethSpentAmount,
|
|
||||||
uint256 makerAssetAcquiredAmount
|
|
||||||
);
|
|
||||||
}
|
|
@@ -1,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;
|
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
|
||||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
|
||||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
|
||||||
|
|
||||||
|
|
||||||
contract LibConstants {
|
|
||||||
|
|
||||||
using LibBytes for bytes;
|
|
||||||
|
|
||||||
uint256 constant internal MAX_UINT = 2**256 - 1;
|
|
||||||
|
|
||||||
// solhint-disable var-name-mixedcase
|
|
||||||
IExchange internal EXCHANGE;
|
|
||||||
IEtherToken internal ETHER_TOKEN;
|
|
||||||
// solhint-enable var-name-mixedcase
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
address _exchange,
|
|
||||||
address _weth
|
|
||||||
)
|
|
||||||
public
|
|
||||||
{
|
|
||||||
EXCHANGE = IExchange(_exchange);
|
|
||||||
ETHER_TOKEN = IEtherToken(_weth);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -25,10 +25,6 @@ library LibForwarderRichErrors {
|
|||||||
bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
|
bytes4 internal constant UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR =
|
||||||
0xf3b96b8d;
|
0xf3b96b8d;
|
||||||
|
|
||||||
// bytes4(keccak256("UnsupportedAssetProxyError(bytes4)"))
|
|
||||||
bytes4 internal constant UNSUPPORTED_ASSET_PROXY_ERROR_SELECTOR =
|
|
||||||
0x7996a271;
|
|
||||||
|
|
||||||
// bytes4(keccak256("CompleteBuyFailedError(uint256,uint256)"))
|
// bytes4(keccak256("CompleteBuyFailedError(uint256,uint256)"))
|
||||||
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
bytes4 internal constant COMPLETE_BUY_FAILED_ERROR_SELECTOR =
|
||||||
0x91353a0c;
|
0x91353a0c;
|
||||||
@@ -37,26 +33,10 @@ library LibForwarderRichErrors {
|
|||||||
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
|
||||||
0x31360af1;
|
0x31360af1;
|
||||||
|
|
||||||
// bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)"))
|
|
||||||
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
|
|
||||||
0xecf40fd9;
|
|
||||||
|
|
||||||
// bytes4(keccak256("OverspentWethError(uint256,uint256)"))
|
// bytes4(keccak256("OverspentWethError(uint256,uint256)"))
|
||||||
bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR =
|
bytes4 internal constant OVERSPENT_WETH_ERROR_SELECTOR =
|
||||||
0xcdcbed5d;
|
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
|
// solhint-disable func-name-mixedcase
|
||||||
function UnregisteredAssetProxyError()
|
function UnregisteredAssetProxyError()
|
||||||
internal
|
internal
|
||||||
@@ -66,19 +46,6 @@ library LibForwarderRichErrors {
|
|||||||
return abi.encodeWithSelector(UNREGISTERED_ASSET_PROXY_ERROR_SELECTOR);
|
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(
|
function CompleteBuyFailedError(
|
||||||
uint256 expectedAssetBuyAmount,
|
uint256 expectedAssetBuyAmount,
|
||||||
uint256 actualAssetBuyAmount
|
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(
|
function OverspentWethError(
|
||||||
uint256 wethSpent,
|
uint256 wethSpent,
|
||||||
uint256 msgValue
|
uint256 msgValue
|
||||||
@@ -136,45 +88,4 @@ library LibForwarderRichErrors {
|
|||||||
msgValue
|
msgValue
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DefaultFunctionWethContractOnlyError(
|
|
||||||
address senderAddress
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR,
|
|
||||||
senderAddress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Erc721AmountMustEqualOneError(
|
|
||||||
uint256 amount
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR,
|
|
||||||
amount
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function EthFeeLengthMismatchError(
|
|
||||||
uint256 ethFeesLength,
|
|
||||||
uint256 feeRecipientsLength
|
|
||||||
)
|
|
||||||
internal
|
|
||||||
pure
|
|
||||||
returns (bytes memory)
|
|
||||||
{
|
|
||||||
return abi.encodeWithSelector(
|
|
||||||
ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR,
|
|
||||||
ethFeesLength,
|
|
||||||
feeRecipientsLength
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -19,18 +19,21 @@
|
|||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
|
||||||
import "../src/MixinExchangeWrapper.sol";
|
import "../src/MixinExchangeWrapper.sol";
|
||||||
import "../src/libs/LibConstants.sol";
|
import "../src/MixinReceiver.sol";
|
||||||
|
|
||||||
|
|
||||||
contract TestForwarder is
|
contract TestForwarder is
|
||||||
LibConstants,
|
MixinExchangeWrapper,
|
||||||
MixinExchangeWrapper
|
MixinReceiver
|
||||||
{
|
{
|
||||||
|
using LibAssetDataTransfer for bytes;
|
||||||
|
|
||||||
// solhint-disable no-empty-blocks
|
// solhint-disable no-empty-blocks
|
||||||
constructor ()
|
constructor ()
|
||||||
public
|
public
|
||||||
LibConstants(
|
MixinExchangeWrapper(
|
||||||
address(0),
|
address(0),
|
||||||
address(0)
|
address(0)
|
||||||
)
|
)
|
||||||
@@ -49,15 +52,12 @@ contract TestForwarder is
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferAssetToSender(
|
function transferOut(
|
||||||
bytes memory assetData,
|
bytes memory assetData,
|
||||||
uint256 amount
|
uint256 amount
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
{
|
{
|
||||||
_transferAssetToSender(
|
assetData.transferOut(amount);
|
||||||
assetData,
|
|
||||||
amount
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0x/contracts-exchange-forwarder",
|
"name": "@0x/contracts-exchange-forwarder",
|
||||||
"version": "4.0.3",
|
"version": "4.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.12"
|
"node": ">=6.12"
|
||||||
},
|
},
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"publicInterfaceContracts": "Forwarder",
|
"publicInterfaceContracts": "Forwarder,IExchangeV2",
|
||||||
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|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."
|
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -52,24 +52,25 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0x/abi-gen": "^5.0.3",
|
"@0x/abi-gen": "^5.1.2",
|
||||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
"@0x/contracts-asset-proxy": "^3.1.3",
|
||||||
"@0x/contracts-dev-utils": "^1.0.3",
|
"@0x/contracts-dev-utils": "^1.0.6",
|
||||||
"@0x/contracts-erc20": "^3.0.3",
|
"@0x/contracts-erc1155": "^2.0.6",
|
||||||
"@0x/contracts-erc721": "^3.0.3",
|
"@0x/contracts-erc20": "^3.0.6",
|
||||||
"@0x/contracts-exchange": "^3.0.3",
|
"@0x/contracts-erc721": "^3.0.6",
|
||||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
"@0x/contracts-exchange": "^3.1.2",
|
||||||
"@0x/contracts-gen": "^2.0.3",
|
"@0x/contracts-exchange-libs": "^4.2.0",
|
||||||
"@0x/contracts-test-utils": "^5.1.0",
|
"@0x/contracts-gen": "^2.0.6",
|
||||||
"@0x/contracts-utils": "^4.0.3",
|
"@0x/contracts-test-utils": "^5.1.3",
|
||||||
"@0x/dev-utils": "^3.1.0",
|
"@0x/contracts-utils": "^4.2.1",
|
||||||
"@0x/order-utils": "^10.1.0",
|
"@0x/dev-utils": "^3.1.3",
|
||||||
"@0x/sol-compiler": "^4.0.3",
|
"@0x/order-utils": "^10.1.3",
|
||||||
|
"@0x/sol-compiler": "^4.0.6",
|
||||||
"@0x/ts-doc-gen": "^0.0.22",
|
"@0x/ts-doc-gen": "^0.0.22",
|
||||||
"@0x/tslint-config": "^4.0.0",
|
"@0x/tslint-config": "^4.0.0",
|
||||||
"@0x/types": "^3.1.1",
|
"@0x/types": "^3.1.1",
|
||||||
"@0x/utils": "^5.1.2",
|
"@0x/utils": "^5.3.0",
|
||||||
"@0x/web3-wrapper": "^7.0.3",
|
"@0x/web3-wrapper": "^7.0.5",
|
||||||
"@types/lodash": "4.14.104",
|
"@types/lodash": "4.14.104",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -89,7 +90,7 @@
|
|||||||
"typescript": "3.0.1"
|
"typescript": "3.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0x/base-contract": "^6.0.3",
|
"@0x/base-contract": "^6.1.2",
|
||||||
"@0x/typescript-typings": "^5.0.1",
|
"@0x/typescript-typings": "^5.0.1",
|
||||||
"ethereum-types": "^3.0.0"
|
"ethereum-types": "^3.0.0"
|
||||||
},
|
},
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user