Compare commits

..

33 Commits

Author SHA1 Message Date
Jacob Evans
4a133ca36f Publish
- @0x/contracts-asset-proxy@3.2.1
 - @0x/contracts-broker@1.1.0
 - @0x/contracts-coordinator@3.1.1
 - @0x/contracts-dev-utils@1.1.1
 - @0x/contracts-erc1155@2.1.1
 - @0x/contracts-erc20-bridge-sampler@1.4.0
 - @0x/contracts-erc20@3.1.1
 - @0x/contracts-erc721@3.1.1
 - @0x/contracts-exchange-forwarder@4.2.1
 - @0x/contracts-exchange-libs@4.3.1
 - @0x/contracts-exchange@3.2.1
 - @0x/contracts-extensions@6.1.1
 - @0x/contracts-integrations@2.4.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.js@9.1.1
 - @0x/asset-swapper@4.2.0
 - @0x/contract-addresses@4.6.0
 - @0x/contract-artifacts@3.6.0
 - @0x/contract-wrappers-test@12.2.9
 - @0x/contract-wrappers@13.6.0
 - @0x/instant@1.0.46
 - @0x/migrations@6.2.0
 - @0x/order-utils@10.2.1
 - @0x/orderbook@2.2.1
2020-02-15 17:39:09 +11:00
Jacob Evans
f7252f919a Updated CHANGELOGS & MD docs 2020-02-15 17:38:47 +11:00
Jacob Evans
e05a03a842 Curve ERC20Bridge (#2480)
* Curve ERC20Bridge

* ERC20BridgeSampler Curve (#2483)

* ERC20Sampler Curve

* Use Bridge Sources for each Curve

* Support multiple versions of the Curve contract

* CHANGELOG and redeployed Curve (mainnet)

* Fix Market ops utils test

* Added Curve DAI USDC USDT TUSD

* Bump sampler gas limit default

* Decode the Curve in tests

* Disable Curve in Buy tests

* blockchainTests.fork.resets Curve and Sampler
2020-02-15 17:02:19 +11:00
mzhu25
dcce8276b8 Add decoders for broker and stop-limit data (#2484)
* Add decoders for broker and stop-limit data

* update changelogs

* Address comments
2020-02-14 17:38:43 -08:00
Alex Towle
fd47947e55 Merge pull request #2454 from 0xProject/fix/dev-utils/and-another-one
Another one...
2020-02-13 20:45:34 -08:00
Alex Towle
ae151df2eb Addressed amir's review feedback 2020-02-13 18:07:45 -08:00
Alex Towle
79de188683 Updated addresses again 2020-02-13 17:37:03 -08:00
Alex Towle
6e5c788e13 Added a test that fails for the old DevUtils 2020-02-13 17:37:03 -08:00
Alex Towle
f53606007d Updated DevUtils again 2020-02-13 17:37:03 -08:00
Greg Hysz
a4ac418bc9 Merge pull request #2479 from 0xProject/test/dydx-mainnet-tests/updateDeployment
Fixed dYdX Bridge Tests
2020-02-13 14:42:47 -08:00
Greg Hysen
a8c09d0bdb Updated contracts-integrations changelog. 2020-02-13 13:21:07 -08:00
Greg Hysen
871105a48a Fixed dYdX Bridge Tests 2020-02-13 13:19:26 -08:00
Fabio B
3b61129ade Update link to docs for web3-wrapper 2020-02-12 22:08:10 +01:00
mzhu25
f471c79b59 Chainlink stop-limit orders (#2473)
* Contracts for Chainlink stop-limit orders

* Tests and asset data utils

* Update contracts-integrations changelog

* Address comments

* Remove priceFreshness parameter

* Remove LibSafeMath

* fix typo

* Add ChainlinkStopLimit addresses to @0x/contract-addresses
2020-02-11 15:10:06 -08:00
Lawrence Forman
dfd9443f74 Merge pull request #2477 from 0xProject/feat/batched-sampler
ERC20BridgeSampler: batchCall()
2020-02-11 14:32:48 -07:00
Lawrence Forman
a36ff9e365 `@0x/asset-swapper: Address review comments. 2020-02-11 12:08:15 -07:00
Lawrence Forman
12e65bbf26 @0x/contracts-erc20-bridge-sampler: Fix failing tests. 2020-02-11 12:08:15 -07:00
Lawrence Forman
ab9841e60b @0x/contract-addresses: Update ERC20BridgeSampler addresses on mainnet and kovan. 2020-02-11 12:08:15 -07:00
Lawrence Forman
7a52f12e57 Rebase and update contract artifacts + wrappers. 2020-02-11 12:07:48 -07:00
Lawrence Forman
11fd4506ac @0x/asset-swapper: Fix failing asset-swapper test. 2020-02-11 12:07:48 -07:00
Lawrence Forman
0c9c68030e @0x/asset-swapper: Use batchCall() version of the ERC20BridgeSampler contract 2020-02-11 12:07:48 -07:00
Lawrence Forman
55d6eddbb2 @0x/contract-artifacts: Update IERC20BridgeSampler wrapper. 2020-02-11 12:07:48 -07:00
Lawrence Forman
8341e60edb @0x/contract-artifacts: Update ERC20BridgeSampler artifact. 2020-02-11 12:07:48 -07:00
Lawrence Forman
6273a1ca73 @0x/contracts-erc20-bridge-sampler: Remove wrapper functions and introduce batchCall(). 2020-02-11 12:07:48 -07:00
mzhu25
1b83ebdf89 Merge pull request #2469 from 0xProject/feature/broker/deployments
Broker-related updates to contract-artifacts, contract-wrappers, contract-addresses
2020-02-10 18:41:24 -08:00
Michael Zhu
fef7f0506f rebase 🙄 2020-02-10 17:38:16 -08:00
Michael Zhu
f44eb4e383 Update changelogs for Forwarder changes 2020-02-10 17:11:01 -08:00
Michael Zhu
05df485c4a Update Forwarder in contract-artifacts and contract-wrappers 2020-02-10 17:11:00 -08:00
Michael Zhu
44857c526b Remove DutchAuction and OrderValidator from python contract addresses 2020-02-10 17:10:36 -08:00
Michael Zhu
b8ad5d5d32 Update Forwarder addresses 2020-02-10 17:10:36 -08:00
Michael Zhu
e3e0d00e21 Add Broker and GodsUnchainedValidator to contract-wrappers 2020-02-10 17:10:14 -08:00
Michael Zhu
a9b1ea9690 Add Broker and GodsUnchainedValidator to contract-addresses 2020-02-10 17:09:34 -08:00
Michael Zhu
8e5dd0f8d9 Add Broker and GodsUnchainedValidator to contract-artifacts 2020-02-10 17:08:24 -08:00
141 changed files with 5447 additions and 2986 deletions

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "3.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.2.0",
"changes": [

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "1.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.1.0",
"changes": [

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "2.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.1.0",
"changes": [

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -327,7 +327,6 @@ contract TestERC20BridgeSampler is
bytes memory
)
public
view
returns (
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "4.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.2.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "4.3.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.3.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "3.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.2.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "6.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "6.1.0",
"changes": [

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -1,2 +1,3 @@
export { artifacts } from './artifacts';
export * from './wrappers';
export * from './chainlink_utils';

View File

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

View File

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

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

View File

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

View File

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

View File

@@ -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 () => {

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "4.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.1.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "2.0.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.0.7",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "5.1.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1581204851,
"version": "5.1.4",

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "4.3.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.3.0",
"changes": [

View File

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

View File

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

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1581748629,
"version": "9.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "9.1.0",
"changes": [

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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