feat: mStable + FQT Rollup (#2662)

* feat: mStable

* deploy and CHANGELOG

* `@0x/contracts-utils`: Add more testnet addresses.

* `@0x/contract-addresses`: Deply Mstable on testnets

* `@0x/contract-addresses`: Remove testnet deployments of mStable :-)

* move `erc20-bridge-sampler` into `asset-swapper`
remove `DevUtils` dependency from sampler contract.

* `@0x/asset-swapper`: Add ERC20BridgeSampler support for validating orders in maker fees denominated in non-maker assets.
`@0x/asset-swapper`: Add tests for `NativeOrderSampler`.

* `@0x/asset-swapper`: Return `0` sample if native order asset data is unsupported.

* `@0x/asset-swapper`: Fix failing test.

* feat: ExchangeProxy FQT fruit rollup (#2645)

* feat: Optimize Bridges in ExchangeProxy

* compile and most work

* work around to trust the delecall contract

* force allowances

* Update Kyber/Eth2Dai bridges

* Remove memory state where not required

* cleanup

* Combine Bridges into one adapter

* mixins

* refactor out ZeroExBridge

* move out interface

* comment out hacks

* update migrations

* remove simbot hacks

* AdapterAddresses and mStable

* Share constructor arg

* fix migration

* Remove whitespace

* `@0x/contracts-zero-ex`: BridgeAdapter -- revert if bridge address is 0.

* `@0x/contract-addresses`: Deploy FQT.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Lawrence Forman <lawrence@0xproject.com>

* update ganache contract addresses

* fix: asset-swapper empty batch call (#2669)

* update ganache contract addresses

* fix: asset-swapper prevent empty sampler batch call

* add sampler to migrations

* change migrations version

* Use contract-wrappers and artifacts

* remove extra data

* remove deps, set sampler to NULL_ADDRESS

* all the exports

* noop sell rate too

* update ganache contract addresses

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
This commit is contained in:
Jacob Evans 2020-08-20 08:18:44 +10:00 committed by GitHub
parent 458a014e6d
commit 7e8b56eef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
113 changed files with 2891 additions and 5319 deletions

View File

@ -40,10 +40,6 @@ lib
/contracts/erc20/test/generated-wrappers
/contracts/erc20/generated-artifacts
/contracts/erc20/test/generated-artifacts
/contracts/erc20-bridge-sampler/generated-wrappers
/contracts/erc20-bridge-sampler/test/generated-wrappers
/contracts/erc20-bridge-sampler/generated-artifacts
/contracts/erc20-bridge-sampler/test/generated-artifacts
/contracts/erc721/generated-wrappers
/contracts/erc721/test/generated-wrappers
/contracts/erc721/generated-artifacts
@ -85,6 +81,10 @@ lib
/packages/json-schemas/schemas
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
/packages/sra-spec/public/
/packages/asset-swapper/generated-wrappers
/packages/asset-swapper/test/generated-wrappers
/packages/asset-swapper/generated-artifacts
/packages/asset-swapper/test/generated-artifacts
package.json
scripts/postpublish_utils.js
packages/sol-coverage/test/fixtures/artifacts

View File

@ -9,6 +9,10 @@
{
"note": "Export DexForwarderBridgeContract",
"pr": 2656
},
{
"note": "Added `MStableBridge`",
"pr": 2662
}
]
},

View File

