Compare commits
33 Commits
@0x/typesc
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
4a133ca36f | ||
|
f7252f919a | ||
|
e05a03a842 | ||
|
dcce8276b8 | ||
|
fd47947e55 | ||
|
ae151df2eb | ||
|
79de188683 | ||
|
6e5c788e13 | ||
|
f53606007d | ||
|
a4ac418bc9 | ||
|
a8c09d0bdb | ||
|
871105a48a | ||
|
3b61129ade | ||
|
f471c79b59 | ||
|
dfd9443f74 | ||
|
a36ff9e365 | ||
|
12e65bbf26 | ||
|
ab9841e60b | ||
|
7a52f12e57 | ||
|
11fd4506ac | ||
|
0c9c68030e | ||
|
55d6eddbb2 | ||
|
8341e60edb | ||
|
6273a1ca73 | ||
|
1b83ebdf89 | ||
|
fef7f0506f | ||
|
f44eb4e383 | ||
|
05df485c4a | ||
|
44857c526b | ||
|
b8ad5d5d32 | ||
|
e3e0d00e21 | ||
|
a9b1ea9690 | ||
|
8e5dd0f8d9 |
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "3.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.2.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.0 - _February 8, 2020_
|
||||
|
||||
* Fix broken tests. (#2462)
|
||||
|
108
contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
Normal file
108
contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
Normal file
@@ -0,0 +1,108 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@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/ICurve.sol";
|
||||
|
||||
|
||||
// solhint-disable not-rely-on-time
|
||||
// solhint-disable space-after-comma
|
||||
contract CurveBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
/// @dev Callback for `ICurve`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
|
||||
/// (DAI, USDC) to the Curve contract, then transfers the bought
|
||||
/// tokens to `to`.
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoeded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address /* from */,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
(address curveAddress, int128 fromCoinIdx, int128 toCoinIdx, int128 version) = abi.decode(bridgeData, (address, int128, int128, int128));
|
||||
ICurve exchange = ICurve(curveAddress);
|
||||
|
||||
address fromTokenAddress = exchange.underlying_coins(fromCoinIdx);
|
||||
require(toTokenAddress != fromTokenAddress, "CurveBridge/INVALID_PAIR");
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
if (version == 0) {
|
||||
exchange.exchange_underlying(
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
// dx
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
// min dy
|
||||
amount,
|
||||
// expires
|
||||
block.timestamp + 1
|
||||
);
|
||||
} else {
|
||||
exchange.exchange_underlying(
|
||||
fromCoinIdx,
|
||||
toCoinIdx,
|
||||
// dx
|
||||
IERC20Token(fromTokenAddress).balanceOf(address(this)),
|
||||
// min dy
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
|
||||
// Transfer the converted `toToken`s to `to`.
|
||||
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
|
||||
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;
|
||||
}
|
||||
}
|
87
contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
Normal file
87
contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
interface ICurve {
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// This function exists on early versions of Curve (USDC/DAI)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
/// @param minBuyAmount The minimum buy amount of the token being bought.
|
||||
/// @param deadline The time in seconds when this operation should expire.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount,
|
||||
uint256 deadline
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
/// @param minBuyAmount The minimum buy amount of the token being bought.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
function get_dy_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dy);
|
||||
|
||||
/// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param buyAmount The amount of token being bought.
|
||||
function get_dx_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 buyAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dx);
|
||||
|
||||
/// @dev Get the underlying token address from the token index
|
||||
/// @param i The token index.
|
||||
function underlying_coins(
|
||||
int128 i
|
||||
)
|
||||
external
|
||||
returns (address tokenAddress);
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -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/@(ChaiBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -53,8 +53,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
@@ -79,11 +79,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-erc1155": "^2.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-erc721": "^3.1.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/contracts-erc1155": "^2.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-erc721": "^3.1.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.0",
|
||||
|
@@ -6,6 +6,7 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
|
||||
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
|
||||
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
||||
@@ -17,6 +18,7 @@ import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
|
||||
import * as IChai from '../generated-artifacts/IChai.json';
|
||||
import * as ICurve from '../generated-artifacts/ICurve.json';
|
||||
import * as IDydx from '../generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
|
||||
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||
@@ -49,6 +51,7 @@ export const artifacts = {
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
@@ -58,6 +61,7 @@ export const artifacts = {
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDydx: IDydx as ContractArtifact,
|
||||
IDydxBridge: IDydxBridge as ContractArtifact,
|
||||
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/chai_bridge';
|
||||
export * from '../generated-wrappers/curve_bridge';
|
||||
export * from '../generated-wrappers/dydx_bridge';
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
export * from '../generated-wrappers/erc20_bridge_proxy';
|
||||
@@ -15,6 +16,7 @@ export * from '../generated-wrappers/i_asset_proxy';
|
||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/i_authorizable';
|
||||
export * from '../generated-wrappers/i_chai';
|
||||
export * from '../generated-wrappers/i_curve';
|
||||
export * from '../generated-wrappers/i_dydx';
|
||||
export * from '../generated-wrappers/i_dydx_bridge';
|
||||
export * from '../generated-wrappers/i_erc20_bridge';
|
||||
|
@@ -6,6 +6,7 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
|
||||
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
|
||||
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
|
||||
@@ -17,6 +18,7 @@ import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
|
||||
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
|
||||
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
|
||||
import * as IChai from '../test/generated-artifacts/IChai.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IDydx from '../test/generated-artifacts/IDydx.json';
|
||||
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json';
|
||||
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
|
||||
@@ -49,6 +51,7 @@ export const artifacts = {
|
||||
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
|
||||
StaticCallProxy: StaticCallProxy as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
@@ -58,6 +61,7 @@ export const artifacts = {
|
||||
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
|
||||
IAuthorizable: IAuthorizable as ContractArtifact,
|
||||
IChai: IChai as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDydx: IDydx as ContractArtifact,
|
||||
IDydxBridge: IDydxBridge as ContractArtifact,
|
||||
IERC20Bridge: IERC20Bridge as ContractArtifact,
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/chai_bridge';
|
||||
export * from '../test/generated-wrappers/curve_bridge';
|
||||
export * from '../test/generated-wrappers/dydx_bridge';
|
||||
export * from '../test/generated-wrappers/erc1155_proxy';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_proxy';
|
||||
@@ -15,6 +16,7 @@ export * from '../test/generated-wrappers/i_asset_proxy';
|
||||
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/i_authorizable';
|
||||
export * from '../test/generated-wrappers/i_chai';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_dydx';
|
||||
export * from '../test/generated-wrappers/i_dydx_bridge';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
|
@@ -4,6 +4,7 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/CurveBridge.json",
|
||||
"generated-artifacts/DydxBridge.json",
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
"generated-artifacts/ERC20BridgeProxy.json",
|
||||
@@ -15,6 +16,7 @@
|
||||
"generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"generated-artifacts/IAuthorizable.json",
|
||||
"generated-artifacts/IChai.json",
|
||||
"generated-artifacts/ICurve.json",
|
||||
"generated-artifacts/IDydx.json",
|
||||
"generated-artifacts/IDydxBridge.json",
|
||||
"generated-artifacts/IERC20Bridge.json",
|
||||
@@ -37,6 +39,7 @@
|
||||
"generated-artifacts/TestUniswapBridge.json",
|
||||
"generated-artifacts/UniswapBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/CurveBridge.json",
|
||||
"test/generated-artifacts/DydxBridge.json",
|
||||
"test/generated-artifacts/ERC1155Proxy.json",
|
||||
"test/generated-artifacts/ERC20BridgeProxy.json",
|
||||
@@ -48,6 +51,7 @@
|
||||
"test/generated-artifacts/IAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/IAuthorizable.json",
|
||||
"test/generated-artifacts/IChai.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IDydx.json",
|
||||
"test/generated-artifacts/IDydxBridge.json",
|
||||
"test/generated-artifacts/IERC20Bridge.json",
|
||||
|
@@ -1,4 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added decoders for broker data",
|
||||
"pr": 2484
|
||||
}
|
||||
],
|
||||
"timestamp": 1581748629
|
||||
},
|
||||
{
|
||||
"timestamp": 1581204851,
|
||||
"version": "1.0.2",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.0 - _February 15, 2020_
|
||||
|
||||
* Added decoders for broker data (#2484)
|
||||
|
||||
## v1.0.2 - _February 8, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-broker",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,14 +52,14 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-erc721": "^3.1.0",
|
||||
"@0x/contracts-exchange": "^3.2.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-erc721": "^3.1.1",
|
||||
"@0x/contracts-exchange": "^3.2.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
@@ -85,7 +85,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.0",
|
||||
"ethereum-types": "^3.1.0"
|
||||
|
@@ -1,42 +1,59 @@
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { ERC1155AssetData } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
export const godsUnchainedUtils = {
|
||||
/**
|
||||
* Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator.
|
||||
*/
|
||||
encodePropertyData(proto: BigNumber, quality: BigNumber): string {
|
||||
return AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]).encode({
|
||||
proto,
|
||||
quality,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData
|
||||
* of a property-based GodsUnchained order. Must also provide the addresses of the Broker,
|
||||
* GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies
|
||||
* how many cards are expected for each "unit" of the takerAssetAmount. For example, If the
|
||||
* takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards
|
||||
* with the given proto and quality to fill the order. If an odd number is provided, the fill fails.
|
||||
*/
|
||||
encodeBrokerAssetData(
|
||||
brokerAddress: string,
|
||||
godsUnchainedAddress: string,
|
||||
validatorAddress: string,
|
||||
proto: BigNumber,
|
||||
quality: BigNumber,
|
||||
bundleSize: number = 1,
|
||||
): string {
|
||||
const dataEncoder = AbiEncoder.create([
|
||||
{ name: 'godsUnchainedAddress', type: 'address' },
|
||||
{ name: 'validatorAddress', type: 'address' },
|
||||
{ name: 'propertyData', type: 'bytes' },
|
||||
]);
|
||||
const propertyData = AbiEncoder.create([
|
||||
{ name: 'proto', type: 'uint16' },
|
||||
{ name: 'quality', type: 'uint8' },
|
||||
]).encode({ proto, quality });
|
||||
const data = dataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData });
|
||||
return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], data);
|
||||
},
|
||||
};
|
||||
export interface GodsUnchainedProperties {
|
||||
proto: BigNumber | number;
|
||||
quality: BigNumber | number;
|
||||
}
|
||||
|
||||
const propertyDataEncoder = AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]);
|
||||
const brokerDataEncoder = AbiEncoder.create([
|
||||
{ name: 'godsUnchainedAddress', type: 'address' },
|
||||
{ name: 'validatorAddress', type: 'address' },
|
||||
{ name: 'propertyData', type: 'bytes' },
|
||||
]);
|
||||
|
||||
/**
|
||||
* Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator.
|
||||
*/
|
||||
export function encodePropertyData(properties: GodsUnchainedProperties): string {
|
||||
return propertyDataEncoder.encode(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData
|
||||
* of a property-based GodsUnchained order. Must also provide the addresses of the Broker,
|
||||
* GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies
|
||||
* how many cards are expected for each "unit" of the takerAssetAmount. For example, If the
|
||||
* takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards
|
||||
* with the given proto and quality to fill the order. If an odd number is provided, the fill fails.
|
||||
*/
|
||||
export function encodeBrokerAssetData(
|
||||
brokerAddress: string,
|
||||
godsUnchainedAddress: string,
|
||||
validatorAddress: string,
|
||||
properties: GodsUnchainedProperties,
|
||||
bundleSize: number = 1,
|
||||
): string {
|
||||
const propertyData = propertyDataEncoder.encode(properties);
|
||||
const brokerData = brokerDataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData });
|
||||
return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], brokerData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes proto and quality from the bytes format expected by the GodsUnchainedValidator.
|
||||
*/
|
||||
export function decodePropertyData(propertyData: string): GodsUnchainedProperties {
|
||||
return propertyDataEncoder.decode(propertyData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes proto and quality from the ERC1155 takerAssetData of a property-based GodsUnchained order.
|
||||
*/
|
||||
export function decodeBrokerAssetData(brokerAssetData: string): GodsUnchainedProperties {
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const { callbackData: brokerData } = assetDataUtils.decodeAssetDataOrThrow(brokerAssetData) as ERC1155AssetData;
|
||||
const { propertyData } = brokerDataEncoder.decode(brokerData);
|
||||
return decodePropertyData(propertyData);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
|
||||
export { godsUnchainedUtils } from './gods_unchained_utils';
|
||||
export * from './gods_unchained_utils';
|
||||
export { BrokerRevertErrors } from '@0x/utils';
|
||||
export {
|
||||
ContractArtifact,
|
||||
|
@@ -2,7 +2,7 @@ import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contra
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { godsUnchainedUtils } from '../src/gods_unchained_utils';
|
||||
import { encodePropertyData } from '../src/gods_unchained_utils';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
|
||||
@@ -33,7 +33,7 @@ blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
|
||||
describe('checkBrokerAsset', () => {
|
||||
const proto = new BigNumber(42);
|
||||
const quality = new BigNumber(7);
|
||||
const propertyData = godsUnchainedUtils.encodePropertyData(proto, quality);
|
||||
const propertyData = encodePropertyData({ proto, quality });
|
||||
|
||||
it('succeeds if assetData proto and quality match propertyData', async () => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "3.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.0 - _February 8, 2020_
|
||||
|
||||
* Update tests. (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,14 +53,14 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-exchange": "^3.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-dev-utils": "^1.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-exchange": "^3.2.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
@@ -86,8 +86,8 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.6",
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contract-addresses": "^4.5.0",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contract-addresses": "^4.6.0",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/json-schemas": "^5.0.6",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "1.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.1.0 - _February 8, 2020_
|
||||
|
||||
* Refactor mixins into public libraries. (#2464)
|
||||
|
@@ -118,22 +118,14 @@ contract OrderValidationUtils is
|
||||
transferableTakerAssetAmount
|
||||
);
|
||||
|
||||
// Execute the maker transfers.
|
||||
fillableTakerAssetAmount = LibOrderTransferSimulation.getSimulatedOrderMakerTransferResults(
|
||||
exchangeAddress,
|
||||
order,
|
||||
order.takerAddress,
|
||||
fillableTakerAssetAmount
|
||||
) == LibOrderTransferSimulation.OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
|
||||
|
||||
if (!_isAssetDataValid(order.takerAssetData)) {
|
||||
fillableTakerAssetAmount = 0;
|
||||
}
|
||||
|
||||
if (order.takerFee != 0 && !_isAssetDataValid(order.takerFeeAssetData)) {
|
||||
// Ensure that all of the asset data is valid. Fee asset data only needs
|
||||
// to be valid if the fees are nonzero.
|
||||
if (!_areOrderAssetDatasValid(order)) {
|
||||
fillableTakerAssetAmount = 0;
|
||||
}
|
||||
|
||||
// If the order is not fillable, then the fillable taker asset amount is
|
||||
// zero by definition.
|
||||
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
|
||||
fillableTakerAssetAmount = 0;
|
||||
}
|
||||
@@ -210,6 +202,21 @@ contract OrderValidationUtils is
|
||||
return transferableAssetAmount;
|
||||
}
|
||||
|
||||
/// @dev Checks that the asset data contained in a ZeroEx is valid and returns
|
||||
/// a boolean that indicates whether or not the asset data was found to be valid.
|
||||
/// @param order A ZeroEx order to validate.
|
||||
/// @return The validatity of the asset data.
|
||||
function _areOrderAssetDatasValid(LibOrder.Order memory order)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
return _isAssetDataValid(order.makerAssetData) &&
|
||||
(order.makerFee == 0 || _isAssetDataValid(order.makerFeeAssetData)) &&
|
||||
_isAssetDataValid(order.takerAssetData) &&
|
||||
(order.takerFee == 0 || _isAssetDataValid(order.takerFeeAssetData));
|
||||
}
|
||||
|
||||
/// @dev This function handles the edge cases around taker validation. This function
|
||||
/// currently attempts to find duplicate ERC721 token's in the taker
|
||||
/// multiAssetData.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -43,10 +43,10 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/assert": "^3.0.6",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "2.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.1.0 - _February 8, 2020_
|
||||
|
||||
* Fix broken tests (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,7 +54,7 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/utils": "^5.4.0",
|
||||
"@0x/web3-wrapper": "^7.0.6",
|
||||
"lodash": "^4.17.11"
|
||||
|
@@ -1,10 +1,24 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
|
@@ -5,9 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## 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_
|
||||
|
||||
|
@@ -21,7 +21,6 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFactory.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.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/DeploymentConstants.sol";
|
||||
@@ -30,160 +29,46 @@ import "./IERC20BridgeSampler.sol";
|
||||
import "./IEth2Dai.sol";
|
||||
import "./IKyberNetwork.sol";
|
||||
import "./IUniswapExchangeQuotes.sol";
|
||||
import "./ICurve.sol";
|
||||
|
||||
|
||||
contract ERC20BridgeSampler is
|
||||
IERC20BridgeSampler,
|
||||
DeploymentConstants
|
||||
{
|
||||
bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)"));
|
||||
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 1500e3;
|
||||
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
|
||||
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 1000e3;
|
||||
uint256 constant internal DEV_UTILS_CALL_GAS = 500e3;
|
||||
address constant private UNISWAP_SOURCE = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||
address constant private ETH2DAI_SOURCE = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||
address constant private KYBER_SOURCE = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
|
||||
/// @dev Gas limit for DevUtils calls.
|
||||
uint256 constant internal DEV_UTILS_CALL_GAS = 500e3; // 500k
|
||||
/// @dev Gas limit for Kyber calls.
|
||||
uint256 constant internal KYBER_CALL_GAS = 1500e3; // 1.5m
|
||||
/// @dev Gas limit for Uniswap calls.
|
||||
uint256 constant internal UNISWAP_CALL_GAS = 150e3; // 150k
|
||||
/// @dev Base gas limit for Eth2Dai calls.
|
||||
uint256 constant internal ETH2DAI_CALL_GAS = 1000e3; // 1m
|
||||
/// @dev Base gas limit for Curve calls. Some Curves have multiple tokens
|
||||
/// So a reasonable ceil is 150k per token. Biggest Curve has 4 tokens.
|
||||
uint256 constant internal CURVE_CALL_GAS = 600e3; // 600k
|
||||
|
||||
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryBatchOrdersAndSampleSells(
|
||||
LibOrder.Order[][] memory orders,
|
||||
bytes[][] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[][] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||
/// @param callDatas ABI-encoded call data for each function call.
|
||||
/// @return callResults ABI-encoded results data for each call.
|
||||
function batchCall(bytes[] calldata callDatas)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
)
|
||||
returns (bytes[] memory callResults)
|
||||
{
|
||||
ordersAndSamples = new OrdersAndSample[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
(
|
||||
uint256[] memory orderFillableAssetAmounts,
|
||||
uint256[][] memory tokenAmountsBySource
|
||||
) = queryOrdersAndSampleSells(orders[i], orderSignatures[i], sources, takerTokenAmounts[i]);
|
||||
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
|
||||
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
|
||||
callResults = new bytes[](callDatas.length);
|
||||
for (uint256 i = 0; i != callDatas.length; ++i) {
|
||||
(bool didSucceed, bytes memory resultData) = address(this).staticcall(callDatas[i]);
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(resultData, 0x20), mload(resultData)) }
|
||||
}
|
||||
callResults[i] = resultData;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryBatchOrdersAndSampleBuys(
|
||||
LibOrder.Order[][] memory orders,
|
||||
bytes[][] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[][] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
)
|
||||
{
|
||||
ordersAndSamples = new OrdersAndSample[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
(
|
||||
uint256[] memory orderFillableAssetAmounts,
|
||||
uint256[][] memory tokenAmountsBySource
|
||||
) = queryOrdersAndSampleBuys(orders[i], orderSignatures[i], sources, makerTokenAmounts[i]);
|
||||
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
|
||||
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleSells(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
uint256[] memory orderFillableTakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
)
|
||||
{
|
||||
require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS");
|
||||
orderFillableTakerAssetAmounts = getOrderFillableTakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures
|
||||
);
|
||||
makerTokenAmountsBySource = sampleSells(
|
||||
sources,
|
||||
_assetDataToTokenAddress(orders[0].takerAssetData),
|
||||
_assetDataToTokenAddress(orders[0].makerAssetData),
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleBuys(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
uint256[] memory orderFillableMakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
)
|
||||
{
|
||||
require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS");
|
||||
orderFillableMakerAssetAmounts = getOrderFillableMakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures
|
||||
);
|
||||
makerTokenAmountsBySource = sampleBuys(
|
||||
sources,
|
||||
_assetDataToTokenAddress(orders[0].takerAssetData),
|
||||
_assetDataToTokenAddress(orders[0].makerAssetData),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// maker/taker asset amounts (returning 0).
|
||||
/// maker/taker asset amounts (returning 0).
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
@@ -270,66 +155,6 @@ contract ERC20BridgeSampler is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes on multiple DEXes at once.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @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 makerTokenAmountsBySource Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function sampleSells(
|
||||
address[] memory sources,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[][] memory makerTokenAmountsBySource)
|
||||
{
|
||||
uint256 numSources = sources.length;
|
||||
makerTokenAmountsBySource = new uint256[][](numSources);
|
||||
for (uint256 i = 0; i < numSources; i++) {
|
||||
makerTokenAmountsBySource[i] = _sampleSellSource(
|
||||
sources[i],
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @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 takerTokenAmountsBySource Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function sampleBuys(
|
||||
address[] memory sources,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[][] memory takerTokenAmountsBySource)
|
||||
{
|
||||
uint256 numSources = sources.length;
|
||||
takerTokenAmountsBySource = new uint256[][](numSources);
|
||||
for (uint256 i = 0; i < numSources; i++) {
|
||||
takerTokenAmountsBySource[i] = _sampleBuySource(
|
||||
sources[i],
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
@@ -354,7 +179,7 @@ contract ERC20BridgeSampler is
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_SAMPLE_CALL_GAS)(
|
||||
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IKyberNetwork(0).getExpectedRate.selector,
|
||||
_takerToken,
|
||||
@@ -396,7 +221,7 @@ contract ERC20BridgeSampler is
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getEth2DaiAddress().staticcall.gas(ETH2DAI_SAMPLE_CALL_GAS)(
|
||||
_getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IEth2Dai(0).getBuyAmount.selector,
|
||||
makerToken,
|
||||
@@ -433,7 +258,7 @@ contract ERC20BridgeSampler is
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
_getEth2DaiAddress().staticcall.gas(ETH2DAI_SAMPLE_CALL_GAS)(
|
||||
_getEth2DaiAddress().staticcall.gas(ETH2DAI_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IEth2Dai(0).getPayAmount.selector,
|
||||
takerToken,
|
||||
@@ -568,6 +393,44 @@ contract ERC20BridgeSampler is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample sell quotes from Curve.
|
||||
/// @param curveAddress Address of the Curve contract.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index 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 sampleSellsFromCurve(
|
||||
address curveAddress,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
curveAddress.staticcall.gas(CURVE_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
ICurve(0).get_dy_underlying.selector,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Overridable way to get token decimals.
|
||||
/// @param tokenAddress Address of the token.
|
||||
/// @return decimals The decimal places for the token.
|
||||
@@ -599,7 +462,7 @@ contract ERC20BridgeSampler is
|
||||
}
|
||||
bytes memory resultData;
|
||||
(didSucceed, resultData) =
|
||||
uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)(
|
||||
uniswapExchangeAddress.staticcall.gas(UNISWAP_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
functionSelector,
|
||||
inputAmount
|
||||
@@ -609,59 +472,6 @@ contract ERC20BridgeSampler is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Samples a supported sell source, defined by its address.
|
||||
/// @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 _sampleSellSource(
|
||||
address source,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
if (source == ETH2DAI_SOURCE) {
|
||||
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == UNISWAP_SOURCE) {
|
||||
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == KYBER_SOURCE) {
|
||||
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
}
|
||||
|
||||
/// @dev Samples a supported buy source, defined by its address.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function _sampleBuySource(
|
||||
address source,
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
if (source == ETH2DAI_SOURCE) {
|
||||
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
if (source == UNISWAP_SOURCE) {
|
||||
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
}
|
||||
|
||||
/// @dev Retrive an existing Uniswap exchange contract.
|
||||
/// Throws if the exchange does not exist.
|
||||
/// @param tokenAddress Address of the token contract.
|
||||
@@ -677,23 +487,9 @@ contract ERC20BridgeSampler is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Extract the token address from ERC20 proxy asset data.
|
||||
/// @param assetData ERC20 asset data.
|
||||
/// @return tokenAddress The decoded token address.
|
||||
function _assetDataToTokenAddress(bytes memory assetData)
|
||||
private
|
||||
pure
|
||||
returns (address tokenAddress)
|
||||
{
|
||||
require(assetData.length == 36, "ERC20BridgeSampler/INVALID_ASSET_DATA");
|
||||
bytes4 selector;
|
||||
assembly {
|
||||
selector := and(mload(add(assetData, 0x20)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
|
||||
tokenAddress := mload(add(assetData, 0x24))
|
||||
}
|
||||
require(selector == ERC20_PROXY_ID, "ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY");
|
||||
}
|
||||
|
||||
/// @dev Assert that the tokens in a trade pair are valid.
|
||||
/// @param makerToken Address of the maker token.
|
||||
/// @param takerToken Address of the taker token.
|
||||
function _assertValidPair(address makerToken, address takerToken)
|
||||
private
|
||||
pure
|
||||
|
87
contracts/erc20-bridge-sampler/contracts/src/ICurve.sol
Normal file
87
contracts/erc20-bridge-sampler/contracts/src/ICurve.sol
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
// solhint-disable func-name-mixedcase
|
||||
interface ICurve {
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// This function exists on early versions of Curve (USDC/DAI)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
/// @param minBuyAmount The minimum buy amount of the token being bought.
|
||||
/// @param deadline The time in seconds when this operation should expire.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount,
|
||||
uint256 deadline
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
/// @param minBuyAmount The minimum buy amount of the token being bought.
|
||||
function exchange_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount,
|
||||
uint256 minBuyAmount
|
||||
)
|
||||
external;
|
||||
|
||||
/// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param sellAmount The amount of token being bought.
|
||||
function get_dy_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dy);
|
||||
|
||||
/// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
|
||||
/// This function exists on later versions of Curve (USDC/DAI/USDT)
|
||||
/// @param i The token index being sold.
|
||||
/// @param j The token index being bought.
|
||||
/// @param buyAmount The amount of token being bought.
|
||||
function get_dx_underlying(
|
||||
int128 i,
|
||||
int128 j,
|
||||
uint256 buyAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 dx);
|
||||
|
||||
/// @dev Get the underlying token address from the token index
|
||||
/// @param i The token index.
|
||||
function underlying_coins(
|
||||
int128 i
|
||||
)
|
||||
external
|
||||
returns (address tokenAddress);
|
||||
}
|
@@ -23,98 +23,14 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IERC20BridgeSampler {
|
||||
struct OrdersAndSample {
|
||||
uint256[] orderFillableAssetAmounts;
|
||||
uint256[][] tokenAmountsBySource;
|
||||
}
|
||||
|
||||
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryBatchOrdersAndSampleSells(
|
||||
LibOrder.Order[][] calldata orders,
|
||||
bytes[][] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[][] calldata takerTokenAmounts
|
||||
)
|
||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||
/// @param callDatas ABI-encoded call data for each function call.
|
||||
/// @return callResults ABI-encoded results data for each call.
|
||||
function batchCall(bytes[] calldata callDatas)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
);
|
||||
|
||||
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index
|
||||
function queryBatchOrdersAndSampleBuys(
|
||||
LibOrder.Order[][] calldata orders,
|
||||
bytes[][] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[][] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
);
|
||||
|
||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleSells(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256[] memory orderFillableTakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
);
|
||||
|
||||
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryOrdersAndSampleBuys(
|
||||
LibOrder.Order[] calldata orders,
|
||||
bytes[] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256[] memory orderFillableMakerAssetAmounts,
|
||||
uint256[][] memory makerTokenAmountsBySource
|
||||
);
|
||||
returns (bytes[] memory callResults);
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// @param orders Native orders to query.
|
||||
@@ -142,39 +58,95 @@ interface IERC20BridgeSampler {
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts);
|
||||
|
||||
/// @dev Sample sell quotes on multiple DEXes at once.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @dev Sample sell quotes from Kyber.
|
||||
/// @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 makerTokenAmountsBySource Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function sampleSells(
|
||||
address[] calldata sources,
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromKyberNetwork(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[][] memory makerTokenAmountsBySource);
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @dev Sample sell quotes from Eth2Dai/Oasis.
|
||||
/// @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 takerTokenAmountsBySource Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function sampleBuys(
|
||||
address[] calldata sources,
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromEth2Dai(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from Uniswap.
|
||||
/// @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 sampleSellsFromUniswap(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
|
||||
/// @dev Sample buy quotes from Uniswap.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromUniswap(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[][] memory takerTokenAmountsBySource);
|
||||
returns (uint256[] memory takerTokenAmounts);
|
||||
|
||||
/// @dev Sample buy quotes from Eth2Dai/Oasis.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromEth2Dai(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts);
|
||||
|
||||
/// @dev Sample sell quotes from Curve.
|
||||
/// @param curveAddress Address of the Curve contract.
|
||||
/// @param fromTokenIdx Index of the taker token (what to sell).
|
||||
/// @param toTokenIdx Index 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 sampleSellsFromCurve(
|
||||
address curveAddress,
|
||||
int128 fromTokenIdx,
|
||||
int128 toTokenIdx,
|
||||
uint256[] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts);
|
||||
}
|
||||
|
@@ -327,7 +327,6 @@ contract TestERC20BridgeSampler is
|
||||
bytes memory
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,7 +38,7 @@
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
||||
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -51,13 +51,13 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-exchange": "^3.2.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-exchange": "^3.2.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
|
@@ -6,6 +6,7 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
|
||||
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
@@ -14,6 +15,7 @@ import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExc
|
||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
||||
export const artifacts = {
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDevUtils: IDevUtils as ContractArtifact,
|
||||
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
|
@@ -25,19 +25,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
|
||||
const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
|
||||
const ERC20_PROXY_ID = '0xf47261b0';
|
||||
const INVALID_ASSET_PROXY_ASSET_DATA = hexUtils.concat('0xf47261b1', hexUtils.leftPad(randomAddress()));
|
||||
const INVALID_ASSET_DATA = hexUtils.random(37);
|
||||
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
|
||||
const BUY_SOURCES = ['Eth2Dai', 'Uniswap'];
|
||||
const SOURCE_IDS: { [source: string]: string } = {
|
||||
Uniswap: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95',
|
||||
Eth2Dai: '0x39755357759ce0d7f32dc8dc45414cca409ae24e',
|
||||
Kyber: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
|
||||
};
|
||||
const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
|
||||
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
|
||||
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
|
||||
const UNSUPPORTED_SOURCE_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_SOURCE';
|
||||
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
@@ -190,7 +177,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
}
|
||||
|
||||
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
||||
const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
|
||||
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) {
|
||||
@@ -324,329 +311,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('queryOrdersAndSampleSells()', () => {
|
||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('returns expected fillable amounts for each order', async () => {
|
||||
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
|
||||
it('can return quotes for all sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
|
||||
it('throws with non-ERC20 maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR);
|
||||
});
|
||||
|
||||
it('throws with non-ERC20 taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR);
|
||||
});
|
||||
|
||||
it('throws with invalid maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR);
|
||||
});
|
||||
|
||||
it('throws with invalid taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('queryOrdersAndSampleBuys()', () => {
|
||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('returns expected fillable amounts for each order', async () => {
|
||||
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
|
||||
it('can return quotes for all sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
|
||||
it('throws if kyber is passed in as a source', async () => {
|
||||
const sources = [...BUY_SOURCES, 'Kyber'];
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
sources.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
|
||||
it('throws with non-ERC20 maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR);
|
||||
});
|
||||
|
||||
it('throws with non-ERC20 taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_ASSET_PROXY_ERROR);
|
||||
});
|
||||
|
||||
it('throws with invalid maker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR);
|
||||
});
|
||||
|
||||
it('throws with invalid taker asset data', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS.map(o => ({
|
||||
...o,
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(INVALID_ASSET_DATA_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleSells()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('returns empty quotes with no sample amounts', async () => {
|
||||
const emptyQuotes = _.times(SELL_SOURCES.length, () => []);
|
||||
const quotes = await testContract
|
||||
.sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(emptyQuotes);
|
||||
});
|
||||
|
||||
it('can return quotes for all sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can return quotes for some sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const sources = _.sampleSize(SELL_SOURCES, 1);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSells(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.sampleSells(
|
||||
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sampleBuys()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
it('returns empty quotes with no sample amounts', async () => {
|
||||
const emptyQuotes = _.times(BUY_SOURCES.length, () => []);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(emptyQuotes);
|
||||
});
|
||||
|
||||
it('can return quotes for all sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('can return quotes for some sources', async () => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const sources = _.sampleSize(BUY_SOURCES, 1);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.sampleBuys(
|
||||
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
|
||||
it('throws if kyber is passed in as a source', async () => {
|
||||
const sources = [...BUY_SOURCES, 'Kyber'];
|
||||
const tx = testContract
|
||||
.sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
blockchainTests.resets('sampleSellsFromKyberNetwork()', () => {
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
@@ -1051,4 +715,65 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
});
|
||||
|
||||
describe('batchCall()', () => {
|
||||
it('can call one function', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||
const calls = [
|
||||
testContract.getOrderFillableTakerAssetAmounts(orders, signatures).getABIEncodedTransactionData(),
|
||||
];
|
||||
const r = await testContract.batchCall(calls).callAsync();
|
||||
expect(r).to.be.length(1);
|
||||
const actual = testContract.getABIDecodedReturnData<BigNumber[]>('getOrderFillableTakerAssetAmounts', r[0]);
|
||||
expect(actual).to.deep.eq(expected);
|
||||
});
|
||||
|
||||
it('can call two functions', async () => {
|
||||
const numOrders = _.random(1, 10);
|
||||
const orders = _.times(2, () => createOrders(MAKER_TOKEN, TAKER_TOKEN, numOrders));
|
||||
const signatures: string[] = _.times(numOrders, i => hexUtils.random());
|
||||
const expecteds = [
|
||||
orders[0].map(getDeterministicFillableTakerAssetAmount),
|
||||
orders[1].map(getDeterministicFillableMakerAssetAmount),
|
||||
];
|
||||
const calls = [
|
||||
testContract.getOrderFillableTakerAssetAmounts(orders[0], signatures).getABIEncodedTransactionData(),
|
||||
testContract.getOrderFillableMakerAssetAmounts(orders[1], signatures).getABIEncodedTransactionData(),
|
||||
];
|
||||
const r = await testContract.batchCall(calls).callAsync();
|
||||
expect(r).to.be.length(2);
|
||||
expect(testContract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', r[0])).to.deep.eq(
|
||||
expecteds[0],
|
||||
);
|
||||
expect(testContract.getABIDecodedReturnData('getOrderFillableMakerAssetAmounts', r[1])).to.deep.eq(
|
||||
expecteds[1],
|
||||
);
|
||||
});
|
||||
|
||||
it('can make recursive calls', async () => {
|
||||
const numOrders = _.random(1, 10);
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, numOrders);
|
||||
const signatures: string[] = _.times(numOrders, i => hexUtils.random());
|
||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||
let r = await testContract
|
||||
.batchCall([
|
||||
testContract
|
||||
.batchCall([
|
||||
testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures)
|
||||
.getABIEncodedTransactionData(),
|
||||
])
|
||||
.getABIEncodedTransactionData(),
|
||||
])
|
||||
.callAsync();
|
||||
expect(r).to.be.length(1);
|
||||
r = testContract.getABIDecodedReturnData<string[]>('batchCall', r[0]);
|
||||
expect(r).to.be.length(1);
|
||||
expect(testContract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', r[0])).to.deep.eq(
|
||||
expected,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_dev_utils';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
|
@@ -6,6 +6,7 @@
|
||||
"generated-artifacts/ERC20BridgeSampler.json",
|
||||
"generated-artifacts/IERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IDevUtils.json",
|
||||
"test/generated-artifacts/IERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "3.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.0 - _February 8, 2020_
|
||||
|
||||
* Add `allowance()` and `balanceOf()` to `LibERC20Token` (#2464)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,8 +53,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "3.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.0 - _February 8, 2020_
|
||||
|
||||
* Fix broken tests (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,8 +54,8 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "4.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.2.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.2.0 - _February 8, 2020_
|
||||
|
||||
* Export `EvmBytecodeOutputLinkReferences` type. (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.2.0",
|
||||
"version": "4.2.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,18 +53,18 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.0",
|
||||
"@0x/contracts-erc1155": "^2.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-erc721": "^3.1.0",
|
||||
"@0x/contracts-exchange": "^3.2.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-dev-utils": "^1.1.1",
|
||||
"@0x/contracts-erc1155": "^2.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-erc721": "^3.1.1",
|
||||
"@0x/contracts-exchange": "^3.2.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "4.3.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.3.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.0 - _February 8, 2020_
|
||||
|
||||
* Export `EvmBytecodeOutputLinkReferences` type. (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.3.0",
|
||||
"version": "4.3.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -81,9 +81,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "3.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.2.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.2.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.2.0 - _February 8, 2020_
|
||||
|
||||
* Flip `LibExchangeRichErrorDecoder` to an actual library. (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -53,13 +53,13 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-multisig": "^4.1.0",
|
||||
"@0x/contracts-staking": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-multisig": "^4.1.1",
|
||||
"@0x/contracts-staking": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
@@ -89,11 +89,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.0",
|
||||
"@0x/contracts-erc1155": "^2.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-erc721": "^3.1.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.1",
|
||||
"@0x/contracts-erc1155": "^2.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-erc721": "^3.1.1",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/utils": "^5.4.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "6.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "6.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v6.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v6.1.0 - _February 8, 2020_
|
||||
|
||||
* Export `EvmBytecodeOutputLinkReferences` type. (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "6.1.0",
|
||||
"version": "6.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,17 +52,17 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-erc721": "^3.1.0",
|
||||
"@0x/contracts-exchange": "^3.2.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-dev-utils": "^1.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-erc721": "^3.1.1",
|
||||
"@0x/contracts-exchange": "^3.2.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
|
@@ -1,4 +1,26 @@
|
||||
[
|
||||
{
|
||||
"version": "2.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added ChainlinkStopLimit contract and tests",
|
||||
"pr": 2473
|
||||
},
|
||||
{
|
||||
"note": "Fixed the mainnet dYdX Bridge tests.",
|
||||
"pr": 2479
|
||||
},
|
||||
{
|
||||
"note": "Addded decoders for stop-limit data",
|
||||
"pr": 2484
|
||||
},
|
||||
{
|
||||
"note": "Added ERC20Sampler and Curve Mainnet test",
|
||||
"pr": 2483
|
||||
}
|
||||
],
|
||||
"timestamp": 1581748629
|
||||
},
|
||||
{
|
||||
"version": "2.3.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,13 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.4.0 - _February 15, 2020_
|
||||
|
||||
* Added ChainlinkStopLimit contract and tests (#2473)
|
||||
* Fixed the mainnet dYdX Bridge tests. (#2479)
|
||||
* Addded decoders for stop-limit data (#2484)
|
||||
* Added ERC20Sampler and Curve Mainnet test (#2483)
|
||||
|
||||
## v2.3.0 - _February 8, 2020_
|
||||
|
||||
* Remove dependency on `DevUtils` for asset data encoding/decoding (#2462)
|
||||
|
50
contracts/integrations/contracts/src/ChainlinkStopLimit.sol
Normal file
50
contracts/integrations/contracts/src/ChainlinkStopLimit.sol
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
|
||||
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 "./interfaces/IChainlinkAggregator.sol";
|
||||
|
||||
|
||||
contract ChainlinkStopLimit {
|
||||
|
||||
/// @dev Checks that the price returned by the encoded Chainlink reference contract is
|
||||
/// within the encoded price range.
|
||||
/// @param stopLimitData Encodes the address of the Chainlink reference contract and the
|
||||
/// valid price range.
|
||||
function checkStopLimit(bytes calldata stopLimitData)
|
||||
external
|
||||
view
|
||||
{
|
||||
(
|
||||
address oracle,
|
||||
int256 minPrice,
|
||||
int256 maxPrice
|
||||
) = abi.decode(
|
||||
stopLimitData,
|
||||
(address, int256, int256)
|
||||
);
|
||||
|
||||
int256 latestPrice = IChainlinkAggregator(oracle).latestAnswer();
|
||||
require(
|
||||
latestPrice >= minPrice && latestPrice <= maxPrice,
|
||||
"ChainlinkStopLimit/OUT_OF_PRICE_RANGE"
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
|
||||
|
||||
// A subset of https://github.com/smartcontractkit/chainlink/blob/master/evm/contracts/interfaces/AggregatorInterface.sol
|
||||
interface IChainlinkAggregator {
|
||||
|
||||
/// @dev Returns the latest data value recorded by the contract.
|
||||
/// @return answer The latest data value recorded. For a price oracle aggregator, this will be
|
||||
/// the price of the given asset in USD, multipled by 10^8
|
||||
function latestAnswer() external view returns (int256 answer);
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/interfaces/IChainlinkAggregator.sol";
|
||||
|
||||
|
||||
contract TestChainlinkAggregator is
|
||||
IChainlinkAggregator
|
||||
{
|
||||
int256 internal _price;
|
||||
|
||||
function setPrice(int256 price_)
|
||||
external
|
||||
{
|
||||
_price = price_;
|
||||
}
|
||||
|
||||
function latestAnswer()
|
||||
external
|
||||
view
|
||||
returns (int256)
|
||||
{
|
||||
return _price;
|
||||
}
|
||||
}
|
@@ -130,7 +130,7 @@ interface IDydx {
|
||||
/// @dev Deploy this contract and call `init` to run the mainnet DydxBridge integration tests.
|
||||
contract TestDydxUser {
|
||||
|
||||
address public constant DYDX_BRIDGE_ADDRESS = 0x96DdBa19b69D6EA2549f6a12d005595167414744;
|
||||
address public constant DYDX_BRIDGE_ADDRESS = 0x55dC8f21D20D4c6ED3C82916A438A413ca68e335;
|
||||
address public constant DYDX_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
|
||||
address public constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
|
||||
uint256 public constant DYDX_DAI_MARKET_ID = 3;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-integrations",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "TestFramework",
|
||||
"abis": "./test/generated-artifacts/@(TestContractWrapper|TestDydxUser|TestEth2Dai|TestEth2DaiBridge|TestFramework|TestMainnetAggregatorFills|TestSignatureValidationWallet|TestUniswapBridge|TestUniswapExchange|TestUniswapExchangeFactory).json",
|
||||
"abis": "./test/generated-artifacts/@(ChainlinkStopLimit|IChainlinkAggregator|TestChainlinkAggregator|TestContractWrapper|TestDydxUser|TestEth2Dai|TestEth2DaiBridge|TestFramework|TestMainnetAggregatorFills|TestSignatureValidationWallet|TestUniswapBridge|TestUniswapExchange|TestUniswapExchangeFactory).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -52,20 +52,21 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contract-addresses": "^4.5.0",
|
||||
"@0x/contract-wrappers": "^13.5.0",
|
||||
"@0x/contracts-broker": "^1.0.2",
|
||||
"@0x/contracts-coordinator": "^3.1.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.0",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-extensions": "^6.1.0",
|
||||
"@0x/contract-addresses": "^4.6.0",
|
||||
"@0x/contract-wrappers": "^13.6.0",
|
||||
"@0x/contracts-broker": "^1.1.0",
|
||||
"@0x/contracts-coordinator": "^3.1.1",
|
||||
"@0x/contracts-dev-utils": "^1.1.1",
|
||||
"@0x/contracts-erc20-bridge-sampler": "^1.4.0",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-extensions": "^6.1.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/coordinator-server": "^1.0.5",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/migrations": "^6.1.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/migrations": "^6.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.6",
|
||||
@@ -91,16 +92,16 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/asset-swapper": "^4.1.2",
|
||||
"@0x/asset-swapper": "^4.2.0",
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-erc1155": "^2.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-erc721": "^3.1.0",
|
||||
"@0x/contracts-exchange": "^3.2.0",
|
||||
"@0x/contracts-multisig": "^4.1.0",
|
||||
"@0x/contracts-staking": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-erc1155": "^2.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-erc721": "^3.1.1",
|
||||
"@0x/contracts-exchange": "^3.2.1",
|
||||
"@0x/contracts-multisig": "^4.1.1",
|
||||
"@0x/contracts-staking": "^2.0.8",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.0",
|
||||
|
58
contracts/integrations/src/chainlink_utils.ts
Normal file
58
contracts/integrations/src/chainlink_utils.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { constants } from '@0x/contracts-test-utils';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { StaticCallAssetData } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
export interface StopLimitParameters {
|
||||
oracle: string;
|
||||
minPrice: BigNumber;
|
||||
maxPrice: BigNumber;
|
||||
}
|
||||
|
||||
const stopLimitDataEncoder = AbiEncoder.create([
|
||||
{ name: 'oracle', type: 'address' },
|
||||
{ name: 'minPrice', type: 'int256' },
|
||||
{ name: 'maxPrice', type: 'int256' },
|
||||
]);
|
||||
|
||||
const stopLimitMethodEncoder = AbiEncoder.createMethod('checkStopLimit', [{ name: 'stopLimitData', type: 'bytes' }]);
|
||||
|
||||
/**
|
||||
* Encodes the given stop limit data parameters into the bytes format expected by the
|
||||
* ChainlinkStopLimit contract.
|
||||
*/
|
||||
export function encodeChainlinkStopLimitData(params: StopLimitParameters): string {
|
||||
return stopLimitDataEncoder.encode(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given stop limit data parameters into StaticCall asset data so that it can be used
|
||||
* in a 0x order.
|
||||
*/
|
||||
export function encodeStopLimitStaticCallData(chainlinkStopLimitAddress: string, params: StopLimitParameters): string {
|
||||
const staticCallData = stopLimitMethodEncoder.encode({
|
||||
stopLimitData: encodeChainlinkStopLimitData(params),
|
||||
});
|
||||
return assetDataUtils.encodeStaticCallAssetData(
|
||||
chainlinkStopLimitAddress,
|
||||
staticCallData,
|
||||
constants.KECCAK256_NULL,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes stop limit data parameters from the bytes format expected by the ChainlinkStopLimit contract.
|
||||
*/
|
||||
export function decodeChainlinkStopLimitData(stopLimitData: string): StopLimitParameters {
|
||||
return stopLimitDataEncoder.decode(stopLimitData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes stop limit data parameters from stop limit StaticCall asset data.
|
||||
*/
|
||||
export function decodeStopLimitStaticCallData(assetData: string): StopLimitParameters {
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
const { staticCallData } = assetDataUtils.decodeAssetDataOrThrow(assetData) as StaticCallAssetData;
|
||||
const stopLimitData = stopLimitMethodEncoder.strictDecode<string>(staticCallData);
|
||||
return decodeChainlinkStopLimitData(stopLimitData);
|
||||
}
|
@@ -1,2 +1,3 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export * from './wrappers';
|
||||
export * from './chainlink_utils';
|
||||
|
@@ -5,6 +5,9 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as ChainlinkStopLimit from '../test/generated-artifacts/ChainlinkStopLimit.json';
|
||||
import * as IChainlinkAggregator from '../test/generated-artifacts/IChainlinkAggregator.json';
|
||||
import * as TestChainlinkAggregator from '../test/generated-artifacts/TestChainlinkAggregator.json';
|
||||
import * as TestContractWrapper from '../test/generated-artifacts/TestContractWrapper.json';
|
||||
import * as TestDydxUser from '../test/generated-artifacts/TestDydxUser.json';
|
||||
import * as TestEth2Dai from '../test/generated-artifacts/TestEth2Dai.json';
|
||||
@@ -16,6 +19,9 @@ import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridg
|
||||
import * as TestUniswapExchange from '../test/generated-artifacts/TestUniswapExchange.json';
|
||||
import * as TestUniswapExchangeFactory from '../test/generated-artifacts/TestUniswapExchangeFactory.json';
|
||||
export const artifacts = {
|
||||
ChainlinkStopLimit: ChainlinkStopLimit as ContractArtifact,
|
||||
IChainlinkAggregator: IChainlinkAggregator as ContractArtifact,
|
||||
TestChainlinkAggregator: TestChainlinkAggregator as ContractArtifact,
|
||||
TestContractWrapper: TestContractWrapper as ContractArtifact,
|
||||
TestDydxUser: TestDydxUser as ContractArtifact,
|
||||
TestEth2Dai: TestEth2Dai as ContractArtifact,
|
||||
|
@@ -0,0 +1,37 @@
|
||||
import { artifacts, ERC20BridgeSamplerContract } from '@0x/contracts-erc20-bridge-sampler';
|
||||
import { blockchainTests, describe, expect, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
blockchainTests.fork.resets('Mainnet Sampler Tests', env => {
|
||||
let testContract: ERC20BridgeSamplerContract;
|
||||
before(async () => {
|
||||
testContract = await ERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ERC20BridgeSampler,
|
||||
env.provider,
|
||||
{ ...env.txDefaults, from: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b' },
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
describe('sampleSellsFromCurve()', () => {
|
||||
const curveAddress = '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51';
|
||||
const daiTokenIdx = new BigNumber(0);
|
||||
const usdcTokenIdx = new BigNumber(1);
|
||||
|
||||
it('samples sells from Curve DAI->USDC', async () => {
|
||||
const samples = await testContract
|
||||
.sampleSellsFromCurve(curveAddress, daiTokenIdx, usdcTokenIdx, [toBaseUnitAmount(1)])
|
||||
.callAsync();
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
|
||||
it('samples sells from Curve USDC->DAI', async () => {
|
||||
const samples = await testContract
|
||||
.sampleSellsFromCurve(curveAddress, usdcTokenIdx, daiTokenIdx, [toBaseUnitAmount(1, 6)])
|
||||
.callAsync();
|
||||
expect(samples.length).to.be.bignumber.greaterThan(0);
|
||||
expect(samples[0]).to.be.bignumber.greaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
111
contracts/integrations/test/bridges/curve_bridge_mainnet_test.ts
Normal file
111
contracts/integrations/test/bridges/curve_bridge_mainnet_test.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { artifacts as assetProxyArtifacts } from '@0x/contracts-asset-proxy';
|
||||
import { CurveBridgeContract } from '@0x/contracts-asset-proxy/lib/src/wrappers';
|
||||
import { ERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { blockchainTests, constants, describe, toBaseUnitAmount } from '@0x/contracts-test-utils';
|
||||
import { AbiEncoder } from '@0x/utils';
|
||||
|
||||
blockchainTests.fork.resets('Mainnet curve bridge tests', env => {
|
||||
let testContract: CurveBridgeContract;
|
||||
const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308';
|
||||
const usdcWallet = '0xF977814e90dA44bFA03b6295A0616a897441aceC';
|
||||
const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
|
||||
const daiWallet = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b';
|
||||
const daiAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
|
||||
const curveAddressUsdcDai = '0x2e60CF74d81ac34eB21eEff58Db4D385920ef419';
|
||||
const curveAddressUsdcDaiUsdt = '0x52EA46506B9CC5Ef470C5bf89f17Dc28bB35D85C';
|
||||
const daiTokenIdx = 0;
|
||||
const usdcTokenIdx = 1;
|
||||
const bridgeDataEncoder = AbiEncoder.create([
|
||||
{ name: 'curveAddress', type: 'address' },
|
||||
{ name: 'fromTokenIdx', type: 'int128' },
|
||||
{ name: 'toTokenIdx', type: 'int128' },
|
||||
{ name: 'version', type: 'int128' },
|
||||
]);
|
||||
before(async () => {
|
||||
testContract = await CurveBridgeContract.deployFrom0xArtifactAsync(
|
||||
assetProxyArtifacts.CurveBridge,
|
||||
env.provider,
|
||||
{ ...env.txDefaults, from: daiWallet },
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
describe('bridgeTransferFrom()', () => {
|
||||
describe('Version 0', () => {
|
||||
const version = 0;
|
||||
it('succeeds exchanges DAI for USDC', async () => {
|
||||
const bridgeData = bridgeDataEncoder.encode([curveAddressUsdcDai, daiTokenIdx, usdcTokenIdx, version]);
|
||||
// Fund the Bridge
|
||||
const dai = new ERC20TokenContract(daiAddress, env.provider, { ...env.txDefaults, from: daiWallet });
|
||||
await dai
|
||||
.transfer(testContract.address, toBaseUnitAmount(1))
|
||||
.awaitTransactionSuccessAsync({ from: daiWallet }, { shouldValidate: false });
|
||||
// Exchange via Curve
|
||||
await testContract
|
||||
.bridgeTransferFrom(
|
||||
usdcAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
receiver,
|
||||
constants.ZERO_AMOUNT,
|
||||
bridgeData,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: daiWallet, gasPrice: 1 }, { shouldValidate: false });
|
||||
});
|
||||
it('succeeds exchanges USDC for DAI', async () => {
|
||||
const bridgeData = bridgeDataEncoder.encode([curveAddressUsdcDai, usdcTokenIdx, daiTokenIdx, version]);
|
||||
// Fund the Bridge
|
||||
const usdc = new ERC20TokenContract(usdcAddress, env.provider, { ...env.txDefaults, from: usdcWallet });
|
||||
await usdc
|
||||
.transfer(testContract.address, toBaseUnitAmount(1, 6))
|
||||
.awaitTransactionSuccessAsync({ from: usdcWallet }, { shouldValidate: false });
|
||||
// Exchange via Curve
|
||||
await testContract
|
||||
.bridgeTransferFrom(daiAddress, constants.NULL_ADDRESS, receiver, constants.ZERO_AMOUNT, bridgeData)
|
||||
.awaitTransactionSuccessAsync({ from: usdcWallet, gasPrice: 1 }, { shouldValidate: false });
|
||||
});
|
||||
});
|
||||
describe('Version 1', () => {
|
||||
const version = 1;
|
||||
it('succeeds exchanges DAI for USDC', async () => {
|
||||
const bridgeData = bridgeDataEncoder.encode([
|
||||
curveAddressUsdcDaiUsdt,
|
||||
daiTokenIdx,
|
||||
usdcTokenIdx,
|
||||
version,
|
||||
]);
|
||||
// Fund the Bridge
|
||||
const dai = new ERC20TokenContract(daiAddress, env.provider, { ...env.txDefaults, from: daiWallet });
|
||||
await dai
|
||||
.transfer(testContract.address, toBaseUnitAmount(1))
|
||||
.awaitTransactionSuccessAsync({ from: daiWallet }, { shouldValidate: false });
|
||||
// Exchange via Curve
|
||||
await testContract
|
||||
.bridgeTransferFrom(
|
||||
usdcAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
receiver,
|
||||
constants.ZERO_AMOUNT,
|
||||
bridgeData,
|
||||
)
|
||||
.awaitTransactionSuccessAsync({ from: daiWallet, gasPrice: 1 }, { shouldValidate: false });
|
||||
});
|
||||
it('succeeds exchanges USDC for DAI', async () => {
|
||||
const bridgeData = bridgeDataEncoder.encode([
|
||||
curveAddressUsdcDaiUsdt,
|
||||
usdcTokenIdx,
|
||||
daiTokenIdx,
|
||||
version,
|
||||
]);
|
||||
// Fund the Bridge
|
||||
const usdc = new ERC20TokenContract(usdcAddress, env.provider, { ...env.txDefaults, from: usdcWallet });
|
||||
await usdc
|
||||
.transfer(testContract.address, toBaseUnitAmount(1, 6))
|
||||
.awaitTransactionSuccessAsync({ from: usdcWallet }, { shouldValidate: false });
|
||||
// Exchange via Curve
|
||||
await testContract
|
||||
.bridgeTransferFrom(daiAddress, constants.NULL_ADDRESS, receiver, constants.ZERO_AMOUNT, bridgeData)
|
||||
.awaitTransactionSuccessAsync({ from: usdcWallet, gasPrice: 1 }, { shouldValidate: false });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -14,7 +14,7 @@ import { contractAddresses, dydxAccountOwner } from '../mainnet_fork_utils';
|
||||
|
||||
import { dydxEvents } from './abi/dydxEvents';
|
||||
|
||||
blockchainTests.fork.skip('Mainnet dydx bridge tests', env => {
|
||||
blockchainTests.fork.resets('Mainnet dydx bridge tests', env => {
|
||||
let testContract: DydxBridgeContract;
|
||||
// random account to receive tokens from dydx
|
||||
const receiver = '0x986ccf5234d9cfbb25246f1a5bfa51f4ccfcb308';
|
||||
@@ -73,7 +73,7 @@ blockchainTests.fork.skip('Mainnet dydx bridge tests', env => {
|
||||
accountOwner: dydxAccountOwner,
|
||||
accountNumber: bridgeData.accountNumbers[action.accountId.toNumber()],
|
||||
market: action.marketId,
|
||||
update: [[true, scaledAmount]],
|
||||
update: { deltaWei: { sign: true, value: scaledAmount } },
|
||||
from: dydxAccountOwner,
|
||||
});
|
||||
break;
|
||||
@@ -83,7 +83,7 @@ blockchainTests.fork.skip('Mainnet dydx bridge tests', env => {
|
||||
accountOwner: dydxAccountOwner,
|
||||
accountNumber: bridgeData.accountNumbers[action.accountId.toNumber()],
|
||||
market: action.marketId,
|
||||
update: [[false, scaledAmount]],
|
||||
update: { deltaWei: { sign: false, value: scaledAmount } },
|
||||
to: receiver,
|
||||
});
|
||||
break;
|
||||
@@ -112,10 +112,10 @@ blockchainTests.fork.skip('Mainnet dydx bridge tests', env => {
|
||||
expect(log.args.from, 'from').to.equal(expectedEvent.from);
|
||||
// We only check the first update field because it's the delta balance (amount deposited).
|
||||
// The next field is the new total, which depends on interest rates at the time of execution.
|
||||
expect(log.args.update[0][0], 'update sign').to.equal(expectedEvent.update[0][0]);
|
||||
const updateValueHex = log.args.update[0][1]._hex;
|
||||
const updateValueBn = new BigNumber(updateValueHex, 16);
|
||||
expect(updateValueBn, 'update value').to.bignumber.equal(expectedEvent.update[0][1]);
|
||||
expect(log.args.update.deltaWei.sign, 'update sign').to.equal(expectedEvent.update.deltaWei.sign);
|
||||
expect(log.args.update.deltaWei.value, 'update value').to.bignumber.equal(
|
||||
expectedEvent.update.deltaWei.value,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1,14 +1,17 @@
|
||||
import {
|
||||
artifacts as BrokerArtifacts,
|
||||
BrokerContract,
|
||||
godsUnchainedUtils,
|
||||
decodeBrokerAssetData,
|
||||
decodePropertyData,
|
||||
encodeBrokerAssetData,
|
||||
encodePropertyData,
|
||||
GodsUnchainedValidatorContract,
|
||||
TestGodsUnchainedContract,
|
||||
} from '@0x/contracts-broker';
|
||||
import { DummyERC721TokenContract } from '@0x/contracts-erc721';
|
||||
import { ExchangeFunctionName, ExchangeRevertErrors } from '@0x/contracts-exchange';
|
||||
import { ReferenceFunctions } from '@0x/contracts-exchange-libs';
|
||||
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, constants, expect, getRandomInteger, randomAddress } from '@0x/contracts-test-utils';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
@@ -72,13 +75,10 @@ blockchainTests.resets('Broker <> Gods Unchained integration tests', env => {
|
||||
deployment.tokens.weth.address,
|
||||
);
|
||||
|
||||
const takerAssetData = godsUnchainedUtils.encodeBrokerAssetData(
|
||||
broker.address,
|
||||
godsUnchained.address,
|
||||
validator.address,
|
||||
makerSpecifiedProto,
|
||||
makerSpecifiedQuality,
|
||||
);
|
||||
const takerAssetData = encodeBrokerAssetData(broker.address, godsUnchained.address, validator.address, {
|
||||
proto: makerSpecifiedProto,
|
||||
quality: makerSpecifiedQuality,
|
||||
});
|
||||
|
||||
const orderConfig = {
|
||||
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||
@@ -530,22 +530,16 @@ blockchainTests.resets('Broker <> Gods Unchained integration tests', env => {
|
||||
|
||||
orders = [
|
||||
await maker.signOrderAsync({
|
||||
takerAssetData: godsUnchainedUtils.encodeBrokerAssetData(
|
||||
broker.address,
|
||||
godsUnchained.address,
|
||||
validator.address,
|
||||
firstOrderProto,
|
||||
firstOrderQuality,
|
||||
),
|
||||
takerAssetData: encodeBrokerAssetData(broker.address, godsUnchained.address, validator.address, {
|
||||
proto: firstOrderProto,
|
||||
quality: firstOrderQuality,
|
||||
}),
|
||||
}),
|
||||
await maker.signOrderAsync({
|
||||
takerAssetData: godsUnchainedUtils.encodeBrokerAssetData(
|
||||
broker.address,
|
||||
godsUnchained.address,
|
||||
validator.address,
|
||||
secondOrderProto,
|
||||
secondOrderQuality,
|
||||
),
|
||||
takerAssetData: encodeBrokerAssetData(broker.address, godsUnchained.address, validator.address, {
|
||||
proto: secondOrderProto,
|
||||
quality: secondOrderQuality,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
});
|
||||
@@ -718,4 +712,30 @@ blockchainTests.resets('Broker <> Gods Unchained integration tests', env => {
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Data encoding/decoding tools', () => {
|
||||
const MAX_UINT8 = 2 ** 8 - 1;
|
||||
const MAX_UINT16 = 2 ** 16 - 1;
|
||||
|
||||
it('correctly decodes property data', async () => {
|
||||
const properties = {
|
||||
proto: getRandomInteger(0, MAX_UINT16),
|
||||
quality: getRandomInteger(0, MAX_UINT8),
|
||||
};
|
||||
const encoded = encodePropertyData(properties);
|
||||
const decoded = decodePropertyData(encoded);
|
||||
expect(decoded.proto).to.bignumber.equal(properties.proto);
|
||||
expect(decoded.quality).to.bignumber.equal(properties.quality);
|
||||
});
|
||||
it('correctly decodes broker asset data', async () => {
|
||||
const properties = {
|
||||
proto: getRandomInteger(0, MAX_UINT16),
|
||||
quality: getRandomInteger(0, MAX_UINT8),
|
||||
};
|
||||
const encoded = encodeBrokerAssetData(randomAddress(), randomAddress(), randomAddress(), properties);
|
||||
const decoded = decodeBrokerAssetData(encoded);
|
||||
expect(decoded.proto).to.bignumber.equal(properties.proto);
|
||||
expect(decoded.quality).to.bignumber.equal(properties.quality);
|
||||
});
|
||||
});
|
||||
}); // tslint:disable-line:max-file-line-count
|
||||
|
@@ -434,6 +434,25 @@ blockchainTests.resets('OrderValidationUtils/OrderTransferSimulatorUtils', env =
|
||||
expect(fillableTakerAssetAmount).to.bignumber.equal(signedOrder.takerAssetAmount);
|
||||
expect(isValidSignature).to.equal(true);
|
||||
});
|
||||
it('should not revert when rounding errors occur', async () => {
|
||||
signedOrder = await maker.signOrderAsync({
|
||||
makerAssetAmount: new BigNumber('2040250070'),
|
||||
takerAssetAmount: new BigNumber('2040250070000000000000'),
|
||||
makerFee: new BigNumber(0),
|
||||
takerFee: new BigNumber(0),
|
||||
});
|
||||
await erc20Token.setBalance(maker.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync();
|
||||
await erc20Token.approve(erc20Proxy.address, signedOrder.makerAssetAmount).awaitTransactionSuccessAsync({
|
||||
from: maker.address,
|
||||
});
|
||||
await erc20Token2.setBalance(taker.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync();
|
||||
await erc20Token2.approve(erc20Proxy.address, signedOrder.takerAssetAmount).awaitTransactionSuccessAsync({
|
||||
from: taker.address,
|
||||
});
|
||||
await taker.configureERC20TokenAsync(deployment.tokens.weth, deployment.staking.stakingProxy.address);
|
||||
await taker.fillOrderAsync(signedOrder, new BigNumber('2040250069999999999990'));
|
||||
await devUtils.getOrderRelevantState(signedOrder, signedOrder.signature).callAsync();
|
||||
});
|
||||
});
|
||||
describe('getOrderRelevantStates', async () => {
|
||||
it('should return the correct information for multiple orders', async () => {
|
||||
|
@@ -3,7 +3,7 @@ import { ContractWrappers } from '@0x/contract-wrappers';
|
||||
import { Web3ProviderEngine } from '@0x/dev-utils';
|
||||
|
||||
const chainId = 1;
|
||||
export const dydxAccountOwner = '0xeb58c2caa96f39626dcceb74fdbb7a9a8b54ec18';
|
||||
export const dydxAccountOwner = '0xfdac948232c5bfbe24b770326ee4dff7a8dd8484';
|
||||
export const contractAddresses = getContractAddressesForChainOrThrow(chainId);
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,192 @@
|
||||
import { ExchangeRevertErrors } from '@0x/contracts-exchange';
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
orderHashUtils,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber, StringRevertError } from '@0x/utils';
|
||||
|
||||
import {
|
||||
decodeChainlinkStopLimitData,
|
||||
decodeStopLimitStaticCallData,
|
||||
encodeChainlinkStopLimitData,
|
||||
encodeStopLimitStaticCallData,
|
||||
} from '../../src/chainlink_utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { Actor } from '../framework/actors/base';
|
||||
import { Maker } from '../framework/actors/maker';
|
||||
import { Taker } from '../framework/actors/taker';
|
||||
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||
import { LocalBalanceStore } from '../framework/balances/local_balance_store';
|
||||
import { DeploymentManager } from '../framework/deployment_manager';
|
||||
import { ChainlinkStopLimitContract, TestChainlinkAggregatorContract } from '../wrappers';
|
||||
|
||||
blockchainTests.resets('Chainlink stop-limit order tests', env => {
|
||||
let deployment: DeploymentManager;
|
||||
let balanceStore: BlockchainBalanceStore;
|
||||
let initialBalances: LocalBalanceStore;
|
||||
|
||||
let chainLinkAggregator: TestChainlinkAggregatorContract;
|
||||
let chainlinkStopLimit: ChainlinkStopLimitContract;
|
||||
|
||||
let maker: Maker;
|
||||
let taker: Taker;
|
||||
|
||||
let order: SignedOrder;
|
||||
|
||||
const minPrice = new BigNumber(42);
|
||||
const maxPrice = new BigNumber(1337);
|
||||
|
||||
before(async () => {
|
||||
deployment = await DeploymentManager.deployAsync(env, {
|
||||
numErc20TokensToDeploy: 2,
|
||||
numErc721TokensToDeploy: 0,
|
||||
numErc1155TokensToDeploy: 0,
|
||||
});
|
||||
const [makerToken, takerToken] = deployment.tokens.erc20;
|
||||
|
||||
chainlinkStopLimit = await ChainlinkStopLimitContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ChainlinkStopLimit,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
chainLinkAggregator = await TestChainlinkAggregatorContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestChainlinkAggregator,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
|
||||
const makerAssetData = assetDataUtils.encodeMultiAssetData(
|
||||
[new BigNumber(1), new BigNumber(1)],
|
||||
[
|
||||
assetDataUtils.encodeERC20AssetData(makerToken.address),
|
||||
encodeStopLimitStaticCallData(chainlinkStopLimit.address, {
|
||||
oracle: chainLinkAggregator.address,
|
||||
minPrice,
|
||||
maxPrice,
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
const orderConfig = {
|
||||
feeRecipientAddress: constants.NULL_ADDRESS,
|
||||
makerAssetData,
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken.address),
|
||||
makerFeeAssetData: constants.NULL_BYTES,
|
||||
takerFeeAssetData: constants.NULL_BYTES,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
};
|
||||
|
||||
maker = new Maker({
|
||||
name: 'Maker',
|
||||
deployment,
|
||||
orderConfig,
|
||||
});
|
||||
taker = new Taker({ name: 'Taker', deployment });
|
||||
|
||||
// Set balances and allowances
|
||||
await maker.configureERC20TokenAsync(makerToken);
|
||||
await taker.configureERC20TokenAsync(takerToken);
|
||||
|
||||
order = await maker.signOrderAsync();
|
||||
|
||||
// Set up balance stores
|
||||
const tokenOwners = {
|
||||
Maker: maker.address,
|
||||
Taker: taker.address,
|
||||
};
|
||||
const tokenContracts = {
|
||||
erc20: { makerToken, takerToken },
|
||||
};
|
||||
balanceStore = new BlockchainBalanceStore(tokenOwners, tokenContracts);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
initialBalances = LocalBalanceStore.create(balanceStore);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
Actor.reset();
|
||||
});
|
||||
|
||||
describe('filling stop-limit orders', () => {
|
||||
it('fillOrder reverts if price < minPrice', async () => {
|
||||
await chainLinkAggregator.setPrice(minPrice.minus(1)).awaitTransactionSuccessAsync();
|
||||
const tx = taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAssetData,
|
||||
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('fillOrder reverts price > maxPrice', async () => {
|
||||
await chainLinkAggregator.setPrice(maxPrice.plus(1)).awaitTransactionSuccessAsync();
|
||||
const tx = taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
const expectedError = new ExchangeRevertErrors.AssetProxyTransferError(
|
||||
orderHashUtils.getOrderHashHex(order),
|
||||
order.makerAssetData,
|
||||
new StringRevertError('ChainlinkStopLimit/OUT_OF_PRICE_RANGE').encode(),
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('fillOrder succeeds if price = minPrice', async () => {
|
||||
await chainLinkAggregator.setPrice(minPrice).awaitTransactionSuccessAsync();
|
||||
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
const expectedBalances = LocalBalanceStore.create(initialBalances);
|
||||
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
it('fillOrder succeeds if price = maxPrice', async () => {
|
||||
await chainLinkAggregator.setPrice(maxPrice).awaitTransactionSuccessAsync();
|
||||
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
const expectedBalances = LocalBalanceStore.create(initialBalances);
|
||||
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
it('fillOrder succeeds if minPrice < price < maxPrice', async () => {
|
||||
await chainLinkAggregator
|
||||
.setPrice(minPrice.plus(maxPrice).dividedToIntegerBy(2))
|
||||
.awaitTransactionSuccessAsync();
|
||||
const receipt = await taker.fillOrderAsync(order, order.takerAssetAmount);
|
||||
const expectedBalances = LocalBalanceStore.create(initialBalances);
|
||||
expectedBalances.simulateFills([order], taker.address, receipt, deployment, DeploymentManager.protocolFee);
|
||||
await balanceStore.updateBalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Data encoding/decoding tools', () => {
|
||||
const MAX_INT256 = new BigNumber(2).exponentiatedBy(255).minus(1);
|
||||
|
||||
it('correctly decodes chainlink stop-limit params', async () => {
|
||||
const params = {
|
||||
oracle: randomAddress(),
|
||||
minPrice: getRandomInteger(0, MAX_INT256),
|
||||
maxPrice: getRandomInteger(0, MAX_INT256),
|
||||
};
|
||||
const encoded = encodeChainlinkStopLimitData(params);
|
||||
const decoded = decodeChainlinkStopLimitData(encoded);
|
||||
expect(decoded).to.deep.equal(params);
|
||||
});
|
||||
it('correctly decodes stop-limit assetData', async () => {
|
||||
const params = {
|
||||
oracle: randomAddress(),
|
||||
minPrice: getRandomInteger(0, MAX_INT256),
|
||||
maxPrice: getRandomInteger(0, MAX_INT256),
|
||||
};
|
||||
const encoded = encodeStopLimitStaticCallData(chainlinkStopLimit.address, params);
|
||||
const decoded = decodeStopLimitStaticCallData(encoded);
|
||||
expect(decoded).to.deep.equal(params);
|
||||
});
|
||||
});
|
||||
});
|
@@ -3,6 +3,9 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../test/generated-wrappers/chainlink_stop_limit';
|
||||
export * from '../test/generated-wrappers/i_chainlink_aggregator';
|
||||
export * from '../test/generated-wrappers/test_chainlink_aggregator';
|
||||
export * from '../test/generated-wrappers/test_contract_wrapper';
|
||||
export * from '../test/generated-wrappers/test_dydx_user';
|
||||
export * from '../test/generated-wrappers/test_eth2_dai';
|
||||
|
@@ -4,6 +4,9 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/TestFramework.json",
|
||||
"test/generated-artifacts/ChainlinkStopLimit.json",
|
||||
"test/generated-artifacts/IChainlinkAggregator.json",
|
||||
"test/generated-artifacts/TestChainlinkAggregator.json",
|
||||
"test/generated-artifacts/TestContractWrapper.json",
|
||||
"test/generated-artifacts/TestDydxUser.json",
|
||||
"test/generated-artifacts/TestEth2Dai.json",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "4.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.0 - _February 8, 2020_
|
||||
|
||||
* Fix broken tests (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-multisig",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,11 +50,11 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "2.0.8",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.0.7",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.8 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.7 - _February 8, 2020_
|
||||
|
||||
* Fix revert for `LibFixedMath.mul(x, 0)`. (#2462)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-staking",
|
||||
"version": "2.0.7",
|
||||
"version": "2.0.8",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -54,14 +54,14 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.0",
|
||||
"@0x/contracts-dev-utils": "^1.1.0",
|
||||
"@0x/contracts-erc20": "^3.1.0",
|
||||
"@0x/contracts-exchange-libs": "^4.3.0",
|
||||
"@0x/contracts-asset-proxy": "^3.2.1",
|
||||
"@0x/contracts-dev-utils": "^1.1.1",
|
||||
"@0x/contracts-erc20": "^3.1.1",
|
||||
"@0x/contracts-exchange-libs": "^4.3.1",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-utils": "^4.3.0",
|
||||
"@0x/contracts-utils": "^4.3.1",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
"@0x/utils": "^5.4.0",
|
||||
"ethereum-types": "^3.1.0",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "5.1.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1581204851,
|
||||
"version": "5.1.4",
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.1.5 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.1.4 - _February 8, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-test-utils",
|
||||
"version": "5.1.4",
|
||||
"version": "5.1.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -44,10 +44,10 @@
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.6",
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contract-addresses": "^4.5.0",
|
||||
"@0x/contract-addresses": "^4.6.0",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/json-schemas": "^5.0.6",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-coverage": "^4.0.7",
|
||||
"@0x/sol-profiler": "^4.0.7",
|
||||
"@0x/sol-trace": "^3.0.7",
|
||||
|
@@ -20,7 +20,12 @@ export let providerConfigs: Web3Config = {
|
||||
shouldUseInProcessGanache: true,
|
||||
shouldAllowUnlimitedContractSize: true,
|
||||
hardfork: 'istanbul',
|
||||
unlocked_accounts: ['0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', '0x55dc8f21d20d4c6ed3c82916a438a413ca68e335'],
|
||||
unlocked_accounts: [
|
||||
'0x6cc5f688a315f3dc28a7781717a9a798a59fda7b',
|
||||
'0x55dc8f21d20d4c6ed3c82916a438a413ca68e335',
|
||||
'0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0', // ERC20BridgeProxy
|
||||
'0xf977814e90da44bfa03b6295a0616a897441acec', // Binance: USDC, TUSD
|
||||
],
|
||||
};
|
||||
|
||||
export const provider: Web3ProviderEngine = web3Factory.getRpcProvider(providerConfigs);
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "4.3.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.3.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.3.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.3.0 - _February 8, 2020_
|
||||
|
||||
* Update Eth2Dai addresses in `DeploymentConstants` (#2474)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-utils",
|
||||
"version": "4.3.0",
|
||||
"version": "4.3.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,9 +52,9 @@
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.2.0",
|
||||
"@0x/contracts-gen": "^2.0.7",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/sol-compiler": "^4.0.7",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.2",
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1581748629,
|
||||
"version": "9.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "9.1.0",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v9.1.1 - _February 15, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v9.1.0 - _February 8, 2020_
|
||||
|
||||
* Export `EvmBytecodeOutputLinkReferences` (#2462)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "9.1.0",
|
||||
"version": "9.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -46,9 +46,9 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@0x/contract-addresses": "^4.5.0",
|
||||
"@0x/contract-addresses": "^4.6.0",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/migrations": "^6.1.0",
|
||||
"@0x/migrations": "^6.2.0",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
@@ -79,10 +79,10 @@
|
||||
"dependencies": {
|
||||
"@0x/abi-gen-wrappers": "^5.4.0-beta.3",
|
||||
"@0x/assert": "^3.0.6",
|
||||
"@0x/asset-swapper": "^4.1.2",
|
||||
"@0x/asset-swapper": "^4.2.0",
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contract-wrappers": "^13.5.0",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/contract-wrappers": "^13.6.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/subproviders": "^6.0.7",
|
||||
"@0x/types": "^3.1.2",
|
||||
"@0x/typescript-typings": "^5.0.2",
|
||||
|
@@ -1,4 +1,18 @@
|
||||
[
|
||||
{
|
||||
"version": "4.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Use `batchCall()` version of the `ERC20BridgeSampler` contract",
|
||||
"pr": 2477
|
||||
},
|
||||
{
|
||||
"note": "Support for sampling Curve contracts",
|
||||
"pr": 2483
|
||||
}
|
||||
],
|
||||
"timestamp": 1581748629
|
||||
},
|
||||
{
|
||||
"timestamp": 1581204851,
|
||||
"version": "4.1.2",
|
||||
|
@@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.2.0 - _February 15, 2020_
|
||||
|
||||
* Use `batchCall()` version of the `ERC20BridgeSampler` contract (#2477)
|
||||
* Support for sampling Curve contracts (#2483)
|
||||
|
||||
## v4.1.2 - _February 8, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/asset-swapper",
|
||||
"version": "4.1.2",
|
||||
"version": "4.2.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -42,11 +42,11 @@
|
||||
"homepage": "https://0x.org/asset-swapper",
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.6",
|
||||
"@0x/contract-addresses": "^4.5.0",
|
||||
"@0x/contract-wrappers": "^13.5.0",
|
||||
"@0x/contract-addresses": "^4.6.0",
|
||||
"@0x/contract-wrappers": "^13.6.0",
|
||||
"@0x/json-schemas": "^5.0.6",
|
||||
"@0x/order-utils": "^10.2.0",
|
||||
"@0x/orderbook": "^2.2.0",
|
||||
"@0x/order-utils": "^10.2.1",
|
||||
"@0x/orderbook": "^2.2.1",
|
||||
"@0x/utils": "^5.4.0",
|
||||
"@0x/web3-wrapper": "^7.0.6",
|
||||
"heartbeats": "^5.0.1",
|
||||
@@ -54,10 +54,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/base-contract": "^6.2.0",
|
||||
"@0x/contracts-test-utils": "^5.1.4",
|
||||
"@0x/contracts-test-utils": "^5.1.5",
|
||||
"@0x/dev-utils": "^3.2.0",
|
||||
"@0x/mesh-rpc-client": "^7.0.4-beta-0xv3",
|
||||
"@0x/migrations": "^6.1.0",
|
||||
"@0x/migrations": "^6.2.0",
|
||||
"@0x/subproviders": "^6.0.7",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
|
@@ -12,6 +12,7 @@ import {
|
||||
} from './types';
|
||||
|
||||
import { constants as marketOperationUtilConstants } from './utils/market_operation_utils/constants';
|
||||
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
|
||||
|
||||
const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info';
|
||||
const NULL_BYTES = '0x';
|
||||
@@ -42,7 +43,7 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
|
||||
orderRefreshIntervalMs: 10000, // 10 seconds
|
||||
},
|
||||
...DEFAULT_ORDER_PRUNER_OPTS,
|
||||
samplerGasLimit: 36e6,
|
||||
samplerGasLimit: 59e6,
|
||||
};
|
||||
|
||||
const DEFAULT_FORWARDER_EXTENSION_CONTRACT_OPTS: ForwarderExtensionContractOpts = {
|
||||
@@ -64,6 +65,34 @@ const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
|
||||
...marketOperationUtilConstants.DEFAULT_GET_MARKET_ORDERS_OPTS,
|
||||
};
|
||||
|
||||
// Mainnet Curve configuration
|
||||
const DEFAULT_CURVE_OPTS: { [source: string]: { version: number; curveAddress: string; tokens: string[] } } = {
|
||||
[ERC20BridgeSource.CurveUsdcDai]: {
|
||||
version: 0,
|
||||
curveAddress: '0x2e60cf74d81ac34eb21eeff58db4d385920ef419',
|
||||
tokens: ['0x6b175474e89094c44da98b954eedeac495271d0f', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
|
||||
},
|
||||
[ERC20BridgeSource.CurveUsdcDaiUsdt]: {
|
||||
version: 1,
|
||||
curveAddress: '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c',
|
||||
tokens: [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7',
|
||||
],
|
||||
},
|
||||
[ERC20BridgeSource.CurveUsdcDaiUsdtTusd]: {
|
||||
version: 1,
|
||||
curveAddress: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51',
|
||||
tokens: [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7',
|
||||
'0x0000000000085d4780b73119b644ae5ecd22b376',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const constants = {
|
||||
ETH_GAS_STATION_API_BASE_URL,
|
||||
PROTOCOL_FEE_MULTIPLIER,
|
||||
@@ -84,4 +113,5 @@ export const constants = {
|
||||
PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
|
||||
MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE,
|
||||
BRIDGE_ASSET_DATA_PREFIX: '0xdc1600f3',
|
||||
DEFAULT_CURVE_OPTS,
|
||||
};
|
||||
|
@@ -21,7 +21,7 @@ import {
|
||||
} from './types';
|
||||
import { assert } from './utils/assert';
|
||||
import { calculateLiquidity } from './utils/calculate_liquidity';
|
||||
import { MarketOperationUtils } from './utils/market_operation_utils';
|
||||
import { DexOrderSampler, MarketOperationUtils } from './utils/market_operation_utils';
|
||||
import { dummyOrderUtils } from './utils/market_operation_utils/dummy_order_utils';
|
||||
import { orderPrunerUtils } from './utils/order_prune_utils';
|
||||
import { OrderStateUtils } from './utils/order_state_utils';
|
||||
@@ -162,12 +162,12 @@ export class SwapQuoter {
|
||||
this._devUtilsContract = new DevUtilsContract(this._contractAddresses.devUtils, provider);
|
||||
this._protocolFeeUtils = new ProtocolFeeUtils(constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS);
|
||||
this._orderStateUtils = new OrderStateUtils(this._devUtilsContract);
|
||||
const samplerContract = new IERC20BridgeSamplerContract(
|
||||
this._contractAddresses.erc20BridgeSampler,
|
||||
this.provider,
|
||||
{ gas: samplerGasLimit },
|
||||
const sampler = new DexOrderSampler(
|
||||
new IERC20BridgeSamplerContract(this._contractAddresses.erc20BridgeSampler, this.provider, {
|
||||
gas: samplerGasLimit,
|
||||
}),
|
||||
);
|
||||
this._marketOperationUtils = new MarketOperationUtils(samplerContract, this._contractAddresses, {
|
||||
this._marketOperationUtils = new MarketOperationUtils(sampler, this._contractAddresses, {
|
||||
chainId,
|
||||
exchangeAddress: this._contractAddresses.exchange,
|
||||
});
|
||||
|
@@ -4,19 +4,17 @@ import { ERC20BridgeSource, GetMarketOrdersOpts } from './types';
|
||||
|
||||
const INFINITE_TIMESTAMP_SEC = new BigNumber(2524604400);
|
||||
|
||||
/**
|
||||
* Convert a source to a canonical address used by the sampler contract.
|
||||
*/
|
||||
const SOURCE_TO_ADDRESS: { [key: string]: string } = {
|
||||
[ERC20BridgeSource.Eth2Dai]: '0x39755357759ce0d7f32dc8dc45414cca409ae24e',
|
||||
[ERC20BridgeSource.Uniswap]: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95',
|
||||
[ERC20BridgeSource.Kyber]: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
|
||||
};
|
||||
|
||||
/**
|
||||
* Valid sources for market sell.
|
||||
*/
|
||||
export const SELL_SOURCES = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber];
|
||||
export const SELL_SOURCES = [
|
||||
ERC20BridgeSource.Uniswap,
|
||||
ERC20BridgeSource.Eth2Dai,
|
||||
ERC20BridgeSource.Kyber,
|
||||
ERC20BridgeSource.CurveUsdcDai,
|
||||
ERC20BridgeSource.CurveUsdcDaiUsdt,
|
||||
ERC20BridgeSource.CurveUsdcDaiUsdtTusd,
|
||||
];
|
||||
|
||||
/**
|
||||
* Valid sources for market buy.
|
||||
@@ -36,7 +34,6 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
|
||||
|
||||
export const constants = {
|
||||
INFINITE_TIMESTAMP_SEC,
|
||||
SOURCE_TO_ADDRESS,
|
||||
SELL_SOURCES,
|
||||
BUY_SOURCES,
|
||||
DEFAULT_GET_MARKET_ORDERS_OPTS,
|
||||
|
@@ -90,6 +90,10 @@ export class CreateOrderUtils {
|
||||
return this._contractAddress.kyberBridge;
|
||||
case ERC20BridgeSource.Uniswap:
|
||||
return this._contractAddress.uniswapBridge;
|
||||
case ERC20BridgeSource.CurveUsdcDai:
|
||||
case ERC20BridgeSource.CurveUsdcDaiUsdt:
|
||||
case ERC20BridgeSource.CurveUsdcDaiUsdtTusd:
|
||||
return this._contractAddress.curveBridge;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -106,13 +110,30 @@ function createBridgeOrder(
|
||||
slippage: number,
|
||||
isBuy: boolean = false,
|
||||
): OptimizedMarketOrder {
|
||||
return {
|
||||
makerAddress: bridgeAddress,
|
||||
makerAssetData: assetDataUtils.encodeERC20BridgeAssetData(
|
||||
let makerAssetData;
|
||||
if (
|
||||
fill.source === ERC20BridgeSource.CurveUsdcDai ||
|
||||
fill.source === ERC20BridgeSource.CurveUsdcDaiUsdt ||
|
||||
fill.source === ERC20BridgeSource.CurveUsdcDaiUsdtTusd
|
||||
) {
|
||||
const { curveAddress, tokens, version } = constants.DEFAULT_CURVE_OPTS[fill.source];
|
||||
const fromTokenIdx = tokens.indexOf(takerToken);
|
||||
const toTokenIdx = tokens.indexOf(makerToken);
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
bridgeAddress,
|
||||
createCurveBridgeData(curveAddress, fromTokenIdx, toTokenIdx, version),
|
||||
);
|
||||
} else {
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
bridgeAddress,
|
||||
createBridgeData(takerToken),
|
||||
),
|
||||
);
|
||||
}
|
||||
return {
|
||||
makerAddress: bridgeAddress,
|
||||
makerAssetData,
|
||||
takerAssetData: assetDataUtils.encodeERC20AssetData(takerToken),
|
||||
...createCommonOrderFields(orderDomain, fill, slippage, isBuy),
|
||||
};
|
||||
@@ -123,6 +144,21 @@ function createBridgeData(tokenAddress: string): string {
|
||||
return encoder.encode({ tokenAddress });
|
||||
}
|
||||
|
||||
function createCurveBridgeData(
|
||||
curveAddress: string,
|
||||
fromTokenIdx: number,
|
||||
toTokenIdx: number,
|
||||
version: number,
|
||||
): string {
|
||||
const curveBridgeDataEncoder = AbiEncoder.create([
|
||||
{ name: 'curveAddress', type: 'address' },
|
||||
{ name: 'fromTokenIdx', type: 'int128' },
|
||||
{ name: 'toTokenIdx', type: 'int128' },
|
||||
{ name: 'version', type: 'int128' },
|
||||
]);
|
||||
return curveBridgeDataEncoder.encode([curveAddress, fromTokenIdx, toTokenIdx, version]);
|
||||
}
|
||||
|
||||
type CommonOrderFields = Pick<
|
||||
OptimizedMarketOrder,
|
||||
Exclude<keyof OptimizedMarketOrder, 'makerAddress' | 'makerAssetData' | 'takerAssetData'>
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { ContractAddresses } from '@0x/contract-addresses';
|
||||
import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers';
|
||||
import { assetDataUtils, ERC20AssetData, orderCalculationUtils } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
@@ -11,7 +10,7 @@ import { fillableAmountsUtils } from '../fillable_amounts_utils';
|
||||
import { constants as marketOperationUtilConstants } from './constants';
|
||||
import { CreateOrderUtils } from './create_order';
|
||||
import { comparePathOutputs, FillsOptimizer, getPathOutput } from './fill_optimizer';
|
||||
import { DexOrderSampler } from './sampler';
|
||||
import { DexOrderSampler, getSampleAmounts } from './sampler';
|
||||
import {
|
||||
AggregationError,
|
||||
CollapsedFill,
|
||||
@@ -27,22 +26,20 @@ import {
|
||||
OrderDomain,
|
||||
} from './types';
|
||||
|
||||
export { DexOrderSampler } from './sampler';
|
||||
|
||||
const { ZERO_AMOUNT } = constants;
|
||||
const { BUY_SOURCES, DEFAULT_GET_MARKET_ORDERS_OPTS, ERC20_PROXY_ID, SELL_SOURCES } = marketOperationUtilConstants;
|
||||
|
||||
export class MarketOperationUtils {
|
||||
private readonly _dexSampler: DexOrderSampler;
|
||||
private readonly _createOrderUtils: CreateOrderUtils;
|
||||
private readonly _orderDomain: OrderDomain;
|
||||
|
||||
constructor(
|
||||
samplerContract: IERC20BridgeSamplerContract,
|
||||
private readonly _sampler: DexOrderSampler,
|
||||
contractAddresses: ContractAddresses,
|
||||
orderDomain: OrderDomain,
|
||||
private readonly _orderDomain: OrderDomain,
|
||||
) {
|
||||
this._dexSampler = new DexOrderSampler(samplerContract);
|
||||
this._createOrderUtils = new CreateOrderUtils(contractAddresses);
|
||||
this._orderDomain = orderDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,10 +62,15 @@ export class MarketOperationUtils {
|
||||
...DEFAULT_GET_MARKET_ORDERS_OPTS,
|
||||
...opts,
|
||||
};
|
||||
const [fillableAmounts, dexQuotes] = await this._dexSampler.getFillableAmountsAndSampleMarketSellAsync(
|
||||
nativeOrders,
|
||||
DexOrderSampler.getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
||||
difference(SELL_SOURCES, _opts.excludedSources),
|
||||
const [makerToken, takerToken] = getOrderTokens(nativeOrders[0]);
|
||||
const [fillableAmounts, dexQuotes] = await this._sampler.executeAsync(
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders),
|
||||
DexOrderSampler.ops.getSellQuotes(
|
||||
difference(SELL_SOURCES, _opts.excludedSources),
|
||||
makerToken,
|
||||
takerToken,
|
||||
getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
||||
),
|
||||
);
|
||||
const nativeOrdersWithFillableAmounts = createSignedOrdersWithFillableAmounts(
|
||||
nativeOrders,
|
||||
@@ -104,11 +106,10 @@ export class MarketOperationUtils {
|
||||
if (!optimalPath) {
|
||||
throw new Error(AggregationError.NoOptimalPath);
|
||||
}
|
||||
const [outputToken, inputToken] = getOrderTokens(nativeOrders[0]);
|
||||
return this._createOrderUtils.createSellOrdersFromPath(
|
||||
this._orderDomain,
|
||||
inputToken,
|
||||
outputToken,
|
||||
takerToken,
|
||||
makerToken,
|
||||
collapsePath(optimalPath, false),
|
||||
_opts.bridgeSlippage,
|
||||
);
|
||||
@@ -134,11 +135,15 @@ export class MarketOperationUtils {
|
||||
...DEFAULT_GET_MARKET_ORDERS_OPTS,
|
||||
...opts,
|
||||
};
|
||||
|
||||
const [fillableAmounts, dexQuotes] = await this._dexSampler.getFillableAmountsAndSampleMarketBuyAsync(
|
||||
nativeOrders,
|
||||
DexOrderSampler.getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
||||
difference(BUY_SOURCES, _opts.excludedSources),
|
||||
const [makerToken, takerToken] = getOrderTokens(nativeOrders[0]);
|
||||
const [fillableAmounts, dexQuotes] = await this._sampler.executeAsync(
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders),
|
||||
DexOrderSampler.ops.getBuyQuotes(
|
||||
difference(BUY_SOURCES, _opts.excludedSources),
|
||||
makerToken,
|
||||
takerToken,
|
||||
getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
||||
),
|
||||
);
|
||||
const signedOrderWithFillableAmounts = this._createBuyOrdersPathFromSamplerResultIfExists(
|
||||
nativeOrders,
|
||||
@@ -174,17 +179,25 @@ export class MarketOperationUtils {
|
||||
...opts,
|
||||
};
|
||||
|
||||
const batchSampleResults = await this._dexSampler.getBatchFillableAmountsAndSampleMarketBuyAsync(
|
||||
batchNativeOrders,
|
||||
makerAmounts.map(makerAmount => DexOrderSampler.getSampleAmounts(makerAmount, _opts.numSamples)),
|
||||
difference(BUY_SOURCES, _opts.excludedSources),
|
||||
);
|
||||
return batchSampleResults.map(([fillableAmounts, dexQuotes], i) =>
|
||||
const sources = difference(BUY_SOURCES, _opts.excludedSources);
|
||||
const ops = [
|
||||
...batchNativeOrders.map(orders => DexOrderSampler.ops.getOrderFillableMakerAmounts(orders)),
|
||||
...batchNativeOrders.map((orders, i) =>
|
||||
DexOrderSampler.ops.getBuyQuotes(sources, getOrderTokens(orders[0])[0], getOrderTokens(orders[0])[1], [
|
||||
makerAmounts[i],
|
||||
]),
|
||||
),
|
||||
];
|
||||
const executeResults = await this._sampler.executeBatchAsync(ops);
|
||||
const batchFillableAmounts = executeResults.slice(0, batchNativeOrders.length) as BigNumber[][];
|
||||
const batchDexQuotes = executeResults.slice(batchNativeOrders.length) as DexSample[][][];
|
||||
|
||||
return batchFillableAmounts.map((fillableAmounts, i) =>
|
||||
this._createBuyOrdersPathFromSamplerResultIfExists(
|
||||
batchNativeOrders[i],
|
||||
makerAmounts[i],
|
||||
fillableAmounts,
|
||||
dexQuotes,
|
||||
batchDexQuotes[i],
|
||||
_opts,
|
||||
),
|
||||
);
|
||||
|
@@ -2,99 +2,379 @@ import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { constants as marketOperationUtilConstants } from './constants';
|
||||
import { constants } from '../../constants';
|
||||
|
||||
import { DexSample, ERC20BridgeSource } from './types';
|
||||
|
||||
const { SOURCE_TO_ADDRESS } = marketOperationUtilConstants;
|
||||
/**
|
||||
* A composable operation the be run in `DexOrderSampler.executeAsync()`.
|
||||
*/
|
||||
export interface BatchedOperation<TResult> {
|
||||
encodeCall(contract: IERC20BridgeSamplerContract): string;
|
||||
handleCallResultsAsync(contract: IERC20BridgeSamplerContract, callResults: string): Promise<TResult>;
|
||||
}
|
||||
|
||||
export class DexOrderSampler {
|
||||
private readonly _samplerContract: IERC20BridgeSamplerContract;
|
||||
|
||||
/**
|
||||
* Generate sample amounts up to `maxFillAmount`.
|
||||
*/
|
||||
public static getSampleAmounts(maxFillAmount: BigNumber, numSamples: number, expBase: number = 1): BigNumber[] {
|
||||
const distribution = [...Array<BigNumber>(numSamples)].map((v, i) => new BigNumber(expBase).pow(i));
|
||||
const stepSizes = distribution.map(d => d.div(BigNumber.sum(...distribution)));
|
||||
const amounts = stepSizes.map((s, i) => {
|
||||
return maxFillAmount
|
||||
.times(BigNumber.sum(...[0, ...stepSizes.slice(0, i + 1)]))
|
||||
.integerValue(BigNumber.ROUND_UP);
|
||||
/**
|
||||
* Composable operations that can be batched in a single transaction,
|
||||
* for use with `DexOrderSampler.executeAsync()`.
|
||||
*/
|
||||
const samplerOperations = {
|
||||
getOrderFillableTakerAmounts(orders: SignedOrder[]): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature))
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('getOrderFillableTakerAssetAmounts', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getOrderFillableMakerAmounts(orders: SignedOrder[]): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature))
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('getOrderFillableMakerAssetAmounts', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getKyberSellQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleSellsFromKyberNetwork(takerToken, makerToken, takerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromKyberNetwork', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getUniswapSellQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleSellsFromUniswap(takerToken, makerToken, takerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromUniswap', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getEth2DaiSellQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleSellsFromEth2Dai(takerToken, makerToken, takerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromEth2Dai', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getCurveSellQuotes(
|
||||
curveAddress: string,
|
||||
fromTokenIdx: number,
|
||||
toTokenIdx: number,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleSellsFromCurve(
|
||||
curveAddress,
|
||||
new BigNumber(fromTokenIdx),
|
||||
new BigNumber(toTokenIdx),
|
||||
takerFillAmounts,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromCurve', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getUniswapBuyQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleBuysFromUniswap(takerToken, makerToken, makerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleBuysFromUniswap', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getEth2DaiBuyQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleBuysFromEth2Dai(takerToken, makerToken, makerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleBuysFromEth2Dai', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getSellQuotes(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<DexSample[][]> {
|
||||
const subOps = sources
|
||||
.map(source => {
|
||||
let batchedOperation;
|
||||
if (source === ERC20BridgeSource.Eth2Dai) {
|
||||
batchedOperation = samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
} else if (source === ERC20BridgeSource.Uniswap) {
|
||||
batchedOperation = samplerOperations.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
} else if (source === ERC20BridgeSource.Kyber) {
|
||||
batchedOperation = samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
} else if (
|
||||
source === ERC20BridgeSource.CurveUsdcDai ||
|
||||
source === ERC20BridgeSource.CurveUsdcDaiUsdt ||
|
||||
source === ERC20BridgeSource.CurveUsdcDaiUsdtTusd
|
||||
) {
|
||||
const { curveAddress, tokens } = constants.DEFAULT_CURVE_OPTS[source];
|
||||
const fromTokenIdx = tokens.indexOf(takerToken);
|
||||
const toTokenIdx = tokens.indexOf(makerToken);
|
||||
if (fromTokenIdx !== -1 && toTokenIdx !== -1) {
|
||||
batchedOperation = samplerOperations.getCurveSellQuotes(
|
||||
curveAddress,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
takerFillAmounts,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
return { batchedOperation, source };
|
||||
})
|
||||
.filter(op => op.batchedOperation) as Array<{
|
||||
batchedOperation: BatchedOperation<BigNumber[]>;
|
||||
source: ERC20BridgeSource;
|
||||
}>;
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
const subCalls = subOps.map(op => op.batchedOperation.encodeCall(contract));
|
||||
return contract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
|
||||
const samples = await Promise.all(
|
||||
subOps.map(async (op, i) =>
|
||||
op.batchedOperation.handleCallResultsAsync(contract, rawSubCallResults[i]),
|
||||
),
|
||||
);
|
||||
return subOps.map((op, i) => {
|
||||
return samples[i].map((output, j) => ({
|
||||
source: op.source,
|
||||
output,
|
||||
input: takerFillAmounts[j],
|
||||
}));
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
getBuyQuotes(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): BatchedOperation<DexSample[][]> {
|
||||
const subOps = sources.map(source => {
|
||||
if (source === ERC20BridgeSource.Eth2Dai) {
|
||||
return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
} else if (source === ERC20BridgeSource.Uniswap) {
|
||||
return samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
} else {
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
});
|
||||
return amounts;
|
||||
}
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
const subCalls = subOps.map(op => op.encodeCall(contract));
|
||||
return contract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
|
||||
const samples = await Promise.all(
|
||||
subOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
|
||||
);
|
||||
return sources.map((source, i) => {
|
||||
return samples[i].map((output, j) => ({
|
||||
source,
|
||||
output,
|
||||
input: makerFillAmounts[j],
|
||||
}));
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate sample amounts up to `maxFillAmount`.
|
||||
*/
|
||||
export function getSampleAmounts(maxFillAmount: BigNumber, numSamples: number, expBase: number = 1): BigNumber[] {
|
||||
const distribution = [...Array<BigNumber>(numSamples)].map((v, i) => new BigNumber(expBase).pow(i));
|
||||
const stepSizes = distribution.map(d => d.div(BigNumber.sum(...distribution)));
|
||||
const amounts = stepSizes.map((s, i) => {
|
||||
return maxFillAmount
|
||||
.times(BigNumber.sum(...[0, ...stepSizes.slice(0, i + 1)]))
|
||||
.integerValue(BigNumber.ROUND_UP);
|
||||
});
|
||||
return amounts;
|
||||
}
|
||||
|
||||
type BatchedOperationResult<T> = T extends BatchedOperation<infer TResult> ? TResult : never;
|
||||
|
||||
/**
|
||||
* Encapsulates interactions with the `ERC20BridgeSampler` contract.
|
||||
*/
|
||||
export class DexOrderSampler {
|
||||
/**
|
||||
* Composable operations that can be batched in a single transaction,
|
||||
* for use with `DexOrderSampler.executeAsync()`.
|
||||
*/
|
||||
public static ops = samplerOperations;
|
||||
private readonly _samplerContract: IERC20BridgeSamplerContract;
|
||||
|
||||
constructor(samplerContract: IERC20BridgeSamplerContract) {
|
||||
this._samplerContract = samplerContract;
|
||||
}
|
||||
|
||||
public async getFillableAmountsAndSampleMarketBuyAsync(
|
||||
nativeOrders: SignedOrder[],
|
||||
sampleAmounts: BigNumber[],
|
||||
sources: ERC20BridgeSource[],
|
||||
): Promise<[BigNumber[], DexSample[][]]> {
|
||||
const signatures = nativeOrders.map(o => o.signature);
|
||||
const [fillableAmount, rawSamples] = await this._samplerContract
|
||||
.queryOrdersAndSampleBuys(nativeOrders, signatures, sources.map(s => SOURCE_TO_ADDRESS[s]), sampleAmounts)
|
||||
.callAsync();
|
||||
const quotes = rawSamples.map((rawDexSamples, sourceIdx) => {
|
||||
const source = sources[sourceIdx];
|
||||
return rawDexSamples.map((sample, sampleIdx) => ({
|
||||
source,
|
||||
input: sampleAmounts[sampleIdx],
|
||||
output: sample,
|
||||
}));
|
||||
});
|
||||
return [fillableAmount, quotes];
|
||||
/* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1
|
||||
>(...ops: [T1]): Promise<[
|
||||
BatchedOperationResult<T1>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2
|
||||
>(...ops: [T1, T2]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2, T3
|
||||
>(...ops: [T1, T2, T3]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>,
|
||||
BatchedOperationResult<T3>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2, T3, T4
|
||||
>(...ops: [T1, T2, T3, T4]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>,
|
||||
BatchedOperationResult<T3>,
|
||||
BatchedOperationResult<T4>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2, T3, T4, T5
|
||||
>(...ops: [T1, T2, T3, T4, T5]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>,
|
||||
BatchedOperationResult<T3>,
|
||||
BatchedOperationResult<T4>,
|
||||
BatchedOperationResult<T5>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2, T3, T4, T5, T6
|
||||
>(...ops: [T1, T2, T3, T4, T5, T6]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>,
|
||||
BatchedOperationResult<T3>,
|
||||
BatchedOperationResult<T4>,
|
||||
BatchedOperationResult<T5>,
|
||||
BatchedOperationResult<T6>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2, T3, T4, T5, T6, T7
|
||||
>(...ops: [T1, T2, T3, T4, T5, T6, T7]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>,
|
||||
BatchedOperationResult<T3>,
|
||||
BatchedOperationResult<T4>,
|
||||
BatchedOperationResult<T5>,
|
||||
BatchedOperationResult<T6>,
|
||||
BatchedOperationResult<T7>
|
||||
]>;
|
||||
|
||||
// prettier-ignore
|
||||
public async executeAsync<
|
||||
T1, T2, T3, T4, T5, T6, T7, T8
|
||||
>(...ops: [T1, T2, T3, T4, T5, T6, T7, T8]): Promise<[
|
||||
BatchedOperationResult<T1>,
|
||||
BatchedOperationResult<T2>,
|
||||
BatchedOperationResult<T3>,
|
||||
BatchedOperationResult<T4>,
|
||||
BatchedOperationResult<T5>,
|
||||
BatchedOperationResult<T6>,
|
||||
BatchedOperationResult<T7>,
|
||||
BatchedOperationResult<T8>
|
||||
]>;
|
||||
|
||||
/**
|
||||
* Run a series of operations from `DexOrderSampler.ops` in a single transaction.
|
||||
*/
|
||||
public async executeAsync(...ops: any[]): Promise<any[]> {
|
||||
return this.executeBatchAsync(ops);
|
||||
}
|
||||
|
||||
public async getBatchFillableAmountsAndSampleMarketBuyAsync(
|
||||
nativeOrders: SignedOrder[][],
|
||||
sampleAmounts: BigNumber[][],
|
||||
sources: ERC20BridgeSource[],
|
||||
): Promise<Array<[BigNumber[], DexSample[][]]>> {
|
||||
const signatures = nativeOrders.map(o => o.map(i => i.signature));
|
||||
const fillableAmountsAndSamples = await this._samplerContract
|
||||
.queryBatchOrdersAndSampleBuys(
|
||||
nativeOrders,
|
||||
signatures,
|
||||
sources.map(s => SOURCE_TO_ADDRESS[s]),
|
||||
sampleAmounts,
|
||||
)
|
||||
.callAsync();
|
||||
const batchFillableAmountsAndQuotes: Array<[BigNumber[], DexSample[][]]> = [];
|
||||
fillableAmountsAndSamples.forEach((sampleResult, i) => {
|
||||
const { tokenAmountsBySource, orderFillableAssetAmounts } = sampleResult;
|
||||
const quotes = tokenAmountsBySource.map((rawDexSamples, sourceIdx) => {
|
||||
const source = sources[sourceIdx];
|
||||
return rawDexSamples.map((sample, sampleIdx) => ({
|
||||
source,
|
||||
input: sampleAmounts[i][sampleIdx],
|
||||
output: sample,
|
||||
}));
|
||||
});
|
||||
batchFillableAmountsAndQuotes.push([orderFillableAssetAmounts, quotes]);
|
||||
});
|
||||
return batchFillableAmountsAndQuotes;
|
||||
}
|
||||
|
||||
public async getFillableAmountsAndSampleMarketSellAsync(
|
||||
nativeOrders: SignedOrder[],
|
||||
sampleAmounts: BigNumber[],
|
||||
sources: ERC20BridgeSource[],
|
||||
): Promise<[BigNumber[], DexSample[][]]> {
|
||||
const signatures = nativeOrders.map(o => o.signature);
|
||||
const [fillableAmount, rawSamples] = await this._samplerContract
|
||||
.queryOrdersAndSampleSells(nativeOrders, signatures, sources.map(s => SOURCE_TO_ADDRESS[s]), sampleAmounts)
|
||||
.callAsync();
|
||||
const quotes = rawSamples.map((rawDexSamples, sourceIdx) => {
|
||||
const source = sources[sourceIdx];
|
||||
return rawDexSamples.map((sample, sampleIdx) => ({
|
||||
source,
|
||||
input: sampleAmounts[sampleIdx],
|
||||
output: sample,
|
||||
}));
|
||||
});
|
||||
return [fillableAmount, quotes];
|
||||
/**
|
||||
* Run a series of operations from `DexOrderSampler.ops` in a single transaction.
|
||||
* Takes an arbitrary length array, but is not typesafe.
|
||||
*/
|
||||
public async executeBatchAsync<T extends Array<BatchedOperation<any>>>(ops: T): Promise<any[]> {
|
||||
const callDatas = ops.map(o => o.encodeCall(this._samplerContract));
|
||||
const callResults = await this._samplerContract.batchCall(callDatas).callAsync();
|
||||
return Promise.all(callResults.map(async (r, i) => ops[i].handleCallResultsAsync(this._samplerContract, r)));
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user