@ -0,0 +1,94 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IMStable.sol";
contract MStableBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
/// @dev Swaps specified tokens against the mStable mUSD contract
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded "from" token address.
/// @return success The magic bytes if successful.
// solhint-disable no-unused-vars
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
IMStable exchange = IMStable(_getMUsdAddress());
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
// Try to sell all of this contract's `fromTokenAddress` token balance.
uint256 boughtAmount = exchange.swap(
fromTokenAddress,
toTokenAddress,
fromTokenBalance,
to
);
emit ERC20BridgeTransfer(
fromTokenAddress,
toTokenAddress,
fromTokenBalance,
boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -0,0 +1,32 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
interface IMStable {
function swap(
address _input,
address _output,
uint256 _quantity,
address _recipient
)
external
returns (uint256 output);
}

View File

@ -38,7 +38,7 @@
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"abis": "./test/generated-artifacts/@(BalancerBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
"abis": "./test/generated-artifacts/@(BalancerBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {

View File

@ -28,6 +28,7 @@ import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
import * as IGasToken from '../generated-artifacts/IGasToken.json';
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
import * as IMStable from '../generated-artifacts/IMStable.json';
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.json';
@ -35,6 +36,7 @@ import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json';
import * as MStableBridge from '../generated-artifacts/MStableBridge.json';
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../generated-artifacts/Ownable.json';
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
@ -66,6 +68,7 @@ export const artifacts = {
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
MStableBridge: MStableBridge as ContractArtifact,
MixinGasToken: MixinGasToken as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
@ -82,6 +85,7 @@ export const artifacts = {
IEth2Dai: IEth2Dai as ContractArtifact,
IGasToken: IGasToken as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IMStable: IMStable as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,

View File

@ -26,10 +26,12 @@ export * from '../generated-wrappers/i_erc20_bridge';
export * from '../generated-wrappers/i_eth2_dai';
export * from '../generated-wrappers/i_gas_token';
export * from '../generated-wrappers/i_kyber_network_proxy';
export * from '../generated-wrappers/i_m_stable';
export * from '../generated-wrappers/i_uniswap_exchange';
export * from '../generated-wrappers/i_uniswap_exchange_factory';
export * from '../generated-wrappers/i_uniswap_v2_router01';
export * from '../generated-wrappers/kyber_bridge';
export * from '../generated-wrappers/m_stable_bridge';
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../generated-wrappers/mixin_authorizable';
export * from '../generated-wrappers/mixin_gas_token';

View File

@ -28,6 +28,7 @@ import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
import * as IMStable from '../test/generated-artifacts/IMStable.json';
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
@ -35,6 +36,7 @@ import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json';
import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json';
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
@ -66,6 +68,7 @@ export const artifacts = {
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
MStableBridge: MStableBridge as ContractArtifact,
MixinGasToken: MixinGasToken as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
@ -82,6 +85,7 @@ export const artifacts = {
IEth2Dai: IEth2Dai as ContractArtifact,
IGasToken: IGasToken as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IMStable: IMStable as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,

View File

@ -26,10 +26,12 @@ export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_gas_token';
export * from '../test/generated-wrappers/i_kyber_network_proxy';
export * from '../test/generated-wrappers/i_m_stable';
export * from '../test/generated-wrappers/i_uniswap_exchange';
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
export * from '../test/generated-wrappers/kyber_bridge';
export * from '../test/generated-wrappers/m_stable_bridge';
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/mixin_authorizable';
export * from '../test/generated-wrappers/mixin_gas_token';

View File

@ -26,10 +26,12 @@
"generated-artifacts/IEth2Dai.json",
"generated-artifacts/IGasToken.json",
"generated-artifacts/IKyberNetworkProxy.json",
"generated-artifacts/IMStable.json",
"generated-artifacts/IUniswapExchange.json",
"generated-artifacts/IUniswapExchangeFactory.json",
"generated-artifacts/IUniswapV2Router01.json",
"generated-artifacts/KyberBridge.json",
"generated-artifacts/MStableBridge.json",
"generated-artifacts/MixinAssetProxyDispatcher.json",
"generated-artifacts/MixinAuthorizable.json",
"generated-artifacts/MixinGasToken.json",
@ -70,10 +72,12 @@
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IGasToken.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/IMStable.json",
"test/generated-artifacts/IUniswapExchange.json",
"test/generated-artifacts/IUniswapExchangeFactory.json",
"test/generated-artifacts/IUniswapV2Router01.json",
"test/generated-artifacts/KyberBridge.json",
"test/generated-artifacts/MStableBridge.json",
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
"test/generated-artifacts/MixinAuthorizable.json",
"test/generated-artifacts/MixinGasToken.json",

View File

@ -1,10 +0,0 @@
# Blacklist all files
.*
*
# Whitelist lib
!lib/**/*
# Whitelist Solidity contracts
!contracts/src/**/*
# Blacklist tests in lib
/lib/test/*
# Package specific ignore

View File

@ -1,210 +0,0 @@
[
{
"version": "1.8.0",
"changes": [
{
"note": "Refactor and support more varied curves",
"pr": 2633
}
]
},
{
"version": "1.7.0",
"changes": [
{
"note": "Pass in `DevUtils` address to required functions",
"pr": 2629
},
{
"note": "Use new Kyber Katalyst functions",
"pr": 2629
}
],
"timestamp": 1594788383
},
{
"version": "1.6.0",
"changes": [
{
"note": "Pass in `DevUtils` address as a constructor parameter",
"pr": 2531
},
{
"note": "Sample `Curve` for buy amounts",
"pr": 2551
},
{
"note": "Added `sampleBuysFromKyberNetwork`",
"pr": 2551
},
{
"note": "Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve",
"pr": 2575
},
{
"note": "Add UniswapV2",
"pr": 2595
},
{
"note": "Sample from MultiBridge",
"pr": 2593
}
],
"timestamp": 1592969527
},
{
"timestamp": 1583220306,
"version": "1.5.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.5.0",
"changes": [
{
"note": "Add generic liquidity provider sampling",
"pr": 2487
},
{
"note": "Use liquidity provider registry in sampler",
"pr": 2499
}
],
"timestamp": 1582837861
},
{
"timestamp": 1582677073,
"version": "1.4.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582623685,
"version": "1.4.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.4.0",
"changes": [
{
"note": "Added Curve contract sampling",
"pr": 2483
}
],
"timestamp": 1581748629
},
{
"version": "1.3.0",
"changes": [
{
"note": "Catch reverts to `DevUtils` calls",
"pr": 2476
},
{
"note": "Remove wrapper functions and introduce `batchCall()`",
"pr": 2477
}
],
"timestamp": 1581204851
},
{
"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",
"changes": [
{
"note": "Add gas limits to external quote calls.",
"pr": 2405
}
],
"timestamp": 1578272714
},
{
"version": "1.0.2",
"changes": [
{
"note": "Do not query empty/unsigned orders. Swallow revets on DEX quotes.",
"pr": 2395
}
],
"timestamp": 1576540892
},
{
"timestamp": 1575931811,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [
{
"note": "Created package.",
"pr": 2344
}
],
"timestamp": 1575296764
},
{
"version": "1.0.0-beta.2",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1575290197
},
{
"version": "1.0.0-beta.1",
"changes": [
{
"note": "Created package.",
"pr": 2344
}
]
}
]

View File

@ -1,83 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.7.0 - _July 15, 2020_
* Pass in `DevUtils` address to required functions (#2629)
* Use new Kyber Katalyst functions (#2629)
## v1.6.0 - _June 24, 2020_
* Pass in `DevUtils` address as a constructor parameter (#2531)
* Sample `Curve` for buy amounts (#2551)
* Added `sampleBuysFromKyberNetwork` (#2551)
* Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve (#2575)
* Add UniswapV2 (#2595)
* Sample from MultiBridge (#2593)
## v1.5.1 - _March 3, 2020_
* Dependencies updated
## v1.5.0 - _February 27, 2020_
* Add generic liquidity provider sampling (#2487)
* Use liquidity provider registry in sampler (#2499)
## v1.4.2 - _February 26, 2020_
* Dependencies updated
## v1.4.1 - _February 25, 2020_
* Dependencies updated
## v1.4.0 - _February 15, 2020_
* Added Curve contract sampling (#2483)
## v1.3.0 - _February 8, 2020_
* Catch reverts to `DevUtils` calls (#2476)
* Remove wrapper functions and introduce `batchCall()` (#2477)
## 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_
* Add gas limits to external quote calls. (#2405)
## v1.0.2 - _December 17, 2019_
* Do not query empty/unsigned orders. Swallow revets on DEX quotes. (#2395)
## v1.0.1 - _December 9, 2019_
* Dependencies updated
## v1.0.0 - _December 2, 2019_
* Created package. (#2344)
## v1.0.0-beta.2 - _December 2, 2019_
* Dependencies updated
## v1.0.0-beta.1 - _Invalid date_
* Created package. (#2344)

View File

@ -1 +0,0 @@
[]

View File

@ -1,67 +0,0 @@
## ERC20BridgeSampler
This package contains contracts used in DEX aggregation.
This is an MVP implementation, which agnostically samples DEXes for off-chain sorting and order generation. It is entirely read-only and never not touches any funds.
## Installation
**Install**
```bash
npm install @0x/contracts-erc20-bridge-sampler --save
```
## 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-erc20-bridge-sampler yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-erc20-bridge-sampler yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@ -1,45 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
interface IDevUtils {
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
/// @param order The order structure.
/// @param signature Signature provided by maker that proves the order's authenticity.
/// `0x01` can always be provided if the signature does not need to be validated.
/// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order),
/// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state),
/// and isValidSignature (validity of the provided signature).
/// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
/// amount of each asset that can be filled.
function getOrderRelevantState(LibOrder.Order calldata order, bytes calldata signature)
external
view
returns (
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
bool isValidSignature
);
}

View File

@ -1,125 +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/LibMath.sol";
import "./IDevUtils.sol";
contract NativeOrderSampler {
/// @dev Gas limit for DevUtils calls.
uint256 constant internal DEV_UTILS_CALL_GAS = 500e3; // 500k
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// maker/taker asset amounts (returning 0).
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param devUtilsAddress Address to the DevUtils contract.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
function getOrderFillableTakerAssetAmounts(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures,
address devUtilsAddress
)
public
view
returns (uint256[] memory orderFillableTakerAssetAmounts)
{
orderFillableTakerAssetAmounts = new uint256[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
// Ignore orders with no signature or empty maker/taker amounts.
if (orderSignatures[i].length == 0 ||
orders[i].makerAssetAmount == 0 ||
orders[i].takerAssetAmount == 0) {
orderFillableTakerAssetAmounts[i] = 0;
continue;
}
// solhint-disable indent
(bool didSucceed, bytes memory resultData) =
devUtilsAddress
.staticcall
.gas(DEV_UTILS_CALL_GAS)
(abi.encodeWithSelector(
IDevUtils(devUtilsAddress).getOrderRelevantState.selector,
orders[i],
orderSignatures[i]
));
// solhint-enable indent
if (!didSucceed) {
orderFillableTakerAssetAmounts[i] = 0;
continue;
}
(
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
bool isValidSignature
) = abi.decode(
resultData,
(LibOrder.OrderInfo, uint256, bool)
);
// The fillable amount is zero if the order is not fillable or if the
// signature is invalid.
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE ||
!isValidSignature) {
orderFillableTakerAssetAmounts[i] = 0;
} else {
orderFillableTakerAssetAmounts[i] = fillableTakerAssetAmount;
}
}
}
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param devUtilsAddress Address to the DevUtils contract.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
function getOrderFillableMakerAssetAmounts(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures,
address devUtilsAddress
)
public
view
returns (uint256[] memory orderFillableMakerAssetAmounts)
{
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
orders,
orderSignatures,
devUtilsAddress
);
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
// convert them to maker asset amounts.
for (uint256 i = 0; i < orders.length; ++i) {
if (orderFillableMakerAssetAmounts[i] != 0) {
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
orderFillableMakerAssetAmounts[i],
orders[i].takerAssetAmount,
orders[i].makerAssetAmount
);
}
}
}
}

View File

@ -1,93 +0,0 @@
{
"name": "@0x/contracts-erc20-bridge-sampler",
"version": "1.7.0",
"engines": {
"node": ">=6.12"
},
"description": "Sampler contracts for the 0x asset-swapper",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"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",
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --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"
},
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|ICurve|IDevUtils|IEth2Dai|IKyberHintHandler|IKyberNetwork|IKyberNetworkProxy|IKyberStorage|ILiquidityProvider|ILiquidityProviderRegistry|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|UniswapSampler|UniswapV2Sampler).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/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.3.1",
"@0x/contracts-asset-proxy": "^3.4.0",
"@0x/contracts-erc20": "^3.2.1",
"@0x/contracts-exchange": "^3.2.7",
"@0x/contracts-exchange-libs": "^4.3.7",
"@0x/contracts-gen": "^2.0.10",
"@0x/contracts-test-utils": "^5.3.4",
"@0x/contracts-utils": "^4.5.1",
"@0x/dev-utils": "^3.3.0",
"@0x/sol-compiler": "^4.1.1",
"@0x/tslint-config": "^4.1.0",
"@0x/web3-wrapper": "^7.2.0",
"@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",
"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",
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.2.3",
"@0x/types": "^3.2.0",
"@0x/typescript-typings": "^5.1.1",
"@0x/utils": "^5.5.1",
"ethereum-types": "^3.2.0",
"lodash": "^4.17.11"
},
"publishConfig": {
"access": "public"
},
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
}

View File

@ -1,2 +0,0 @@
export * from './wrappers';
export * from './artifacts';

View File

@ -1,96 +0,0 @@
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* truffleframework.com/docs/advanced/configuration
*
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
// const HDWalletProvider = require('truffle-hdwallet-provider');
// const infuraKey = "fj4jll3k.....";
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
// development: {
// host: "127.0.0.1", // Localhost (default: none)
// port: 8545, // Standard Ethereum port (default: none)
// network_id: "*", // Any network (default: none)
// },
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
// ropsten: {
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
// network_id: 3, // Ropsten's id
// gas: 5500000, // Ropsten has a lower block limit than mainnet
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
// },
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: '0.5.9',
settings: {
evmVersion: 'istanbul',
optimizer: {
enabled: true,
runs: 1000000,
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
},
},
},
},
};

View File

@ -1,39 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/DummyLiquidityProvider.json",
"generated-artifacts/DummyLiquidityProviderRegistry.json",
"generated-artifacts/ERC20BridgeSampler.json",
"generated-artifacts/ILiquidityProvider.json",
"generated-artifacts/ILiquidityProviderRegistry.json",
"test/generated-artifacts/ApproximateBuys.json",
"test/generated-artifacts/CurveSampler.json",
"test/generated-artifacts/DummyLiquidityProvider.json",
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
"test/generated-artifacts/ERC20BridgeSampler.json",
"test/generated-artifacts/Eth2DaiSampler.json",
"test/generated-artifacts/ICurve.json",
"test/generated-artifacts/IDevUtils.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberHintHandler.json",
"test/generated-artifacts/IKyberNetwork.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/IKyberStorage.json",
"test/generated-artifacts/ILiquidityProvider.json",
"test/generated-artifacts/ILiquidityProviderRegistry.json",
"test/generated-artifacts/IMultiBridge.json",
"test/generated-artifacts/IUniswapExchangeQuotes.json",
"test/generated-artifacts/IUniswapV2Router01.json",
"test/generated-artifacts/KyberSampler.json",
"test/generated-artifacts/LiquidityProviderSampler.json",
"test/generated-artifacts/MultiBridgeSampler.json",
"test/generated-artifacts/NativeOrderSampler.json",
"test/generated-artifacts/SamplerUtils.json",
"test/generated-artifacts/TestERC20BridgeSampler.json",
"test/generated-artifacts/UniswapSampler.json",
"test/generated-artifacts/UniswapV2Sampler.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@ -1,10 +0,0 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false,
"max-file-line-count": false
},
"linterOptions": {
"exclude": ["src/artifacts.ts", "test/artifacts.ts"]
}
}

View File

@ -57,7 +57,6 @@
"@0x/contracts-broker": "^1.1.6",
"@0x/contracts-coordinator": "^3.1.7",
"@0x/contracts-dev-utils": "^1.3.5",
"@0x/contracts-erc20-bridge-sampler": "^1.7.0",
"@0x/contracts-exchange-forwarder": "^4.2.7",
"@0x/contracts-exchange-libs": "^4.3.7",
"@0x/contracts-extensions": "^6.2.1",

View File

@ -50,90 +50,98 @@ contract DeploymentConstants {
address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
/// @dev Mainnet address of the GST Collector
address constant private GST_COLLECTOR_ADDRESS = 0x000000D3b08566BE75A6DB803C03C85C0c1c5B96;
/// @dev Mainnet address of the mStable mUSD contract.
address constant private MUSD_ADDRESS = 0xe2f2a5C287993345a840Db3B0845fbC70f5935a5;
/* // Ropsten addresses ///////////////////////////////////////////////////////
/// @dev Mainnet address of the WETH contract.
address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
/// @dev Mainnet address of the KyberNetworkProxy contract.
address constant private KYBER_NETWORK_PROXY_ADDRESS = address(0);
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = address(0);
/// @dev Mainnet address of the `UniswapV2Router01` contract.
address constant private UNISWAP_V2_ROUTER_01_ADDRESS = address(0);
/// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
address constant private ETH2DAI_ADDRESS = address(0);
/// @dev Mainnet address of the `ERC20BridgeProxy` contract
address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xb344afeD348de15eb4a9e180205A2B0739628339;
///@dev Mainnet address of the `Dai` (multi-collateral) contract
address constant private DAI_ADDRESS = address(0);
/// @dev Mainnet address of the `Chai` contract
address constant private CHAI_ADDRESS = address(0);
/// @dev Mainnet address of the 0x DevUtils contract.
address constant private DEV_UTILS_ADDRESS = 0xC812AF3f3fBC62F76ea4262576EC0f49dB8B7f1c;
/// @dev Kyber ETH pseudo-address.
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Mainnet address of the dYdX contract.
address constant private DYDX_ADDRESS = address(0);
/// @dev Mainnet address of the GST2 contract
address constant private GST_ADDRESS = address(0);
/// @dev Mainnet address of the GST Collector
address constant private GST_COLLECTOR_ADDRESS = address(0); */
// // Ropsten addresses ///////////////////////////////////////////////////////
// /// @dev Mainnet address of the WETH contract.
// address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
// /// @dev Mainnet address of the KyberNetworkProxy contract.
// address constant private KYBER_NETWORK_PROXY_ADDRESS = 0xd719c34261e099Fdb33030ac8909d5788D3039C4;
// /// @dev Mainnet address of the `UniswapExchangeFactory` contract.
// address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0x9c83dCE8CA20E9aAF9D3efc003b2ea62aBC08351;
// /// @dev Mainnet address of the `UniswapV2Router01` contract.
// address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
// /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
// address constant private ETH2DAI_ADDRESS = address(0);
// /// @dev Mainnet address of the `ERC20BridgeProxy` contract
// address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xb344afeD348de15eb4a9e180205A2B0739628339;
// ///@dev Mainnet address of the `Dai` (multi-collateral) contract
// address constant private DAI_ADDRESS = address(0);
// /// @dev Mainnet address of the `Chai` contract
// address constant private CHAI_ADDRESS = address(0);
// /// @dev Mainnet address of the 0x DevUtils contract.
// address constant private DEV_UTILS_ADDRESS = 0xC812AF3f3fBC62F76ea4262576EC0f49dB8B7f1c;
// /// @dev Kyber ETH pseudo-address.
// address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// /// @dev Mainnet address of the dYdX contract.
// address constant private DYDX_ADDRESS = address(0);
// /// @dev Mainnet address of the GST2 contract
// address constant private GST_ADDRESS = address(0);
// /// @dev Mainnet address of the GST Collector
// address constant private GST_COLLECTOR_ADDRESS = address(0);
// /// @dev Mainnet address of the mStable mUSD contract.
// address constant private MUSD_ADDRESS = 0x4E1000616990D83e56f4b5fC6CC8602DcfD20459;
/* // Rinkeby addresses ///////////////////////////////////////////////////////
/// @dev Mainnet address of the WETH contract.
address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
/// @dev Mainnet address of the KyberNetworkProxy contract.
address constant private KYBER_NETWORK_PROXY_ADDRESS = address(0);
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = address(0);
/// @dev Mainnet address of the `UniswapV2Router01` contract.
address constant private UNISWAP_V2_ROUTER_01_ADDRESS = address(0);
/// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
address constant private ETH2DAI_ADDRESS = address(0);
/// @dev Mainnet address of the `ERC20BridgeProxy` contract
address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xA2AA4bEFED748Fba27a3bE7Dfd2C4b2c6DB1F49B;
///@dev Mainnet address of the `Dai` (multi-collateral) contract
address constant private DAI_ADDRESS = address(0);
/// @dev Mainnet address of the `Chai` contract
address constant private CHAI_ADDRESS = address(0);
/// @dev Mainnet address of the 0x DevUtils contract.
address constant private DEV_UTILS_ADDRESS = 0x46B5BC959e8A754c0256FFF73bF34A52Ad5CdfA9;
/// @dev Kyber ETH pseudo-address.
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Mainnet address of the dYdX contract.
address constant private DYDX_ADDRESS = address(0);
/// @dev Mainnet address of the GST2 contract
address constant private GST_ADDRESS = address(0);
/// @dev Mainnet address of the GST Collector
address constant private GST_COLLECTOR_ADDRESS = address(0); */
// // Rinkeby addresses ///////////////////////////////////////////////////////
// /// @dev Mainnet address of the WETH contract.
// address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
// /// @dev Mainnet address of the KyberNetworkProxy contract.
// address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x0d5371e5EE23dec7DF251A8957279629aa79E9C5;
// /// @dev Mainnet address of the `UniswapExchangeFactory` contract.
// address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36;
// /// @dev Mainnet address of the `UniswapV2Router01` contract.
// address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
// /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
// address constant private ETH2DAI_ADDRESS = address(0);
// /// @dev Mainnet address of the `ERC20BridgeProxy` contract
// address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xA2AA4bEFED748Fba27a3bE7Dfd2C4b2c6DB1F49B;
// ///@dev Mainnet address of the `Dai` (multi-collateral) contract
// address constant private DAI_ADDRESS = address(0);
// /// @dev Mainnet address of the `Chai` contract
// address constant private CHAI_ADDRESS = address(0);
// /// @dev Mainnet address of the 0x DevUtils contract.
// address constant private DEV_UTILS_ADDRESS = 0x46B5BC959e8A754c0256FFF73bF34A52Ad5CdfA9;
// /// @dev Kyber ETH pseudo-address.
// address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// /// @dev Mainnet address of the dYdX contract.
// address constant private DYDX_ADDRESS = address(0);
// /// @dev Mainnet address of the GST2 contract
// address constant private GST_ADDRESS = address(0);
// /// @dev Mainnet address of the GST Collector
// address constant private GST_COLLECTOR_ADDRESS = address(0);
// /// @dev Mainnet address of the mStable mUSD contract.
// address constant private MUSD_ADDRESS = address(0);
/* // Kovan addresses /////////////////////////////////////////////////////////
/// @dev Kovan address of the WETH contract.
address constant private WETH_ADDRESS = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
/// @dev Kovan address of the KyberNetworkProxy contract.
address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D;
/// @dev Kovan address of the `UniswapExchangeFactory` contract.
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30;
/// @dev Kovan address of the `UniswapV2Router01` contract.
address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
/// @dev Kovan address of the Eth2Dai `MatchingMarket` contract.
address constant private ETH2DAI_ADDRESS = 0xe325acB9765b02b8b418199bf9650972299235F4;
/// @dev Kovan address of the `ERC20BridgeProxy` contract
address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x3577552C1Fb7A44aD76BeEB7aB53251668A21F8D;
/// @dev Kovan address of the `Chai` contract
address constant private CHAI_ADDRESS = address(0);
/// @dev Kovan address of the `Dai` (multi-collateral) contract
address constant private DAI_ADDRESS = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;
/// @dev Kovan address of the 0x DevUtils contract.
address constant private DEV_UTILS_ADDRESS = 0x9402639A828BdF4E9e4103ac3B69E1a6E522eB59;
/// @dev Kyber ETH pseudo-address.
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Kovan address of the dYdX contract.
address constant private DYDX_ADDRESS = address(0);
/// @dev Kovan address of the GST2 contract
address constant private GST_ADDRESS = address(0);
/// @dev Kovan address of the GST Collector
address constant private GST_COLLECTOR_ADDRESS = address(0); */
// // Kovan addresses /////////////////////////////////////////////////////////
// /// @dev Kovan address of the WETH contract.
// address constant private WETH_ADDRESS = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
// /// @dev Kovan address of the KyberNetworkProxy contract.
// address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D;
// /// @dev Kovan address of the `UniswapExchangeFactory` contract.
// address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30;
// /// @dev Kovan address of the `UniswapV2Router01` contract.
// address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
// /// @dev Kovan address of the Eth2Dai `MatchingMarket` contract.
// address constant private ETH2DAI_ADDRESS = 0xe325acB9765b02b8b418199bf9650972299235F4;
// /// @dev Kovan address of the `ERC20BridgeProxy` contract
// address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x3577552C1Fb7A44aD76BeEB7aB53251668A21F8D;
// /// @dev Kovan address of the `Chai` contract
// address constant private CHAI_ADDRESS = address(0);
// /// @dev Kovan address of the `Dai` (multi-collateral) contract
// address constant private DAI_ADDRESS = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;
// /// @dev Kovan address of the 0x DevUtils contract.
// address constant private DEV_UTILS_ADDRESS = 0x9402639A828BdF4E9e4103ac3B69E1a6E522eB59;
// /// @dev Kyber ETH pseudo-address.
// address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// /// @dev Kovan address of the dYdX contract.
// address constant private DYDX_ADDRESS = address(0);
// /// @dev Kovan address of the GST2 contract
// address constant private GST_ADDRESS = address(0);
// /// @dev Kovan address of the GST Collector
// address constant private GST_COLLECTOR_ADDRESS = address(0);
// /// @dev Mainnet address of the mStable mUSD contract.
// address constant private MUSD_ADDRESS = address(0);
/// @dev Overridable way to get the `KyberNetworkProxy` address.
/// @return kyberAddress The `IKyberNetworkProxy` address.
@ -254,4 +262,14 @@ contract DeploymentConstants {
{
return GST_COLLECTOR_ADDRESS;
}
/// @dev An overridable way to retrieve the mStable mUSD address.
/// @return musd The mStable mUSD address.
function _getMUsdAddress()
internal
view
returns (address musd)
{
return MUSD_ADDRESS;
}
}

View File

@ -0,0 +1,172 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "./mixins/MixinAdapterAddresses.sol";
import "./mixins/MixinBalancer.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinKyber.sol";
import "./mixins/MixinMStable.sol";
import "./mixins/MixinOasis.sol";
import "./mixins/MixinUniswap.sol";
import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinZeroExBridge.sol";
contract BridgeAdapter is
MixinAdapterAddresses,
MixinBalancer,
MixinCurve,
MixinKyber,
MixinMStable,
MixinOasis,
MixinUniswap,
MixinUniswapV2,
MixinZeroExBridge
{
address private immutable BALANCER_BRIDGE_ADDRESS;
address private immutable CURVE_BRIDGE_ADDRESS;
address private immutable KYBER_BRIDGE_ADDRESS;
address private immutable MSTABLE_BRIDGE_ADDRESS;
address private immutable OASIS_BRIDGE_ADDRESS;
address private immutable UNISWAP_BRIDGE_ADDRESS;
address private immutable UNISWAP_V2_BRIDGE_ADDRESS;
/// @dev Emitted when a trade occurs.
/// @param inputToken The token the bridge is converting from.
/// @param outputToken The token the bridge is converting to.
/// @param inputTokenAmount Amount of input token.
/// @param outputTokenAmount Amount of output token.
/// @param from The bridge address, indicating the underlying source of the fill.
/// @param to The `to` address, currrently `address(this)`
event ERC20BridgeTransfer(
address inputToken,
address outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address from,
address to
);
constructor(AdapterAddresses memory addresses)
public
MixinBalancer()
MixinCurve()
MixinKyber(addresses)
MixinMStable(addresses)
MixinOasis(addresses)
MixinUniswap(addresses)
MixinUniswapV2(addresses)
MixinZeroExBridge()
{
BALANCER_BRIDGE_ADDRESS = addresses.balancerBridge;
CURVE_BRIDGE_ADDRESS = addresses.curveBridge;
KYBER_BRIDGE_ADDRESS = addresses.kyberBridge;
MSTABLE_BRIDGE_ADDRESS = addresses.mStableBridge;
OASIS_BRIDGE_ADDRESS = addresses.oasisBridge;
UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge;
UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge;
}
function trade(
bytes calldata makerAssetData,
address fromTokenAddress,
uint256 sellAmount
)
external
returns (uint256 boughtAmount)
{
(
address toTokenAddress,
address bridgeAddress,
bytes memory bridgeData
) = abi.decode(
makerAssetData[4:],
(address, address, bytes)
);
require(
bridgeAddress != address(this) && bridgeAddress != address(0),
"BridgeAdapter/INVALID_BRIDGE_ADDRESS"
);
if (bridgeAddress == CURVE_BRIDGE_ADDRESS) {
boughtAmount = _tradeCurve(
toTokenAddress,
sellAmount,
bridgeData
);
} else if (bridgeAddress == UNISWAP_V2_BRIDGE_ADDRESS) {
boughtAmount = _tradeUniswapV2(
toTokenAddress,
sellAmount,
bridgeData
);
} else if (bridgeAddress == UNISWAP_BRIDGE_ADDRESS) {
boughtAmount = _tradeUniswap(
toTokenAddress,
sellAmount,
bridgeData
);
} else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS) {
boughtAmount = _tradeBalancer(
toTokenAddress,
sellAmount,
bridgeData
);
} else if (bridgeAddress == KYBER_BRIDGE_ADDRESS) {
boughtAmount = _tradeKyber(
toTokenAddress,
sellAmount,
bridgeData
);
} else if (bridgeAddress == MSTABLE_BRIDGE_ADDRESS) {
boughtAmount = _tradeMStable(
toTokenAddress,
sellAmount,
bridgeData
);
} else if (bridgeAddress == OASIS_BRIDGE_ADDRESS) {
boughtAmount = _tradeOasis(
toTokenAddress,
sellAmount,
bridgeData
);
} else {
boughtAmount = _tradeZeroExBridge(
bridgeAddress,
fromTokenAddress,
toTokenAddress,
sellAmount,
bridgeData
);
}
emit ERC20BridgeTransfer(
fromTokenAddress,
toTokenAddress,
sellAmount,
boughtAmount,
bridgeAddress,
address(this)
);
return boughtAmount;
}
}

View File

@ -0,0 +1,30 @@
/*
Copyright 2020 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.6.5;
interface IBridgeAdapter {
function trade(
bytes calldata makerAssetData,
address fromTokenAddress,
uint256 sellAmount
)
external
returns (uint256 boughtAmount);
}

View File

@ -0,0 +1,42 @@
/*
Copyright 2020 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.6.5;
contract MixinAdapterAddresses
{
struct AdapterAddresses {
// Bridges
address balancerBridge;
address curveBridge;
address kyberBridge;
address mStableBridge;
address oasisBridge;
address uniswapBridge;
address uniswapV2Bridge;
// Exchanges
address kyberNetworkProxy;
address oasis;
address uniswapV2Router;
address uniswapExchangeFactory;
address mStable;
// Other
address weth;
}
}

View File

@ -0,0 +1,74 @@
/*
Copyright 2020 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.6.5;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
interface IBalancerPool {
/// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`.
/// @param tokenIn The token being sold
/// @param tokenAmountIn The amount of `tokenIn` to sell.
/// @param tokenOut The token being bought.
/// @param minAmountOut The minimum amount of `tokenOut` to buy.
/// @param maxPrice The maximum value for `spotPriceAfter`.
/// @return tokenAmountOut The amount of `tokenOut` bought.
/// @return spotPriceAfter The new marginal spot price of the given
/// token pair for this pool.
function swapExactAmountIn(
address tokenIn,
uint tokenAmountIn,
address tokenOut,
uint minAmountOut,
uint maxPrice
) external returns (uint tokenAmountOut, uint spotPriceAfter);
}
contract MixinBalancer {
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeBalancer(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data.
(address fromTokenAddress, address poolAddress) = abi.decode(
bridgeData,
(address, address)
);
IERC20TokenV06(fromTokenAddress).approveIfBelow(
poolAddress,
sellAmount
);
// Sell all of this contract's `fromTokenAddress` token balance.
(boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
fromTokenAddress, // tokenIn
sellAmount, // tokenAmountIn
toTokenAddress, // tokenOut
1, // minAmountOut
uint256(-1) // maxPrice
);
return boughtAmount;
}
}

View File

@ -0,0 +1,70 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
contract MixinCurve {
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
using LibRichErrorsV06 for bytes;
struct CurveBridgeData {
address curveAddress;
bytes4 exchangeFunctionSelector;
address fromTokenAddress;
int128 fromCoinIdx;
int128 toCoinIdx;
}
function _tradeCurve(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the Curve metadata.
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
IERC20TokenV06(data.fromTokenAddress).approveIfBelow(data.curveAddress, sellAmount);
uint256 beforeBalance = IERC20TokenV06(toTokenAddress).balanceOf(address(this));
(bool success, bytes memory resultData) =
data.curveAddress.call(abi.encodeWithSelector(
data.exchangeFunctionSelector,
data.fromCoinIdx,
data.toCoinIdx,
// dx
sellAmount,
// min dy
1
));
if (!success) {
resultData.rrevert();
}
return IERC20TokenV06(toTokenAddress).balanceOf(address(this)).safeSub(beforeBalance);
}
}

View File

@ -0,0 +1,123 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IKyberNetworkProxy {
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens.
/// @param sellTokenAddress Token to sell.
/// @param sellAmount Amount of tokens to sell.
/// @param buyTokenAddress Token to buy.
/// @param recipientAddress Address to send bought tokens to.
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
/// @param minConversionRate The minimal conversion rate. If actual rate
/// is lower, trade is canceled.
/// @param walletId The wallet ID to send part of the fees
/// @return boughtAmount Amount of tokens bought.
function trade(
address sellTokenAddress,
uint256 sellAmount,
address buyTokenAddress,
address payable recipientAddress,
uint256 maxBuyTokenAmount,
uint256 minConversionRate,
address walletId
)
external
payable
returns(uint256 boughtAmount);
}
contract MixinKyber is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Address indicating the trade is using ETH
address private immutable KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Mainnet address of the WETH contract.
IEtherTokenV06 private immutable WETH;
/// @dev Mainnet address of the KyberNetworkProxy contract.
IKyberNetworkProxy private immutable KYBER_NETWORK_PROXY;
constructor(AdapterAddresses memory addresses)
public
{
WETH = IEtherTokenV06(addresses.weth);
KYBER_NETWORK_PROXY = IKyberNetworkProxy(addresses.kyberNetworkProxy);
}
function _tradeKyber(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `fromTokenAddress`.
address fromTokenAddress = abi.decode(bridgeData, (address));
uint256 payableAmount;
if (fromTokenAddress != address(WETH)) {
// If the input token is not WETH, grant an allowance to the exchange
// to spend them.
IERC20TokenV06(fromTokenAddress).approveIfBelow(
address(KYBER_NETWORK_PROXY),
sellAmount
);
} else {
// If the input token is WETH, unwrap it and attach it to the call.
fromTokenAddress = KYBER_ETH_ADDRESS;
payableAmount = sellAmount;
WETH.withdraw(payableAmount);
}
bool isToTokenWeth = toTokenAddress == address(WETH);
// Try to sell all of this contract's input token balance through
// `KyberNetworkProxy.trade()`.
boughtAmount = KYBER_NETWORK_PROXY.trade{ value: payableAmount }(
// Input token.
fromTokenAddress,
// Sell amount.
sellAmount,
// Output token.
isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress,
// Transfer to this contract
address(uint160(address(this))),
// Buy as much as possible.
uint256(-1),
// Lowest minimum conversion rate
1,
// No affiliate address.
address(0)
);
if (isToTokenWeth) {
WETH.deposit{ value: boughtAmount }();
}
return boughtAmount;
}
}

View File

@ -0,0 +1,74 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IMStable {
function swap(
address _input,
address _output,
uint256 _quantity,
address _recipient
)
external
returns (uint256 output);
}
contract MixinMStable is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the mStable mUSD contract.
IMStable private immutable MSTABLE;
constructor(AdapterAddresses memory addresses)
public
{
MSTABLE = IMStable(addresses.mStable);
}
function _tradeMStable(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
IERC20TokenV06(fromTokenAddress).approveIfBelow(address(MSTABLE), sellAmount);
boughtAmount = MSTABLE.swap(
fromTokenAddress,
toTokenAddress,
sellAmount,
address(this)
);
}
}

View File

@ -0,0 +1,84 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IOasis {
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
/// @param fromToken The token being sold.
/// @param sellAmount The amount of `fromToken` token being sold.
/// @param toToken The token being bought.
/// @param minFillAmount Minimum amount of `toToken` token to buy.
/// @return fillAmount Amount of `toToken` bought.
function sellAllAmount(
address fromToken,
uint256 sellAmount,
address toToken,
uint256 minFillAmount
)
external
returns (uint256 fillAmount);
}
contract MixinOasis is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the Oasis `MatchingMarket` contract.
IOasis private immutable OASIS;
constructor(AdapterAddresses memory addresses)
public
{
OASIS = IOasis(addresses.oasis);
}
function _tradeOasis(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
IERC20TokenV06(fromTokenAddress).approveIfBelow(
address(OASIS),
sellAmount
);
// Try to sell all of this contract's `fromTokenAddress` token balance.
boughtAmount = OASIS.sellAllAmount(
fromTokenAddress,
sellAmount,
toTokenAddress,
// min fill amount
1
);
return boughtAmount;
}
}

View File

@ -0,0 +1,220 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IUniswapExchangeFactory {
/// @dev Get the exchange for a token.
/// @param tokenAddress The address of the token contract.
function getExchange(address tokenAddress)
external
view
returns (address);
}
interface IUniswapExchange {
/// @dev Buys at least `minTokensBought` tokens with ETH and transfer them
/// to `recipient`.
/// @param minTokensBought The minimum number of tokens to buy.
/// @param deadline Time when this order expires.
/// @param recipient Who to transfer the tokens to.
/// @return tokensBought Amount of tokens bought.
function ethToTokenTransferInput(
uint256 minTokensBought,
uint256 deadline,
address recipient
)
external
payable
returns (uint256 tokensBought);
/// @dev Buys at least `minEthBought` ETH with tokens.
/// @param tokensSold Amount of tokens to sell.
/// @param minEthBought The minimum amount of ETH to buy.
/// @param deadline Time when this order expires.
/// @return ethBought Amount of tokens bought.
function tokenToEthSwapInput(
uint256 tokensSold,
uint256 minEthBought,
uint256 deadline
)
external
returns (uint256 ethBought);
/// @dev Buys at least `minTokensBought` tokens with the exchange token
/// and transfer them to `recipient`.
/// @param tokensSold Amount of tokens to sell.
/// @param minTokensBought The minimum number of tokens to buy.
/// @param minEthBought The minimum amount of intermediate ETH to buy.
/// @param deadline Time when this order expires.
/// @param recipient Who to transfer the tokens to.
/// @param toTokenAddress The token being bought.
/// @return tokensBought Amount of tokens bought.
function tokenToTokenTransferInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address recipient,
address toTokenAddress
)
external
returns (uint256 tokensBought);
/// @dev Buys at least `minTokensBought` tokens with the exchange token.
/// @param tokensSold Amount of tokens to sell.
/// @param minTokensBought The minimum number of tokens to buy.
/// @param minEthBought The minimum amount of intermediate ETH to buy.
/// @param deadline Time when this order expires.
/// @param toTokenAddress The token being bought.
/// @return tokensBought Amount of tokens bought.
function tokenToTokenSwapInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address toTokenAddress
)
external
returns (uint256 tokensBought);
}
contract MixinUniswap is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the WETH contract.
IEtherTokenV06 private immutable WETH;
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
IUniswapExchangeFactory private immutable UNISWAP_EXCHANGE_FACTORY;
constructor(AdapterAddresses memory addresses)
public
{
WETH = IEtherTokenV06(addresses.weth);
UNISWAP_EXCHANGE_FACTORY = IUniswapExchangeFactory(addresses.uniswapExchangeFactory);
}
function _tradeUniswap(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
// Get the exchange for the token pair.
IUniswapExchange exchange = _getUniswapExchangeForTokenPair(
fromTokenAddress,
toTokenAddress
);
// Convert from WETH to a token.
if (fromTokenAddress == address(WETH)) {
// Unwrap the WETH.
WETH.withdraw(sellAmount);
// Buy as much of `toTokenAddress` token with ETH as possible
boughtAmount = exchange.ethToTokenTransferInput{ value: sellAmount }(
// Minimum buy amount.
1,
// Expires after this block.
block.timestamp,
// Recipient is `this`.
address(this)
);
// Convert from a token to WETH.
} else if (toTokenAddress == address(WETH)) {
// Grant the exchange an allowance.
IERC20TokenV06(fromTokenAddress).approveIfBelow(
address(exchange),
sellAmount
);
// Buy as much ETH with `fromTokenAddress` token as possible.
boughtAmount = exchange.tokenToEthSwapInput(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.
1,
// Expires after this block.
block.timestamp
);
// Wrap the ETH.
WETH.deposit{ value: boughtAmount }();
// Convert from one token to another.
} else {
// Grant the exchange an allowance.
IERC20TokenV06(fromTokenAddress).approveIfBelow(
address(exchange),
sellAmount
);
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
boughtAmount = exchange.tokenToTokenSwapInput(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.
1,
// Must buy at least 1 intermediate wei of ETH.
1,
// Expires after this block.
block.timestamp,
// Convert to `toTokenAddress`.
toTokenAddress
);
}
return boughtAmount;
}
/// @dev Retrieves the uniswap exchange for a given token pair.
/// In the case of a WETH-token exchange, this will be the non-WETH token.
/// In th ecase of a token-token exchange, this will be the first token.
/// @param fromTokenAddress The address of the token we are converting from.
/// @param toTokenAddress The address of the token we are converting to.
/// @return exchange The uniswap exchange.
function _getUniswapExchangeForTokenPair(
address fromTokenAddress,
address toTokenAddress
)
private
view
returns (IUniswapExchange exchange)
{
address exchangeTokenAddress = fromTokenAddress;
// Whichever isn't WETH is the exchange token.
if (fromTokenAddress == address(WETH)) {
exchangeTokenAddress = toTokenAddress;
}
exchange = IUniswapExchange(UNISWAP_EXCHANGE_FACTORY.getExchange(exchangeTokenAddress));
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
return exchange;
}
}

View File

@ -0,0 +1,100 @@
/*
Copyright 2020 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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
/*
UniswapV2
*/
interface IUniswapV2Router02 {
/// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
/// The first element of path is the input token, the last is the output token, and any intermediate elements represent
/// intermediate pairs to trade through (if, for example, a direct pair does not exist).
/// @param amountIn The amount of input tokens to send.
/// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
/// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
/// @param to Recipient of the output tokens.
/// @param deadline Unix timestamp after which the transaction will revert.
/// @return amounts The input token amount and all subsequent output token amounts.
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
contract MixinUniswapV2 is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `UniswapV2Router02` contract.
IUniswapV2Router02 private immutable UNISWAP_V2_ROUTER;
constructor(AdapterAddresses memory addresses)
public
{
UNISWAP_V2_ROUTER = IUniswapV2Router02(addresses.uniswapV2Router);
}
function _tradeUniswapV2(
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256)
{
// Decode the bridge data to get the `fromTokenAddress`.
// solhint-disable indent
address[] memory path = abi.decode(bridgeData, (address[]));
// solhint-enable indent
require(path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(path[path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
// Grant the Uniswap router an allowance.
IERC20TokenV06(path[0]).approveIfBelow(
address(UNISWAP_V2_ROUTER),
sellAmount
);
uint[] memory amounts = UNISWAP_V2_ROUTER.swapExactTokensForTokens(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.
1,
// Convert `fromTokenAddress` to `toTokenAddress`.
path,
// Recipient is `this`.
address(this),
// Expires after this block.
block.timestamp
);
return amounts[amounts.length-1];
}
}

View File

@ -0,0 +1,76 @@
/*
Copyright 2020 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.6.5;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
interface IERC20Bridge {
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
/// @param tokenAddress The address of the ERC20 token to transfer.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
/// @return success The magic bytes `0xdc1600f3` if successful.
function bridgeTransferFrom(
address tokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success);
}
contract MixinZeroExBridge {
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
function _tradeZeroExBridge(
address bridgeAddress,
address fromTokenAddress,
address toTokenAddress,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
uint256 balanceBefore = IERC20TokenV06(toTokenAddress).balanceOf(address(this));
// Trade the good old fashioned way
IERC20TokenV06(fromTokenAddress).compatTransfer(
bridgeAddress,
sellAmount
);
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
toTokenAddress,
bridgeAddress,
address(this),
1, // amount to transfer back from the bridge
bridgeData
);
boughtAmount = IERC20TokenV06(toTokenAddress).balanceOf(address(this)).safeSub(balanceBefore);
}
}

View File

@ -1,46 +0,0 @@
/*
Copyright 2020 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.6.5;
import "../vendor/v3/IGasToken.sol";
contract FixinGasToken
{
/// @dev Mainnet address of the GST2 contract
address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
/// @dev Mainnet address of the GST Collector
address constant private GST_COLLECTOR_ADDRESS = 0x000000D3b08566BE75A6DB803C03C85C0c1c5B96;
/// @dev Frees gas tokens using the balance of `from`. Amount freed is based
/// on the gas consumed in the function
modifier freesGasTokensFromCollector() {
uint256 gasBefore = gasleft();
_;
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
// 14154 24000 6870
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
GST_ADDRESS.call(
abi.encodeWithSelector(
IGasToken(address(0)).freeFromUpTo.selector,
GST_COLLECTOR_ADDRESS,
value
)
);
}
}

View File

@ -27,17 +27,14 @@ import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibTransformERC20RichErrors.sol";
import "../vendor/v3/IExchange.sol";
import "../vendor/v3/IERC20Bridge.sol";
import "../bridges/IBridgeAdapter.sol";
import "./Transformer.sol";
import "./LibERC20Transformer.sol";
import "../fixins/FixinGasToken.sol";
/// @dev A transformer that fills an ERC20 market sell/buy quote.
/// This transformer shortcuts bridge orders and fills them directly
contract FillQuoteTransformer is
Transformer,
FixinGasToken
Transformer
{
using LibERC20TokenV06 for IERC20TokenV06;
using LibERC20Transformer for IERC20TokenV06;
@ -116,15 +113,18 @@ contract FillQuoteTransformer is
IExchange public immutable exchange;
/// @dev The ERC20Proxy address.
address public immutable erc20Proxy;
/// @dev The BridgeAdapter address
IBridgeAdapter public immutable bridgeAdapter;
/// @dev Create this contract.
/// @param exchange_ The Exchange V3 instance.
constructor(IExchange exchange_)
constructor(IExchange exchange_, IBridgeAdapter bridgeAdapter_)
public
Transformer()
{
exchange = exchange_;
erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID);
bridgeAdapter = bridgeAdapter_;
}
/// @dev Sell this contract's entire balance of of `sellToken` in exchange
@ -139,7 +139,6 @@ contract FillQuoteTransformer is
)
external
override
freesGasTokensFromCollector
returns (bytes4 success)
{
TransformData memory data = abi.decode(data_, (TransformData));
@ -308,7 +307,6 @@ contract FillQuoteTransformer is
signature,
takerTokenFillAmount,
state,
makerToken,
takerFeeToken == takerToken
);
}
@ -372,7 +370,6 @@ contract FillQuoteTransformer is
signature,
takerTokenFillAmount,
state,
makerToken,
takerFeeToken == takerToken
);
}
@ -383,7 +380,6 @@ contract FillQuoteTransformer is
/// @param signature The order signature.
/// @param takerAssetFillAmount How much taker asset to fill.
/// @param state Intermediate state variables to get around stack limits.
/// @param makerToken The maker token.
/// @param isTakerFeeInTakerToken Whether the taker fee token is the same as the
/// taker token.
function _fillOrder(
@ -391,7 +387,6 @@ contract FillQuoteTransformer is
bytes memory signature,
uint256 takerAssetFillAmount,
FillState memory state,
IERC20TokenV06 makerToken,
bool isTakerFeeInTakerToken
)
private
@ -402,37 +397,23 @@ contract FillQuoteTransformer is
takerAssetFillAmount.min256(order.takerAssetAmount);
availableTakerAssetFillAmount =
availableTakerAssetFillAmount.min256(state.takerTokenBalanceRemaining);
// If it is a Bridge order we fill this directly
// rather than filling via 0x Exchange
// If it is a Bridge order we fill this directly through the BridgeAdapter
if (order.makerAssetData.readBytes4(0) == ERC20_BRIDGE_PROXY_ID) {
// Calculate the amount (in maker token) we expect to receive
// from the bridge
uint256 outputTokenAmount = LibMathV06.getPartialAmountFloor(
availableTakerAssetFillAmount,
order.takerAssetAmount,
order.makerAssetAmount
);
(bool success, bytes memory data) = address(_implementation).delegatecall(
(bool success, bytes memory resultData) = address(bridgeAdapter).delegatecall(
abi.encodeWithSelector(
this.fillBridgeOrder.selector,
order.makerAddress,
IBridgeAdapter.trade.selector,
order.makerAssetData,
order.takerAssetData,
availableTakerAssetFillAmount,
outputTokenAmount
address(_getTokenFromERC20AssetData(order.takerAssetData)),
availableTakerAssetFillAmount
)
);
// Swallow failures, leaving all results as zero.
// TransformERC20 asserts the overall price is as expected. It is possible
// a subsequent fill can net out at the expected price so we do not assert
// the trade balance
if (success) {
results.makerTokenBoughtAmount = makerToken
.balanceOf(address(this))
.safeSub(state.boughtAmount);
results.makerTokenBoughtAmount = abi.decode(resultData, (uint256));
results.takerTokenSoldAmount = availableTakerAssetFillAmount;
// protocol fee paid remains 0
}
return results;
} else {
// Emit an event if we do not have sufficient ETH to cover the protocol fee.
if (state.ethRemaining < state.protocolFee) {
@ -460,46 +441,6 @@ contract FillQuoteTransformer is
}
}
/// @dev Attempt to fill an ERC20 Bridge order. If the fill reverts,
/// or the amount filled was not sufficient this reverts.
/// @param makerAddress The address of the maker.
/// @param makerAssetData The encoded ERC20BridgeProxy asset data.
/// @param takerAssetData The encoded ERC20 asset data.
/// @param inputTokenAmount How much taker asset to fill clamped to the available balance.
/// @param outputTokenAmount How much maker asset to receive.
function fillBridgeOrder(
address makerAddress,
bytes calldata makerAssetData,
bytes calldata takerAssetData,
uint256 inputTokenAmount,
uint256 outputTokenAmount
)
external
{
// Track changes in the maker token balance.
(
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
) = abi.decode(
makerAssetData.sliceDestructive(4, makerAssetData.length),
(address, address, bytes)
);
require(bridgeAddress != address(this), "INVALID_BRIDGE_ADDRESS");
// Transfer the tokens to the bridge to perform the work
_getTokenFromERC20AssetData(takerAssetData).compatTransfer(
bridgeAddress,
inputTokenAmount
);
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
tokenAddress,
makerAddress,
address(this),
outputTokenAmount, // amount to transfer back from the bridge
bridgeData
);
}
/// @dev Extract the token from plain ERC20 asset data.
/// If the asset-data is empty, a zero token address will be returned.
/// @param assetData The order asset data.

View File

@ -29,6 +29,7 @@ contract TestFillQuoteTransformerBridge {
struct FillBehavior {
// Scaling for maker assets minted, in 1e18.
uint256 makerAssetMintRatio;
uint256 amount;
}
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
@ -49,7 +50,7 @@ contract TestFillQuoteTransformerBridge {
LibMathV06.getPartialAmountFloor(
behavior.makerAssetMintRatio,
1e18,
amount
behavior.amount
)
);
return ERC20_BRIDGE_PROXY_ID;

View File

@ -39,9 +39,9 @@
"publish:private": "yarn build && gitpkg publish"
},
"config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20,FillQuoteTransformer,PayTakerTransformer,WethTransformer,Ownable,SimpleFunctionRegistry,TransformERC20,TokenSpender,AffiliateFeeTransformer,SignatureValidator,MetaTransactions",
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20,FillQuoteTransformer,PayTakerTransformer,WethTransformer,Ownable,SimpleFunctionRegistry,TransformERC20,TokenSpender,AffiliateFeeTransformer,SignatureValidator,MetaTransactions,BridgeAdapter",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|Bootstrap|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinGasToken|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|IMetaTransactions|IOwnable|ISignatureValidator|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|MetaTransactions|Ownable|PayTakerTransformer|SignatureValidator|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|TransformerDeployer|WethTransformer|ZeroEx).json"
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|Bootstrap|BridgeAdapter|FillQuoteTransformer|FixinCommon|FixinEIP712|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|IMetaTransactions|IOwnable|ISignatureValidator|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|MetaTransactions|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinKyber|MixinMStable|MixinOasis|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|Ownable|PayTakerTransformer|SignatureValidator|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|TransformerDeployer|WethTransformer|ZeroEx).json"
},
"repository": {
"type": "git",

View File

@ -6,6 +6,7 @@
import { ContractArtifact } from 'ethereum-types';
import * as AffiliateFeeTransformer from '../generated-artifacts/AffiliateFeeTransformer.json';
import * as BridgeAdapter from '../generated-artifacts/BridgeAdapter.json';
import * as FillQuoteTransformer from '../generated-artifacts/FillQuoteTransformer.json';
import * as FullMigration from '../generated-artifacts/FullMigration.json';
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
@ -48,4 +49,5 @@ export const artifacts = {
AffiliateFeeTransformer: AffiliateFeeTransformer as ContractArtifact,
SignatureValidator: SignatureValidator as ContractArtifact,
MetaTransactions: MetaTransactions as ContractArtifact,
BridgeAdapter: BridgeAdapter as ContractArtifact,
};

View File

@ -1,6 +1,40 @@
export { ZeroExRevertErrors } from '@0x/utils';
export {
AbiDefinition,
CompilerOpts,
CompilerSettings,
CompilerSettingsMetadata,
ConstructorAbi,
ConstructorStateMutability,
ContractAbi,
ContractArtifact,
ContractChainData,
ContractChains,
DataItem,
DevdocOutput,
EventAbi,
EventParameter,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
EvmOutput,
FallbackAbi,
FunctionAbi,
MethodAbi,
OptimizerSettings,
OutputField,
ParamDescription,
RevertErrorAbi,
StandardContractOutput,
StateMutability,
TupleDataItem,
} from 'ethereum-types';
export { artifacts } from './artifacts';
export * from './migration';
export * from './nonce_utils';
export * from './signed_call_data';
export {
AffiliateFeeTransformerContract,
BridgeAdapterContract,
FillQuoteTransformerContract,
IOwnableContract,
IOwnableEvents,
@ -13,37 +47,3 @@ export {
WethTransformerContract,
ZeroExContract,
} from './wrappers';
export { ZeroExRevertErrors } from '@0x/utils';
export {
ContractArtifact,
ContractChains,
CompilerOpts,
StandardContractOutput,
CompilerSettings,
ContractChainData,
ContractAbi,
DevdocOutput,
EvmOutput,
CompilerSettingsMetadata,
OptimizerSettings,
OutputField,
ParamDescription,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
AbiDefinition,
FunctionAbi,
EventAbi,
RevertErrorAbi,
EventParameter,
DataItem,
MethodAbi,
ConstructorAbi,
FallbackAbi,
ConstructorStateMutability,
TupleDataItem,
StateMutability,
} from 'ethereum-types';
export * from './nonce_utils';
export * from './migration';
export * from './signed_call_data';

View File

@ -4,6 +4,7 @@
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/affiliate_fee_transformer';
export * from '../generated-wrappers/bridge_adapter';
export * from '../generated-wrappers/fill_quote_transformer';
export * from '../generated-wrappers/full_migration';
export * from '../generated-wrappers/i_allowance_target';

View File

@ -8,14 +8,15 @@ import { ContractArtifact } from 'ethereum-types';
import * as AffiliateFeeTransformer from '../test/generated-artifacts/AffiliateFeeTransformer.json';
import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.json';
import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json';
import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json';
import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json';
import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json';
import * as FixinEIP712 from '../test/generated-artifacts/FixinEIP712.json';
import * as FixinGasToken from '../test/generated-artifacts/FixinGasToken.json';
import * as FlashWallet from '../test/generated-artifacts/FlashWallet.json';
import * as FullMigration from '../test/generated-artifacts/FullMigration.json';
import * as IAllowanceTarget from '../test/generated-artifacts/IAllowanceTarget.json';
import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json';
import * as IBridgeAdapter from '../test/generated-artifacts/IBridgeAdapter.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
import * as IExchange from '../test/generated-artifacts/IExchange.json';
@ -52,6 +53,15 @@ import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTra
import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json';
import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json';
import * as MetaTransactions from '../test/generated-artifacts/MetaTransactions.json';
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
import * as MixinOasis from '../test/generated-artifacts/MixinOasis.json';
import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json';
import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json';
import * as MixinZeroExBridge from '../test/generated-artifacts/MixinZeroExBridge.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
import * as SignatureValidator from '../test/generated-artifacts/SignatureValidator.json';
@ -87,6 +97,17 @@ import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json';
export const artifacts = {
IZeroEx: IZeroEx as ContractArtifact,
ZeroEx: ZeroEx as ContractArtifact,
BridgeAdapter: BridgeAdapter as ContractArtifact,
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact,
MixinBalancer: MixinBalancer as ContractArtifact,
MixinCurve: MixinCurve as ContractArtifact,
MixinKyber: MixinKyber as ContractArtifact,
MixinMStable: MixinMStable as ContractArtifact,
MixinOasis: MixinOasis as ContractArtifact,
MixinUniswap: MixinUniswap as ContractArtifact,
MixinUniswapV2: MixinUniswapV2 as ContractArtifact,
MixinZeroExBridge: MixinZeroExBridge as ContractArtifact,
LibCommonRichErrors: LibCommonRichErrors as ContractArtifact,
LibMetaTransactionsRichErrors: LibMetaTransactionsRichErrors as ContractArtifact,
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
@ -119,7 +140,6 @@ export const artifacts = {
LibSignedCallData: LibSignedCallData as ContractArtifact,
FixinCommon: FixinCommon as ContractArtifact,
FixinEIP712: FixinEIP712 as ContractArtifact,
FixinGasToken: FixinGasToken as ContractArtifact,
FullMigration: FullMigration as ContractArtifact,
InitialMigration: InitialMigration as ContractArtifact,
LibBootstrap: LibBootstrap as ContractArtifact,

View File

@ -20,6 +20,7 @@ import * as _ from 'lodash';
import { artifacts } from '../artifacts';
import { TestFillQuoteTransformerBridgeContract } from '../generated-wrappers/test_fill_quote_transformer_bridge';
import {
BridgeAdapterContract,
FillQuoteTransformerContract,
TestFillQuoteTransformerExchangeContract,
TestFillQuoteTransformerHostContract,
@ -50,12 +51,34 @@ blockchainTests.resets('FillQuoteTransformer', env => {
env.txDefaults,
artifacts,
);
const bridgeAdapter = await BridgeAdapterContract.deployFrom0xArtifactAsync(
artifacts.BridgeAdapter,
env.provider,
env.txDefaults,
artifacts,
{
balancerBridge: NULL_ADDRESS,
curveBridge: NULL_ADDRESS,
kyberBridge: NULL_ADDRESS,
mStableBridge: NULL_ADDRESS,
oasisBridge: NULL_ADDRESS,
uniswapBridge: NULL_ADDRESS,
uniswapV2Bridge: NULL_ADDRESS,
kyberNetworkProxy: NULL_ADDRESS,
oasis: NULL_ADDRESS,
uniswapV2Router: NULL_ADDRESS,
uniswapExchangeFactory: NULL_ADDRESS,
mStable: NULL_ADDRESS,
weth: NULL_ADDRESS,
},
);
transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(
artifacts.FillQuoteTransformer,
env.provider,
env.txDefaults,
artifacts,
exchange.address,
bridgeAdapter.address,
);
host = await TestFillQuoteTransformerHostContract.deployFrom0xArtifactAsync(
artifacts.TestFillQuoteTransformerHost,
@ -110,8 +133,9 @@ blockchainTests.resets('FillQuoteTransformer', env => {
};
}
function createBridgeOrder(fields: Partial<Order> = {}, bridgeData: string = encodeBridgeBehavior()): FilledOrder {
function createBridgeOrder(fields: Partial<Order> = {}, fillRatio: Numberish = 1.0): FilledOrder {
const order = createOrder(fields);
const bridgeData = encodeBridgeBehavior(order.makerAssetAmount, fillRatio);
return {
...order,
makerAddress: bridge.address,
@ -265,11 +289,12 @@ blockchainTests.resets('FillQuoteTransformer', env => {
);
}
function encodeBridgeBehavior(makerAssetMintRatio: Numberish = 1.0): string {
function encodeBridgeBehavior(amount: BigNumber, makerAssetMintRatio: Numberish = 1.0): string {
return hexUtils.slice(
bridge
.encodeBehaviorData({
makerAssetMintRatio: new BigNumber(makerAssetMintRatio).times('1e18').integerValue(),
amount,
})
.getABIEncodedTransactionData(),
4,
@ -865,7 +890,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
});
});
describe('bridge orders', () => {
describe('bridge orders fall through', () => {
it('can fully sell to a single bridge order quote', async () => {
const orders = _.times(1, () => createBridgeOrder());
const signatures = orders.map(() => NULL_BYTES);

View File

@ -6,14 +6,15 @@
export * from '../test/generated-wrappers/affiliate_fee_transformer';
export * from '../test/generated-wrappers/allowance_target';
export * from '../test/generated-wrappers/bootstrap';
export * from '../test/generated-wrappers/bridge_adapter';
export * from '../test/generated-wrappers/fill_quote_transformer';
export * from '../test/generated-wrappers/fixin_common';
export * from '../test/generated-wrappers/fixin_e_i_p712';
export * from '../test/generated-wrappers/fixin_gas_token';
export * from '../test/generated-wrappers/flash_wallet';
export * from '../test/generated-wrappers/full_migration';
export * from '../test/generated-wrappers/i_allowance_target';
export * from '../test/generated-wrappers/i_bootstrap';
export * from '../test/generated-wrappers/i_bridge_adapter';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_erc20_transformer';
export * from '../test/generated-wrappers/i_exchange';
@ -50,6 +51,15 @@ export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors';
export * from '../test/generated-wrappers/lib_transform_erc20_storage';
export * from '../test/generated-wrappers/lib_wallet_rich_errors';
export * from '../test/generated-wrappers/meta_transactions';
export * from '../test/generated-wrappers/mixin_adapter_addresses';
export * from '../test/generated-wrappers/mixin_balancer';
export * from '../test/generated-wrappers/mixin_curve';
export * from '../test/generated-wrappers/mixin_kyber';
export * from '../test/generated-wrappers/mixin_m_stable';
export * from '../test/generated-wrappers/mixin_oasis';
export * from '../test/generated-wrappers/mixin_uniswap';
export * from '../test/generated-wrappers/mixin_uniswap_v2';
export * from '../test/generated-wrappers/mixin_zero_ex_bridge';
export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/pay_taker_transformer';
export * from '../test/generated-wrappers/signature_validator';

View File

@ -4,6 +4,7 @@
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/AffiliateFeeTransformer.json",
"generated-artifacts/BridgeAdapter.json",
"generated-artifacts/FillQuoteTransformer.json",
"generated-artifacts/FullMigration.json",
"generated-artifacts/IAllowanceTarget.json",
@ -27,14 +28,15 @@
"test/generated-artifacts/AffiliateFeeTransformer.json",
"test/generated-artifacts/AllowanceTarget.json",
"test/generated-artifacts/Bootstrap.json",
"test/generated-artifacts/BridgeAdapter.json",
"test/generated-artifacts/FillQuoteTransformer.json",
"test/generated-artifacts/FixinCommon.json",
"test/generated-artifacts/FixinEIP712.json",
"test/generated-artifacts/FixinGasToken.json",
"test/generated-artifacts/FlashWallet.json",
"test/generated-artifacts/FullMigration.json",
"test/generated-artifacts/IAllowanceTarget.json",
"test/generated-artifacts/IBootstrap.json",
"test/generated-artifacts/IBridgeAdapter.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IERC20Transformer.json",
"test/generated-artifacts/IExchange.json",
@ -71,6 +73,15 @@
"test/generated-artifacts/LibTransformERC20Storage.json",
"test/generated-artifacts/LibWalletRichErrors.json",
"test/generated-artifacts/MetaTransactions.json",
"test/generated-artifacts/MixinAdapterAddresses.json",
"test/generated-artifacts/MixinBalancer.json",
"test/generated-artifacts/MixinCurve.json",
"test/generated-artifacts/MixinKyber.json",
"test/generated-artifacts/MixinMStable.json",
"test/generated-artifacts/MixinOasis.json",
"test/generated-artifacts/MixinUniswap.json",
"test/generated-artifacts/MixinUniswapV2.json",
"test/generated-artifacts/MixinZeroExBridge.json",
"test/generated-artifacts/Ownable.json",
"test/generated-artifacts/PayTakerTransformer.json",
"test/generated-artifacts/SignatureValidator.json",

View File

@ -51,7 +51,7 @@
"lint:contracts": "wsrun lint -p ${npm_package_config_contractsPackages} -c --fast-exit --stages --exclude-missing"
},
"config": {
"contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc20-bridge-sampler @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler @0x/contracts-broker @0x/contracts-zero-ex",
"contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator @0x/contracts-broker @0x/contracts-zero-ex",
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic",
"packagesWithDocPages": "0x.js @0x/contract-wrappers @0x/connect @0x/json-schemas @0x/subproviders @0x/web3-wrapper @0x/order-utils @0x/sol-compiler @0x/sol-coverage @0x/sol-profiler @0x/sol-trace @0x/dev-utils @0x/asset-swapper @0x/migrations @0x/orderbook @0x/contracts-asset-proxy @0x/contracts-coordinator @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-extensions @0x/contracts-staking @0x/contracts-zero-ex",
"ignoreDependencyVersions": "@types/styled-components @types/node",

2
packages/asset-swapper/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
**/generated-artifacts
**/generated-wrappers

View File

@ -3,6 +3,8 @@
*
# Whitelist lib
!lib/**/*
# Whitelist Solidity contracts
!contracts/src/**/*
# Blacklist tests and publish scripts
/lib/test/*
/lib/monorepo_scripts/

View File

@ -0,0 +1,21 @@
{
"extends": "default",
"rules": {
"avoid-low-level-calls": false,
"avoid-tx-origin": "warn",
"bracket-align": false,
"code-complexity": false,
"compiler-fixed": false,
"const-name-snakecase": "error",
"expression-indent": "error",
"function-max-lines": false,
"func-order": "error",
"indent": ["error", 4],
"max-line-length": ["warn", 160],
"no-inline-assembly": false,
"quotes": ["error", "double"],
"separate-by-one-line-in-contract": "error",
"space-after-comma": "error",
"statement-indent": "error"
}
}

View File

@ -45,6 +45,14 @@
{
"note": "Adjust fill by ethToInputRate when ethToOutputRate is 0",
"pr": 2660
},
{
"note": "Added `mStable`",
"pr": 2662
},
{
"note": "Merge `erc20-bridge-sampler` into this package",
"pr": 2664
}
]
},

View File

@ -24,20 +24,22 @@ import "./Eth2DaiSampler.sol";
import "./KyberSampler.sol";
import "./LiquidityProviderSampler.sol";
import "./MultiBridgeSampler.sol";
import "./MStableSampler.sol";
import "./NativeOrderSampler.sol";
import "./UniswapSampler.sol";
import "./UniswapV2Sampler.sol";
contract ERC20BridgeSampler is
Eth2DaiSampler,
UniswapSampler,
KyberSampler,
CurveSampler,
Eth2DaiSampler,
KyberSampler,
LiquidityProviderSampler,
UniswapV2Sampler,
MStableSampler,
MultiBridgeSampler,
NativeOrderSampler
NativeOrderSampler,
UniswapSampler,
UniswapV2Sampler
{
/// @dev Call multiple public functions on this contract in a single transaction.
/// @param callDatas ABI-encoded call data for each function call.
@ -49,6 +51,9 @@ contract ERC20BridgeSampler is
{
callResults = new bytes[](callDatas.length);
for (uint256 i = 0; i != callDatas.length; ++i) {
if (callDatas[i].length == 0) {
continue;
}
(bool didSucceed, bytes memory resultData) = address(this).staticcall(callDatas[i]);
if (!didSucceed) {
assembly { revert(add(resultData, 0x20), mload(resultData)) }

View File

@ -0,0 +1,32 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
interface IMStable {
function getSwapOutput(
address _input,
address _output,
uint256 _quantity
)
external
view
returns (bool, string memory, uint256 output);
}

View File

@ -127,6 +127,9 @@ contract LiquidityProviderSampler is
view
returns (address providerAddress)
{
if (registryAddress == address(0)) {
return address(0);
}
bytes memory callData = abi.encodeWithSelector(
ILiquidityProviderRegistry(0).getLiquidityProviderForMarket.selector,
takerToken,

View File

@ -0,0 +1,126 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "./IMStable.sol";
import "./ApproximateBuys.sol";
import "./SamplerUtils.sol";
contract MStableSampler is
DeploymentConstants,
SamplerUtils,
ApproximateBuys
{
/// @dev Default gas limit for mStable calls.
uint256 constant private DEFAULT_CALL_GAS = 800e3; // 800k
/// @dev Sample sell quotes from the mStable mUSD contract
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromMStable(
address takerToken,
address makerToken,
uint256[] memory takerTokenAmounts
)
public
view
returns (uint256[] memory makerTokenAmounts)
{
// Initialize array of maker token amounts.
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
(bool didSucceed, bytes memory resultData) =
address(_getMUsdAddress()).staticcall.gas(DEFAULT_CALL_GAS)(
abi.encodeWithSelector(
IMStable(0).getSwapOutput.selector,
takerToken,
makerToken,
takerTokenAmounts[i]
));
uint256 buyAmount = 0;
if (didSucceed) {
(, , buyAmount) = abi.decode(resultData, (bool, string, uint256));
} else {
break;
}
makerTokenAmounts[i] = buyAmount;
}
}
/// @dev Sample buy quotes from MStable mUSD contract
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param makerTokenAmounts Maker token buy amount for each sample.
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.
function sampleBuysFromMStable(
address takerToken,
address makerToken,
uint256[] memory makerTokenAmounts
)
public
view
returns (uint256[] memory takerTokenAmounts)
{
return _sampleApproximateBuys(
ApproximateBuyQuoteOpts({
makerTokenData: abi.encode(makerToken),
takerTokenData: abi.encode(takerToken),
getSellQuoteCallback: _sampleSellForApproximateBuyFromMStable
}),
makerTokenAmounts
);
}
function _sampleSellForApproximateBuyFromMStable(
bytes memory takerTokenData,
bytes memory makerTokenData,
uint256 sellAmount
)
private
view
returns (uint256 buyAmount)
{
(address takerToken) =
abi.decode(takerTokenData, (address));
(address makerToken) =
abi.decode(makerTokenData, (address));
(bool success, bytes memory resultData) =
address(this).staticcall(abi.encodeWithSelector(
this.sampleSellsFromMStable.selector,
takerToken,
makerToken,
_toSingleValueArray(sellAmount)
));
if (!success) {
return 0;
}
// solhint-disable-next-line indent
return abi.decode(resultData, (uint256[]))[0];
}
}

View File

@ -0,0 +1,205 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
contract NativeOrderSampler {
using LibSafeMath for uint256;
using LibBytes for bytes;
/// @dev The Exchange ERC20Proxy ID.
bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0;
/// @dev Gas limit for calls to `getOrderFillableTakerAmount()`.
uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// maker/taker asset amounts (returning 0).
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param exchange The V3 exchange.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
function getOrderFillableTakerAssetAmounts(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures,
IExchange exchange
)
public
view
returns (uint256[] memory orderFillableTakerAssetAmounts)
{
orderFillableTakerAssetAmounts = new uint256[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
// solhint-disable indent
(bool didSucceed, bytes memory resultData) =
address(this)
.staticcall
.gas(DEFAULT_CALL_GAS)
(abi.encodeWithSelector(
this.getOrderFillableTakerAmount.selector,
orders[i],
orderSignatures[i],
exchange
));
// solhint-enable indent
orderFillableTakerAssetAmounts[i] = didSucceed
? abi.decode(resultData, (uint256))
: 0;
}
}
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param exchange The V3 exchange.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
function getOrderFillableMakerAssetAmounts(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures,
IExchange exchange
)
public
view
returns (uint256[] memory orderFillableMakerAssetAmounts)
{
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
orders,
orderSignatures,
exchange
);
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
// convert them to maker asset amounts.
for (uint256 i = 0; i < orders.length; ++i) {
if (orderFillableMakerAssetAmounts[i] != 0) {
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
orderFillableMakerAssetAmounts[i],
orders[i].takerAssetAmount,
orders[i].makerAssetAmount
);
}
}
}
/// @dev Get the fillable taker amount of an order, taking into account
/// order state, maker fees, and maker balances.
function getOrderFillableTakerAmount(
LibOrder.Order memory order,
bytes memory signature,
IExchange exchange
)
public
view
returns (uint256 fillableTakerAmount)
{
if (signature.length == 0 ||
order.makerAssetAmount == 0 ||
order.takerAssetAmount == 0)
{
return 0;
}
LibOrder.OrderInfo memory orderInfo = exchange.getOrderInfo(order);
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
return 0;
}
if (!exchange.isValidHashSignature(orderInfo.orderHash, order.makerAddress, signature)) {
return 0;
}
address spender = exchange.getAssetProxy(ERC20_ASSET_PROXY_ID);
IERC20Token makerToken = _getTokenFromERC20AssetData(order.makerAssetData);
if (makerToken == IERC20Token(0)) {
return 0;
}
IERC20Token makerFeeToken = order.makerFee > 0
? _getTokenFromERC20AssetData(order.makerFeeAssetData)
: IERC20Token(0);
uint256 remainingTakerAmount = order.takerAssetAmount
.safeSub(orderInfo.orderTakerAssetFilledAmount);
fillableTakerAmount = remainingTakerAmount;
// The total fillable maker amount is the remaining fillable maker amount
// PLUS maker fees, if maker fees are denominated in the maker token.
uint256 totalFillableMakerAmount = LibMath.safeGetPartialAmountFloor(
remainingTakerAmount,
order.takerAssetAmount,
makerFeeToken == makerToken
? order.makerAssetAmount.safeAdd(order.makerFee)
: order.makerAssetAmount
);
// The spendable amount of maker tokens (by the maker) is the lesser of
// the maker's balance and the allowance they've granted to the ERC20Proxy.
uint256 spendableMakerAmount = LibSafeMath.min256(
makerToken.balanceOf(order.makerAddress),
makerToken.allowance(order.makerAddress, spender)
);
// Scale the fillable taker amount by the ratio of the maker's
// spendable maker amount over the total fillable maker amount.
if (spendableMakerAmount < totalFillableMakerAmount) {
fillableTakerAmount = LibMath.getPartialAmountCeil(
spendableMakerAmount,
totalFillableMakerAmount,
remainingTakerAmount
);
}
// If the maker fee is denominated in another token, constrain
// the fillable taker amount by how much the maker can pay of that token.
if (makerFeeToken != makerToken && makerFeeToken != IERC20Token(0)) {
uint256 spendableExtraMakerFeeAmount = LibSafeMath.min256(
makerFeeToken.balanceOf(order.makerAddress),
makerFeeToken.allowance(order.makerAddress, spender)
);
if (spendableExtraMakerFeeAmount < order.makerFee) {
fillableTakerAmount = LibSafeMath.min256(
fillableTakerAmount,
LibMath.getPartialAmountCeil(
spendableExtraMakerFeeAmount,
order.makerFee,
remainingTakerAmount
)
);
}
}
}
function _getTokenFromERC20AssetData(bytes memory assetData)
private
pure
returns (IERC20Token token)
{
if (assetData.length == 0) {
return IERC20Token(address(0));
}
if (assetData.length != 36 ||
assetData.readBytes4(0) != ERC20_ASSET_PROXY_ID)
{
return IERC20Token(address(0));
}
return IERC20Token(assetData.readAddress(16));
}
}

View File

@ -23,7 +23,6 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "../src/ERC20BridgeSampler.sol";
import "../src/IEth2Dai.sol";
import "../src/IDevUtils.sol";
import "../src/IKyberNetworkProxy.sol";
import "../src/IUniswapV2Router01.sol";
@ -477,33 +476,17 @@ contract TestERC20BridgeSampler is
uniswap.createTokenExchanges(tokenAddresses);
}
// `IDevUtils.getOrderRelevantState()`, overridden to return deterministic
// states.
function getOrderRelevantState(
// Overridden to return deterministic states.
function getOrderFillableTakerAmount(
LibOrder.Order memory order,
bytes memory
bytes memory,
IExchange
)
public
pure
returns (
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
bool isValidSignature
)
view
returns (uint256 fillableTakerAmount)
{
// The order hash is just the hash of the salt.
bytes32 orderHash = keccak256(abi.encode(order.salt));
// Everything else is derived from the hash.
orderInfo.orderHash = orderHash;
if (uint256(orderHash) % 100 > 90) {
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
} else {
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
}
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
fillableTakerAssetAmount =
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
isValidSignature = uint256(orderHash) % 2 == 1;
return uint256(keccak256(abi.encode(order.salt))) % order.takerAssetAmount;
}
// Overriden to return deterministic decimals.

View File

@ -0,0 +1,109 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "../src/NativeOrderSampler.sol";
contract TestNativeOrderSamplerToken {
mapping (address => uint256) public balanceOf;
mapping (address => mapping(address => uint256)) public allowance;
function setBalanceAndAllowance(
address owner,
address spender,
uint256 balance,
uint256 allowance_
)
external
{
balanceOf[owner] = balance;
allowance[owner][spender] = allowance_;
}
}
contract TestNativeOrderSampler is
NativeOrderSampler
{
uint8 private constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED) + 1;
bytes32 private constant VALID_SIGNATURE_HASH = keccak256(hex"01");
function createTokens(uint256 count)
external
returns (TestNativeOrderSamplerToken[] memory tokens)
{
tokens = new TestNativeOrderSamplerToken[](count);
for (uint256 i = 0; i < count; ++i) {
tokens[i] = new TestNativeOrderSamplerToken();
}
}
function setTokenBalanceAndAllowance(
TestNativeOrderSamplerToken token,
address owner,
address spender,
uint256 balance,
uint256 allowance
)
external
{
token.setBalanceAndAllowance(owner, spender, balance, allowance);
}
// IExchange.getAssetProxy()
function getAssetProxy(bytes4 proxyId)
public
pure
returns (address)
{
return address(uint160(uint256(keccak256(abi.encode(proxyId)))));
}
// IExchange.getOrderInfo()
function getOrderInfo(LibOrder.Order calldata order)
external
pure
returns (LibOrder.OrderInfo memory orderInfo)
{
// The order salt determines everything.
orderInfo.orderHash = keccak256(abi.encode(order.salt));
if (uint8(order.salt) == 0xFF) {
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
} else {
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
}
// The expiration time is the filled taker asset amount.
orderInfo.orderTakerAssetFilledAmount = order.expirationTimeSeconds;
}
// IExchange.isValidSignature()
function isValidHashSignature(
bytes32,
address,
bytes calldata signature
)
external
pure
returns (bool isValid)
{
return keccak256(signature) == VALID_SIGNATURE_HASH;
}
}

View File

@ -8,26 +8,35 @@
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
"build": "yarn tsc -b",
"build": "yarn pre_build && tsc -b",
"watch": "tsc -w -p tsconfig.json",
"build:ci": "yarn build",
"lint": "tslint --format stylish --project . && yarn prettier --check",
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"compile": "sol-compiler",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"lint-contracts": "#solhint -c .solhint.json contracts/**/**/**/**/*.sol",
"prettier": "prettier '**/*.{ts,tsx,json,md}' --config ../../.prettierrc --ignore-path ../../.prettierignore",
"fix": "tslint --fix --format stylish --project . && yarn prettier --write",
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
"test:circleci": "yarn test:coverage",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 30000 --bail --exit",
"clean": "shx rm -rf lib test_temp generated_docs",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*_test.js' lib/test/global_hooks.js --timeout 30000 --bail --exit",
"clean": "shx rm -rf lib test_temp generated_docs test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"diff_docs": "git diff --exit-code ./docs",
"s3:sync_md_docs": "aws s3 sync ./docs s3://docs-markdown/${npm_package_name}/v${npm_package_version} --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
"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",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"publish:private": "yarn build && gitpkg publish"
},
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|ICurve|IEth2Dai|IKyberHintHandler|IKyberNetwork|IKyberNetworkProxy|IKyberStorage|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|TestNativeOrderSampler|UniswapSampler|UniswapV2Sampler).json",
"postpublish": {
"assets": []
}
@ -47,34 +56,43 @@
},
"dependencies": {
"@0x/assert": "^3.0.9",
"@0x/base-contract": "^6.2.3",
"@0x/contract-addresses": "^4.11.0",
"@0x/contract-artifacts": "^3.7.1",
"@0x/contract-wrappers": "^13.8.0",
"@0x/json-schemas": "^5.1.0",
"@0x/order-utils": "^10.3.0",
"@0x/orderbook": "^2.2.7",
"@0x/quote-server": "^2.0.2",
"@0x/types": "^3.2.0",
"@0x/typescript-typings": "^5.1.1",
"@0x/utils": "^5.5.1",
"@0x/web3-wrapper": "^7.2.0",
"@balancer-labs/sor": "0.3.2",
"axios": "^0.19.2",
"axios-mock-adapter": "^1.18.1",
"decimal.js": "^10.2.0",
"ethereum-types": "^3.2.0",
"ethereumjs-util": "^5.1.1",
"heartbeats": "^5.0.1",
"lodash": "^4.17.11"
},
"devDependencies": {
"@0x/base-contract": "^6.2.3",
"@0x/contracts-asset-proxy": "^3.4.0",
"@0x/contracts-erc20": "^3.2.1",
"@0x/contracts-exchange": "^3.2.7",
"@0x/contracts-exchange-libs": "^4.3.7",
"@0x/contracts-gen": "^2.0.10",
"@0x/contracts-test-utils": "^5.3.4",
"@0x/contracts-utils": "^4.5.1",
"@0x/dev-utils": "^3.3.0",
"@0x/mesh-rpc-client": "^7.0.4-beta-0xv3",
"@0x/migrations": "^6.4.0",
"@0x/sol-compiler": "^4.1.1",
"@0x/subproviders": "^6.1.1",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.1.0",
"@0x/types": "^3.2.0",
"@0x/typescript-typings": "^5.1.1",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@ -82,7 +100,6 @@
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"ethereum-types": "^3.2.0",
"gitpkg": "https://github.com/0xProject/gitpkg.git",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",

View File

@ -13,21 +13,57 @@ export {
SRAWebsocketOrderProviderOpts,
} from '@0x/orderbook';
export { RFQTFirmQuote, RFQTIndicativeQuote } from '@0x/quote-server';
export { APIOrder, Asset, AssetPairsItem, SignedOrder } from '@0x/types';
export { BigNumber } from '@0x/utils';
export {
APIOrder,
Asset,
AssetPairsItem,
DecodedLogEvent,
EventCallback,
IndexedFilterValues,
SignedOrder,
} from '@0x/types';
export { BigNumber } from '@0x/utils';
export { AxiosInstance } from 'axios';
export {
AbiDefinition,
BlockParam,
BlockParamLiteral,
CompilerOpts,
CompilerSettings,
CompilerSettingsMetadata,
ConstructorAbi,
ConstructorStateMutability,
ContractAbi,
ContractArtifact,
ContractChainData,
ContractChains,
ContractEventArg,
DataItem,
DecodedLogArgs,
DevdocOutput,
EIP1193Event,
EIP1193Provider,
EventAbi,
EventParameter,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
EvmOutput,
FallbackAbi,
FunctionAbi,
GanacheProvider,
GethCallOverrides,
JSONRPCErrorCallback,
JSONRPCRequestPayload,
JSONRPCResponseError,
JSONRPCResponsePayload,
LogWithDecodedArgs,
MethodAbi,
OptimizerSettings,
OutputField,
ParamDescription,
RevertErrorAbi,
StandardContractOutput,
StateMutability,
SupportedProvider,
TupleDataItem,
Web3JsProvider,
@ -36,6 +72,7 @@ export {
Web3JsV3Provider,
ZeroExProvider,
} from 'ethereum-types';
export { artifacts } from './artifacts';
export { InsufficientAssetLiquidityError } from './errors';
export { SwapQuoteConsumer } from './quote_consumers/swap_quote_consumer';
export { SwapQuoter } from './swap_quoter';
@ -99,7 +136,6 @@ export {
} from './utils/quote_report_generator';
export { QuoteRequestor } from './utils/quote_requestor';
export { rfqtMocker } from './utils/rfqt_mocker';
export { ERC20BridgeSamplerContract } from './wrappers';
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
export type Native = ERC20BridgeSource.Native;
export { AxiosInstance } from 'axios';

View File

@ -1,6 +1,5 @@
import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { ERC20BridgeSampler } from '@0x/contract-artifacts';
import { DevUtilsContract, ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
import { DevUtilsContract } from '@0x/contract-wrappers';
import { schemas } from '@0x/json-schemas';
import { assetDataUtils, SignedOrder } from '@0x/order-utils';
import { MeshOrderProviderOpts, Orderbook, SRAPollingOrderProviderOpts } from '@0x/orderbook';
@ -8,6 +7,7 @@ import { BigNumber, providerUtils } from '@0x/utils';
import { BlockParamLiteral, SupportedProvider, ZeroExProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { constants } from './constants';
import {
CalculateSwapQuoteOpts,
@ -39,6 +39,7 @@ import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
import { QuoteRequestor } from './utils/quote_requestor';
import { sortingUtils } from './utils/sorting_utils';
import { SwapQuoteCalculator } from './utils/swap_quote_calculator';
import { ERC20BridgeSamplerContract } from './wrappers';
export class SwapQuoter {
public readonly provider: ZeroExProvider;
@ -183,7 +184,7 @@ export class SwapQuoter {
);
this._orderStateUtils = new OrderStateUtils(this._devUtilsContract);
// Allow the sampler bytecode to be overwritten using geths override functionality
const samplerBytecode = _.get(ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
const defaultCodeOverrides = samplerBytecode
? {
[this._contractAddresses.erc20BridgeSampler]: { code: samplerBytecode },

View File

@ -14,6 +14,7 @@ export const SELL_SOURCES = [
ERC20BridgeSource.Kyber,
ERC20BridgeSource.Curve,
ERC20BridgeSource.Balancer,
ERC20BridgeSource.MStable,
];
/**
@ -26,6 +27,7 @@ export const BUY_SOURCES = [
ERC20BridgeSource.Kyber,
ERC20BridgeSource.Curve,
ERC20BridgeSource.Balancer,
ERC20BridgeSource.MStable,
];
export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {

View File

@ -97,7 +97,7 @@ export class MarketOperationUtils {
// Call the sampler contract.
const samplerPromise = this._sampler.executeAsync(
// Get native order fillable amounts.
DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.devUtils),
DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange),
// Get the custom liquidity provider from registry.
DexOrderSampler.ops.getLiquidityProviderFromRegistry(
this._liquidityProviderRegistry,
@ -213,7 +213,7 @@ export class MarketOperationUtils {
// Call the sampler contract.
const samplerPromise = this._sampler.executeAsync(
// Get native order fillable amounts.
DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.devUtils),
DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange),
// Get the custom liquidity provider from registry.
DexOrderSampler.ops.getLiquidityProviderFromRegistry(
this._liquidityProviderRegistry,
@ -381,7 +381,7 @@ export class MarketOperationUtils {
const sources = difference(BUY_SOURCES, _opts.excludedSources);
const ops = [
...batchNativeOrders.map(orders =>
DexOrderSampler.ops.getOrderFillableMakerAmounts(orders, this.contractAddresses.devUtils),
DexOrderSampler.ops.getOrderFillableMakerAmounts(orders, this.contractAddresses.exchange),
),
...(await Promise.all(
batchNativeOrders.map(async orders =>

View File

@ -196,6 +196,8 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
return (fill.fillData as LiquidityProviderFillData).poolAddress;
case ERC20BridgeSource.MultiBridge:
return (fill.fillData as MultiBridgeFillData).poolAddress;
case ERC20BridgeSource.MStable:
return opts.contractAddresses.mStableBridge;
default:
break;
}

View File

@ -1,7 +1,7 @@
import { ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
import { BigNumber } from '@0x/utils';
import { BigNumber, NULL_BYTES } from '@0x/utils';
import { SamplerOverrides } from '../../types';
import { ERC20BridgeSamplerContract } from '../../wrappers';
import { BalancerPoolsCache } from './balancer_utils';
import { samplerOperations } from './sampler_operations';
@ -144,18 +144,23 @@ export class DexOrderSampler {
const { overrides, block } = this._samplerOverrides
? this._samplerOverrides
: { overrides: undefined, block: undefined };
// All operations are NOOPs
if (callDatas.every(cd => cd === NULL_BYTES)) {
return Promise.all(
callDatas.map(async (_callData, i) => ops[i].handleCallResultsAsync(this._samplerContract, NULL_BYTES)),
);
}
// Execute all non-empty calldatas.
const rawCallResults = await this._samplerContract
.batchCall(callDatas.filter(cd => cd !== '0x'))
.batchCall(callDatas.filter(cd => cd !== NULL_BYTES))
.callAsync({ overrides }, block);
// Return the parsed results.
let rawCallResultsIdx = 0;
return Promise.all(
callDatas.map(async (callData, i) => {
if (callData !== '0x') {
return ops[i].handleCallResultsAsync(this._samplerContract, rawCallResults[rawCallResultsIdx++]);
}
return ops[i].handleCallResultsAsync(this._samplerContract, '0x');
const result = callData !== NULL_BYTES ? rawCallResults[rawCallResultsIdx++] : NULL_BYTES;
return ops[i].handleCallResultsAsync(this._samplerContract, result);
}),
);
}

View File

@ -3,6 +3,7 @@ import * as _ from 'lodash';
import { BigNumber, ERC20BridgeSource, SignedOrder } from '../..';
import { BalancerPool, BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
import { NULL_BYTES, ZERO_AMOUNT } from './constants';
import { getCurveInfosForPair } from './curve_utils';
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
import {
@ -20,11 +21,11 @@ import {
* for use with `DexOrderSampler.executeAsync()`.
*/
export const samplerOperations = {
getOrderFillableTakerAmounts(orders: SignedOrder[], devUtilsAddress: string): BatchedOperation<BigNumber[]> {
getOrderFillableTakerAmounts(orders: SignedOrder[], exchangeAddress: string): BatchedOperation<BigNumber[]> {
return {
encodeCall: contract => {
return contract
.getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature), devUtilsAddress)
.getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature), exchangeAddress)
.getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
@ -32,11 +33,11 @@ export const samplerOperations = {
},
};
},
getOrderFillableMakerAmounts(orders: SignedOrder[], devUtilsAddress: string): BatchedOperation<BigNumber[]> {
getOrderFillableMakerAmounts(orders: SignedOrder[], exchangeAddress: string): BatchedOperation<BigNumber[]> {
return {
encodeCall: contract => {
return contract
.getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature), devUtilsAddress)
.getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature), exchangeAddress)
.getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
@ -301,6 +302,32 @@ export const samplerOperations = {
...samplerOperations.constant(makerFillAmounts.map(amount => computeBalancerBuyQuote(pool, amount))),
};
},
getMStableSellQuotes(makerToken: string, takerToken: string, takerFillAmounts: BigNumber[]): SourceQuoteOperation {
return {
source: ERC20BridgeSource.MStable,
encodeCall: contract => {
return contract
.sampleSellsFromMStable(makerToken, takerToken, takerFillAmounts)
.getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromMStable', callResults);
},
};
},
getMStableBuyQuotes(makerToken: string, takerToken: string, makerFillAmounts: BigNumber[]): SourceQuoteOperation {
return {
source: ERC20BridgeSource.MStable,
encodeCall: contract => {
return contract
.sampleBuysFromMStable(makerToken, takerToken, makerFillAmounts)
.getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
return contract.getABIDecodedReturnData<BigNumber[]>('sampleBuysFromMStable', callResults);
},
};
},
getMedianSellRateAsync: async (
sources: ERC20BridgeSource[],
makerToken: string,
@ -326,21 +353,29 @@ export const samplerOperations = {
);
return {
encodeCall: contract => {
const encodedCall = getSellQuotes.encodeCall(contract);
// All soures were excluded
if (encodedCall === NULL_BYTES) {
return NULL_BYTES;
}
const subCalls = [getSellQuotes.encodeCall(contract)];
return contract.batchCall(subCalls).getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
if (callResults === NULL_BYTES) {
return ZERO_AMOUNT;
}
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
const samples = await getSellQuotes.handleCallResultsAsync(contract, rawSubCallResults[0]);
if (samples.length === 0) {
return new BigNumber(0);
return ZERO_AMOUNT;
}
const flatSortedSamples = samples
.reduce((acc, v) => acc.concat(...v))
.filter(v => !v.output.isZero())
.sort((a, b) => a.output.comparedTo(b.output));
if (flatSortedSamples.length === 0) {
return new BigNumber(0);
return ZERO_AMOUNT;
}
const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)];
return medianSample.output.div(medianSample.input);
@ -350,7 +385,7 @@ export const samplerOperations = {
constant<T>(result: T): BatchedOperation<T> {
return {
encodeCall: _contract => {
return '0x';
return NULL_BYTES;
},
handleCallResultsAsync: async (_contract, _callResults) => {
return result;
@ -456,6 +491,8 @@ export const samplerOperations = {
return pools.map(pool =>
samplerOperations.getBalancerSellQuotes(pool, takerFillAmounts),
);
case ERC20BridgeSource.MStable:
return samplerOperations.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts);
default:
throw new Error(`Unsupported sell sample source: ${source}`);
}
@ -467,17 +504,27 @@ export const samplerOperations = {
const nonSamplerOps = subOps.filter(op => op.source === ERC20BridgeSource.Balancer);
return {
encodeCall: contract => {
// All operations are NOOPs
if (samplerOps.length === 0) {
return NULL_BYTES;
}
const subCalls = samplerOps.map(op => op.encodeCall(contract));
return contract.batchCall(subCalls).getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
let samples = await Promise.all(
samplerOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
);
samples = samples.concat(
await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))),
);
let samples: BigNumber[][];
// If all operations were NOOPs then just call the handle result callback
if (callResults === NULL_BYTES && samplerOps.length === 0) {
samples = await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, '')));
} else {
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
samples = await Promise.all(
samplerOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
);
samples = samples.concat(
await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))),
);
}
return [...samplerOps, ...nonSamplerOps].map((op, i) => {
return samples[i].map((output, j) => ({
source: op.source,
@ -553,6 +600,8 @@ export const samplerOperations = {
return pools.map(pool =>
samplerOperations.getBalancerBuyQuotes(pool, makerFillAmounts),
);
case ERC20BridgeSource.MStable:
return samplerOperations.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts);
default:
throw new Error(`Unsupported buy sample source: ${source}`);
}
@ -564,17 +613,26 @@ export const samplerOperations = {
const nonSamplerOps = subOps.filter(op => op.source === ERC20BridgeSource.Balancer);
return {
encodeCall: contract => {
// All operations are NOOPs
if (samplerOps.length === 0) {
return NULL_BYTES;
}
const subCalls = samplerOps.map(op => op.encodeCall(contract));
return contract.batchCall(subCalls).getABIEncodedTransactionData();
},
handleCallResultsAsync: async (contract, callResults) => {
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
let samples = await Promise.all(
samplerOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
);
samples = samples.concat(
await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))),
);
let samples: BigNumber[][];
if (callResults === NULL_BYTES && samplerOps.length === 0) {
samples = await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, '')));
} else {
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
samples = await Promise.all(
samplerOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
);
samples = samples.concat(
await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))),
);
}
return [...samplerOps, ...nonSamplerOps].map((op, i) => {
return samples[i].map((output, j) => ({
source: op.source,

View File

@ -1,10 +1,10 @@
import { ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
import { RFQTIndicativeQuote } from '@0x/quote-server';
import { MarketOperation, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { RfqtRequestOpts, SignedOrderWithFillableAmounts } from '../../types';
import { QuoteRequestor } from '../../utils/quote_requestor';
import { ERC20BridgeSamplerContract } from '../../wrappers';
import { QuoteReport } from '../quote_report_generator';
/**
@ -38,6 +38,7 @@ export enum ERC20BridgeSource {
LiquidityProvider = 'LiquidityProvider',
MultiBridge = 'MultiBridge',
Balancer = 'Balancer',
MStable = 'mStable',
}
// tslint:disable: enum-naming

View File

@ -12,7 +12,6 @@ import * as DummyLiquidityProviderRegistry from '../test/generated-artifacts/Dum
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
import * as ICurve from '../test/generated-artifacts/ICurve.json';
import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberHintHandler from '../test/generated-artifacts/IKyberHintHandler.json';
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
@ -20,15 +19,18 @@ import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkPr
import * as IKyberStorage from '../test/generated-artifacts/IKyberStorage.json';
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
import * as IMStable from '../test/generated-artifacts/IMStable.json';
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
import * as KyberSampler from '../test/generated-artifacts/KyberSampler.json';
import * as LiquidityProviderSampler from '../test/generated-artifacts/LiquidityProviderSampler.json';
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json';
import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json';
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json';
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.json';
export const artifacts = {
@ -39,7 +41,6 @@ export const artifacts = {
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
ICurve: ICurve as ContractArtifact,
IDevUtils: IDevUtils as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberHintHandler: IKyberHintHandler as ContractArtifact,
IKyberNetwork: IKyberNetwork as ContractArtifact,
@ -47,15 +48,18 @@ export const artifacts = {
IKyberStorage: IKyberStorage as ContractArtifact,
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
IMStable: IMStable as ContractArtifact,
IMultiBridge: IMultiBridge as ContractArtifact,
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
KyberSampler: KyberSampler as ContractArtifact,
LiquidityProviderSampler: LiquidityProviderSampler as ContractArtifact,
MStableSampler: MStableSampler as ContractArtifact,
MultiBridgeSampler: MultiBridgeSampler as ContractArtifact,
NativeOrderSampler: NativeOrderSampler as ContractArtifact,
SamplerUtils: SamplerUtils as ContractArtifact,
UniswapSampler: UniswapSampler as ContractArtifact,
UniswapV2Sampler: UniswapV2Sampler as ContractArtifact,
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
};

View File

@ -1,10 +1,14 @@
import { artifacts, ERC20BridgeSamplerContract } from '@0x/contracts-erc20-bridge-sampler';
import { blockchainTests, describe, expect, toBaseUnitAmount, Web3ProviderEngine } from '@0x/contracts-test-utils';
import { RPCSubprovider } from '@0x/subproviders';
import { BigNumber, providerUtils } from '@0x/utils';
import { artifacts } from '../artifacts';
import { ERC20BridgeSamplerContract } from '../wrappers';
export const VB = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b';
// tslint:disable: custom-no-magic-numbers
blockchainTests.skip('Mainnet Sampler Tests', env => {
let testContract: ERC20BridgeSamplerContract;
const fakeSamplerAddress = '0x1111111111111111111111111111111111111111';

View File

@ -10,12 +10,16 @@ import { Order } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { artifacts } from '../artifacts';
import {
DummyLiquidityProviderContract,
DummyLiquidityProviderRegistryContract,
TestERC20BridgeSamplerContract,
} from './wrappers';
} from '../wrappers';
// tslint:disable: custom-no-magic-numbers
const { NULL_ADDRESS } = constants;
blockchainTests('erc20-bridge-sampler', env => {
let testContract: TestERC20BridgeSamplerContract;
@ -33,7 +37,6 @@ blockchainTests('erc20-bridge-sampler', env => {
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
let devUtilsAddress: string;
before(async () => {
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
@ -42,8 +45,6 @@ blockchainTests('erc20-bridge-sampler', env => {
env.txDefaults,
{},
);
// TestERC20BridgeSampler stubs DevUtils
devUtilsAddress = testContract.address;
});
function getPackedHash(...args: string[]): string {
@ -209,12 +210,7 @@ blockchainTests('erc20-bridge-sampler', env => {
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
const hash = getPackedHash(hexUtils.leftPad(order.salt));
const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
if (orderStatus !== 3 || !isValidSignature) {
return constants.ZERO_AMOUNT;
}
return order.takerAssetAmount.minus(new BigNumber(hash).mod(order.takerAssetAmount));
return new BigNumber(hash).mod(order.takerAssetAmount);
}
function getDeterministicFillableMakerAssetAmount(order: Order): BigNumber {
@ -272,44 +268,15 @@ blockchainTests('erc20-bridge-sampler', env => {
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
const actual = await testContract
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
.getOrderFillableTakerAssetAmounts(orders, signatures, NULL_ADDRESS)
.callAsync();
expect(actual).to.deep.eq(expected);
});
it('returns empty for no orders', async () => {
const actual = await testContract.getOrderFillableTakerAssetAmounts([], [], devUtilsAddress).callAsync();
const actual = await testContract.getOrderFillableTakerAssetAmounts([], [], NULL_ADDRESS).callAsync();
expect(actual).to.deep.eq([]);
});
it('returns zero for an order with zero maker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
.callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with zero taker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
.callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with an empty signature', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
const actual = await testContract
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
.callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
});
describe('getOrderFillableMakerAssetAmounts()', () => {
@ -318,44 +285,15 @@ blockchainTests('erc20-bridge-sampler', env => {
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
const actual = await testContract
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
.getOrderFillableMakerAssetAmounts(orders, signatures, NULL_ADDRESS)
.callAsync();
expect(actual).to.deep.eq(expected);
});
it('returns empty for no orders', async () => {
const actual = await testContract.getOrderFillableMakerAssetAmounts([], [], devUtilsAddress).callAsync();
const actual = await testContract.getOrderFillableMakerAssetAmounts([], [], NULL_ADDRESS).callAsync();
expect(actual).to.deep.eq([]);
});
it('returns zero for an order with zero maker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
.callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with zero taker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
const actual = await testContract
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
.callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with an empty signature', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
const actual = await testContract
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
.callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
});
blockchainTests.resets('sampleSellsFromKyberNetwork()', () => {
@ -1036,7 +974,7 @@ blockchainTests('erc20-bridge-sampler', env => {
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
const calls = [
testContract
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
.getOrderFillableTakerAssetAmounts(orders, signatures, NULL_ADDRESS)
.getABIEncodedTransactionData(),
];
const r = await testContract.batchCall(calls).callAsync();
@ -1055,10 +993,10 @@ blockchainTests('erc20-bridge-sampler', env => {
];
const calls = [
testContract
.getOrderFillableTakerAssetAmounts(orders[0], signatures, devUtilsAddress)
.getOrderFillableTakerAssetAmounts(orders[0], signatures, NULL_ADDRESS)
.getABIEncodedTransactionData(),
testContract
.getOrderFillableMakerAssetAmounts(orders[1], signatures, devUtilsAddress)
.getOrderFillableMakerAssetAmounts(orders[1], signatures, NULL_ADDRESS)
.getABIEncodedTransactionData(),
];
const r = await testContract.batchCall(calls).callAsync();
@ -1081,7 +1019,7 @@ blockchainTests('erc20-bridge-sampler', env => {
testContract
.batchCall([
testContract
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
.getOrderFillableTakerAssetAmounts(orders, signatures, NULL_ADDRESS)
.getABIEncodedTransactionData(),
])
.getABIEncodedTransactionData(),

View File

@ -0,0 +1,313 @@
import {
assertIntegerRoughlyEquals,
blockchainTests,
constants,
expect,
getRandomInteger,
randomAddress,
} from '@0x/contracts-test-utils';
import { Order } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import * as _ from 'lodash';
import { artifacts } from '../artifacts';
import { TestNativeOrderSamplerContract } from '../wrappers';
const { NULL_BYTES, ZERO_AMOUNT } = constants;
// tslint:disable: custom-no-magic-numbers
blockchainTests.resets('NativeOrderSampler contract', env => {
let testContract: TestNativeOrderSamplerContract;
let makerToken: string;
let takerToken: string;
let feeToken: string;
let erc20Proxy: string;
const ERC20_PROXY_ID = '0xf47261b0';
const VALID_SIGNATURE = '0x01';
const INVALID_SIGNATURE = '0x00';
before(async () => {
testContract = await TestNativeOrderSamplerContract.deployFrom0xArtifactAsync(
artifacts.TestNativeOrderSampler,
env.provider,
env.txDefaults,
{},
);
erc20Proxy = await testContract.getAssetProxy(ERC20_PROXY_ID).callAsync();
const NUM_TOKENS = new BigNumber(3);
[makerToken, takerToken, feeToken] = await testContract.createTokens(NUM_TOKENS).callAsync();
await testContract.createTokens(NUM_TOKENS).awaitTransactionSuccessAsync();
});
function getPackedHash(...args: string[]): string {
return hexUtils.hash(hexUtils.concat(...args.map(a => hexUtils.toHex(a))));
}
interface OrderInfo {
orderHash: string;
orderStatus: number;
orderTakerAssetFilledAmount: BigNumber;
}
function getOrderInfo(order: Order): OrderInfo {
const hash = getPackedHash(hexUtils.leftPad(order.salt));
const orderStatus = order.salt.mod(255).eq(0) ? 3 : 5;
const filledAmount = order.expirationTimeSeconds;
return {
orderStatus,
orderHash: hash,
orderTakerAssetFilledAmount: filledAmount,
};
}
function createFillableOrderSalt(): BigNumber {
return new BigNumber(hexUtils.concat(hexUtils.slice(hexUtils.random(), 0, -1), '0x01'));
}
function createUnfillableOrderSalt(): BigNumber {
return new BigNumber(hexUtils.concat(hexUtils.slice(hexUtils.random(), 0, -1), '0xff'));
}
function getOrderFillableTakerAmount(order: Order): BigNumber {
return order.takerAssetAmount.minus(getOrderInfo(order).orderTakerAssetFilledAmount);
}
function getERC20AssetData(tokenAddress: string): string {
return hexUtils.concat(ERC20_PROXY_ID, hexUtils.leftPad(tokenAddress));
}
function createOrder(fields: Partial<Order> = {}, filledTakerAssetAmount: BigNumber = ZERO_AMOUNT): Order {
return {
chainId: 1337,
exchangeAddress: randomAddress(),
makerAddress: randomAddress(),
takerAddress: randomAddress(),
senderAddress: randomAddress(),
feeRecipientAddress: randomAddress(),
makerAssetAmount: getRandomInteger(1e18, 10e18),
takerAssetAmount: getRandomInteger(1e18, 10e18),
makerFee: getRandomInteger(1e18, 10e18),
takerFee: getRandomInteger(1e18, 10e18),
makerAssetData: getERC20AssetData(makerToken),
takerAssetData: getERC20AssetData(takerToken),
makerFeeAssetData: getERC20AssetData(feeToken),
takerFeeAssetData: getERC20AssetData(randomAddress()),
salt: createFillableOrderSalt(),
// Expiration time will be used to determine filled amount.
expirationTimeSeconds: filledTakerAssetAmount,
...fields,
};
}
async function fundMakerAsync(
order: Order,
assetData: string,
balanceScaling: number = 1,
allowanceScaling: number = 1,
): Promise<void> {
let token;
let amount;
if (assetData === order.makerAssetData) {
token = makerToken;
amount =
order.makerAssetData === order.makerFeeAssetData
? order.makerAssetAmount.plus(order.makerFee)
: order.makerAssetAmount;
} else {
token = feeToken;
amount = order.makerFee;
}
amount = amount.times(getOrderFillableTakerAmount(order).div(BigNumber.max(1, order.takerAssetAmount)));
await testContract
.setTokenBalanceAndAllowance(
token,
order.makerAddress,
erc20Proxy,
amount.times(balanceScaling).integerValue(),
amount.times(allowanceScaling).integerValue(),
)
.awaitTransactionSuccessAsync();
}
describe('getOrderFillableTakerAmount()', () => {
it('returns the full amount for a fully funded order', async () => {
const order = createOrder();
const expected = getOrderFillableTakerAmount(order);
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(actual).to.bignumber.eq(expected);
});
it('returns the full amount for a fully funded order without maker fees', async () => {
const order = createOrder({ makerFee: ZERO_AMOUNT });
const expected = getOrderFillableTakerAmount(order);
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(actual).to.bignumber.eq(expected);
});
it('returns the full amount for a fully funded order without maker fee asset data', async () => {
const order = createOrder({ makerFeeAssetData: NULL_BYTES });
const expected = getOrderFillableTakerAmount(order);
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(actual).to.bignumber.eq(expected);
});
it('returns the full amount for a fully funded order with maker fees denominated in the maker asset', async () => {
const order = createOrder({ makerFeeAssetData: getERC20AssetData(makerToken) });
const expected = getOrderFillableTakerAmount(order);
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(actual).to.bignumber.eq(expected);
});
it('returns partial amount with insufficient maker asset balance', async () => {
const order = createOrder();
const expected = getOrderFillableTakerAmount(order)
.times(0.5)
.integerValue(BigNumber.ROUND_DOWN);
await fundMakerAsync(order, order.makerAssetData, 0.5);
await fundMakerAsync(order, order.makerFeeAssetData);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
assertIntegerRoughlyEquals(actual, expected, 100);
});
it('returns partial amount with insufficient maker asset allowance', async () => {
const order = createOrder();
const expected = getOrderFillableTakerAmount(order)
.times(0.5)
.integerValue(BigNumber.ROUND_DOWN);
await fundMakerAsync(order, order.makerAssetData, 1, 0.5);
await fundMakerAsync(order, order.makerFeeAssetData);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
assertIntegerRoughlyEquals(actual, expected, 100);
});
it('returns partial amount with insufficient maker fee asset balance', async () => {
const order = createOrder();
const expected = getOrderFillableTakerAmount(order)
.times(0.5)
.integerValue(BigNumber.ROUND_DOWN);
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData, 0.5);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
assertIntegerRoughlyEquals(actual, expected, 100);
});
it('returns partial amount with insufficient maker fee asset allowance', async () => {
const order = createOrder();
const expected = getOrderFillableTakerAmount(order)
.times(0.5)
.integerValue(BigNumber.ROUND_DOWN);
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData, 1, 0.5);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
assertIntegerRoughlyEquals(actual, expected, 100);
});
it('returns partial amount with insufficient maker asset balance (maker asset fees)', async () => {
const order = createOrder({ makerFeeAssetData: getERC20AssetData(makerToken) });
const expected = getOrderFillableTakerAmount(order)
.times(0.5)
.integerValue(BigNumber.ROUND_DOWN);
await fundMakerAsync(order, order.makerAssetData, 0.5);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
assertIntegerRoughlyEquals(actual, expected, 100);
});
it('returns partial amount with insufficient maker asset allowance (maker asset fees)', async () => {
const order = createOrder({ makerFeeAssetData: getERC20AssetData(makerToken) });
const expected = getOrderFillableTakerAmount(order)
.times(0.5)
.integerValue(BigNumber.ROUND_DOWN);
await fundMakerAsync(order, order.makerAssetData, 1, 0.5);
const actual = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
assertIntegerRoughlyEquals(actual, expected, 100);
});
it('returns zero for an that is not fillable', async () => {
const order = {
...createOrder(),
salt: createUnfillableOrderSalt(),
};
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const fillableTakerAmount = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
});
it('returns zero for an order with zero maker asset amount', async () => {
const order = {
...createOrder(),
makerAssetAmount: ZERO_AMOUNT,
};
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const fillableTakerAmount = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
});
it('returns zero for an order with zero taker asset amount', async () => {
const order = {
...createOrder(),
takerAssetAmount: ZERO_AMOUNT,
};
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const fillableTakerAmount = await testContract
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
.callAsync();
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
});
it('returns zero for an order with an empty signature', async () => {
const order = createOrder();
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const fillableTakerAmount = await testContract
.getOrderFillableTakerAmount(order, NULL_BYTES, testContract.address)
.callAsync();
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
});
it('returns zero for an order with an invalid signature', async () => {
const order = createOrder();
await fundMakerAsync(order, order.makerAssetData);
await fundMakerAsync(order, order.makerFeeAssetData);
const fillableTakerAmount = await testContract
.getOrderFillableTakerAmount(order, INVALID_SIGNATURE, testContract.address)
.callAsync();
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
});
});
});

View File

@ -32,7 +32,7 @@ describe('DexSampler tests', () => {
const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
const devUtilsAddress = getContractAddressesForChainOrThrow(CHAIN_ID).devUtils;
const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange;
describe('getSampleAmounts()', () => {
const FILL_AMOUNT = getRandomInteger(1, 1e18);
@ -106,7 +106,7 @@ describe('DexSampler tests', () => {
});
const dexOrderSampler = new DexOrderSampler(sampler);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, devUtilsAddress),
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, exchangeAddress),
);
expect(fillableAmounts).to.deep.eq(expectedFillableAmounts);
});
@ -122,7 +122,7 @@ describe('DexSampler tests', () => {
});
const dexOrderSampler = new DexOrderSampler(sampler);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, devUtilsAddress),
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, exchangeAddress),
);
expect(fillableAmounts).to.deep.eq(expectedFillableAmounts);
});
@ -632,8 +632,8 @@ describe('DexSampler tests', () => {
});
const dexOrderSampler = new DexOrderSampler(sampler);
const [fillableMakerAmounts, fillableTakerAmounts] = await dexOrderSampler.executeAsync(
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, devUtilsAddress),
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, devUtilsAddress),
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, exchangeAddress),
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, exchangeAddress),
);
expect(fillableMakerAmounts).to.deep.eq(expectedFillableMakerAmounts);
expect(fillableTakerAmounts).to.deep.eq(expectedFillableTakerAmounts);

View File

@ -31,11 +31,6 @@ const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
describe('MarketOperationUtils tests', () => {
const CHAIN_ID = 1;
const contractAddresses = { ...getContractAddressesForChainOrThrow(CHAIN_ID), multiBridge: NULL_ADDRESS };
const ETH2DAI_BRIDGE_ADDRESS = contractAddresses.eth2DaiBridge;
const KYBER_BRIDGE_ADDRESS = contractAddresses.kyberBridge;
const UNISWAP_BRIDGE_ADDRESS = contractAddresses.uniswapBridge;
const UNISWAP_V2_BRIDGE_ADDRESS = contractAddresses.uniswapV2Bridge;
const CURVE_BRIDGE_ADDRESS = contractAddresses.curveBridge;
let originalSamplerOperations: any;
before(() => {
@ -79,16 +74,18 @@ describe('MarketOperationUtils tests', () => {
}
const { bridgeAddress } = bridgeData;
switch (bridgeAddress) {
case KYBER_BRIDGE_ADDRESS.toLowerCase():
case contractAddresses.kyberBridge.toLowerCase():
return ERC20BridgeSource.Kyber;
case ETH2DAI_BRIDGE_ADDRESS.toLowerCase():
case contractAddresses.eth2DaiBridge.toLowerCase():
return ERC20BridgeSource.Eth2Dai;
case UNISWAP_BRIDGE_ADDRESS.toLowerCase():
case contractAddresses.uniswapBridge.toLowerCase():
return ERC20BridgeSource.Uniswap;
case UNISWAP_V2_BRIDGE_ADDRESS.toLowerCase():
case contractAddresses.uniswapV2Bridge.toLowerCase():
return ERC20BridgeSource.UniswapV2;
case CURVE_BRIDGE_ADDRESS.toLowerCase():
case contractAddresses.curveBridge.toLowerCase():
return ERC20BridgeSource.Curve;
case contractAddresses.mStableBridge.toLowerCase():
return ERC20BridgeSource.MStable;
default:
break;
}
@ -294,6 +291,7 @@ describe('MarketOperationUtils tests', () => {
[ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0),
};
interface FillDataBySource {
@ -425,7 +423,12 @@ describe('MarketOperationUtils tests', () => {
sampleDistributionBase: 1,
bridgeSlippage: 0,
maxFallbackSlippage: 100,
excludedSources: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.Curve, ERC20BridgeSource.Balancer],
excludedSources: [
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Curve,
ERC20BridgeSource.Balancer,
ERC20BridgeSource.MStable,
],
allowFallback: false,
shouldBatchBridgeOrders: false,
};
@ -462,7 +465,7 @@ describe('MarketOperationUtils tests', () => {
...DEFAULT_OPTS,
excludedSources: [],
});
expect(sourcesPolled.sort()).to.deep.eq(SELL_SOURCES.slice().sort());
expect(sourcesPolled.sort()).to.deep.equals(SELL_SOURCES.slice().sort());
});
it('polls the liquidity provider when the registry is provided in the arguments', async () => {
@ -484,7 +487,7 @@ describe('MarketOperationUtils tests', () => {
...DEFAULT_OPTS,
excludedSources: [],
});
expect(args.sources.sort()).to.deep.eq(
expect(args.sources.sort()).to.deep.equals(
SELL_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(),
);
expect(args.liquidityProviderAddress).to.eql(registryAddress);
@ -503,7 +506,7 @@ describe('MarketOperationUtils tests', () => {
...DEFAULT_OPTS,
excludedSources,
});
expect(sourcesPolled.sort()).to.deep.eq(_.without(SELL_SOURCES, ...excludedSources).sort());
expect(sourcesPolled.sort()).to.deep.equals(_.without(SELL_SOURCES, ...excludedSources).sort());
});
it('generates bridge orders with correct asset data', async () => {
@ -836,6 +839,7 @@ describe('MarketOperationUtils tests', () => {
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Curve,
ERC20BridgeSource.Balancer,
ERC20BridgeSource.MStable,
],
allowFallback: false,
shouldBatchBridgeOrders: false,
@ -873,7 +877,7 @@ describe('MarketOperationUtils tests', () => {
...DEFAULT_OPTS,
excludedSources: [],
});
expect(sourcesPolled).to.deep.eq(BUY_SOURCES);
expect(sourcesPolled.sort()).to.deep.equals(BUY_SOURCES.sort());
});
it('polls the liquidity provider when the registry is provided in the arguments', async () => {
@ -914,7 +918,7 @@ describe('MarketOperationUtils tests', () => {
...DEFAULT_OPTS,
excludedSources,
});
expect(sourcesPolled).to.deep.eq(_.without(BUY_SOURCES, ...excludedSources));
expect(sourcesPolled.sort()).to.deep.eq(_.without(BUY_SOURCES, ...excludedSources).sort());
});
it('generates bridge orders with correct asset data', async () => {

View File

@ -1,9 +1,10 @@
import { ContractFunctionObj } from '@0x/base-contract';
import { ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
import { constants } from '@0x/contracts-test-utils';
import { Order } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import { ERC20BridgeSamplerContract } from '../../src/wrappers';
export type GetOrderFillableAssetAmountResult = BigNumber[];
export type GetOrderFillableAssetAmountHandler = (
orders: Order[],
@ -59,6 +60,8 @@ interface Handlers {
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
}
// tslint:disable: no-unbound-method
export class MockSamplerContract extends ERC20BridgeSamplerContract {
private readonly _handlers: Partial<Handlers> = {};

View File

@ -10,7 +10,6 @@ export * from '../test/generated-wrappers/dummy_liquidity_provider_registry';
export * from '../test/generated-wrappers/erc20_bridge_sampler';
export * from '../test/generated-wrappers/eth2_dai_sampler';
export * from '../test/generated-wrappers/i_curve';
export * from '../test/generated-wrappers/i_dev_utils';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_hint_handler';
export * from '../test/generated-wrappers/i_kyber_network';
@ -18,14 +17,17 @@ export * from '../test/generated-wrappers/i_kyber_network_proxy';
export * from '../test/generated-wrappers/i_kyber_storage';
export * from '../test/generated-wrappers/i_liquidity_provider';
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
export * from '../test/generated-wrappers/i_m_stable';
export * from '../test/generated-wrappers/i_multi_bridge';
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
export * from '../test/generated-wrappers/kyber_sampler';
export * from '../test/generated-wrappers/liquidity_provider_sampler';
export * from '../test/generated-wrappers/m_stable_sampler';
export * from '../test/generated-wrappers/multi_bridge_sampler';
export * from '../test/generated-wrappers/native_order_sampler';
export * from '../test/generated-wrappers/sampler_utils';
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
export * from '../test/generated-wrappers/test_native_order_sampler';
export * from '../test/generated-wrappers/uniswap_sampler';
export * from '../test/generated-wrappers/uniswap_v2_sampler';

View File

@ -1,8 +1,40 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": "."
},
"include": ["./src/**/*", "./test/**/*"]
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/DummyLiquidityProvider.json",
"generated-artifacts/DummyLiquidityProviderRegistry.json",
"generated-artifacts/ERC20BridgeSampler.json",
"generated-artifacts/ILiquidityProvider.json",
"generated-artifacts/ILiquidityProviderRegistry.json",
"test/generated-artifacts/ApproximateBuys.json",
"test/generated-artifacts/CurveSampler.json",
"test/generated-artifacts/DummyLiquidityProvider.json",
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
"test/generated-artifacts/ERC20BridgeSampler.json",
"test/generated-artifacts/Eth2DaiSampler.json",
"test/generated-artifacts/ICurve.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberHintHandler.json",
"test/generated-artifacts/IKyberNetwork.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/IKyberStorage.json",
"test/generated-artifacts/ILiquidityProvider.json",
"test/generated-artifacts/ILiquidityProviderRegistry.json",
"test/generated-artifacts/IMStable.json",
"test/generated-artifacts/IMultiBridge.json",
"test/generated-artifacts/IUniswapExchangeQuotes.json",
"test/generated-artifacts/IUniswapV2Router01.json",
"test/generated-artifacts/KyberSampler.json",
"test/generated-artifacts/LiquidityProviderSampler.json",
"test/generated-artifacts/MStableSampler.json",
"test/generated-artifacts/MultiBridgeSampler.json",
"test/generated-artifacts/NativeOrderSampler.json",
"test/generated-artifacts/SamplerUtils.json",
"test/generated-artifacts/TestERC20BridgeSampler.json",
"test/generated-artifacts/TestNativeOrderSampler.json",
"test/generated-artifacts/UniswapSampler.json",
"test/generated-artifacts/UniswapV2Sampler.json"
]
}

Some files were not shown because too many files have changed in this diff Show More