Compare commits

...

32 Commits

Author SHA1 Message Date
Github Actions
03ecc530c3 Publish
- @0x/contracts-asset-proxy@3.7.3
 - @0x/contracts-broker@1.1.21
 - @0x/contracts-coordinator@3.1.22
 - @0x/contracts-dev-utils@1.3.20
 - @0x/contracts-erc1155@2.1.21
 - @0x/contracts-erc20@3.3.0
 - @0x/contracts-erc721@3.1.21
 - @0x/contracts-exchange-forwarder@4.2.22
 - @0x/contracts-exchange-libs@4.3.21
 - @0x/contracts-exchange@3.2.22
 - @0x/contracts-extensions@6.2.16
 - @0x/contracts-integrations@2.7.22
 - @0x/contracts-multisig@4.1.22
 - @0x/contracts-staking@2.0.29
 - @0x/contracts-test-utils@5.3.18
 - @0x/contracts-utils@4.7.0
 - @0x/contracts-zero-ex@0.17.0
 - @0x/asset-swapper@5.6.2
 - @0x/contract-artifacts@3.11.0
 - @0x/contract-wrappers-test@12.2.33
 - @0x/contract-wrappers@13.12.0
 - @0x/migrations@6.5.9
 - @0x/order-utils@10.4.13
 - @0x/protocol-utils@1.1.3
2021-01-04 23:22:36 +00:00
Github Actions
d52b1d24d0 Updated CHANGELOGS & MD docs 2021-01-04 23:22:26 +00:00
Lawrence Forman
5083fab06a That time DevUtils wouldn't die (#97)
* `@0x/contracts-utils`: Allow for excess return data in `LibERC20TokenV06` compat* functions

* `@0x/contracts-zero-ex`: Add DevUtils-like functions to `NativeOrdersFeature`

* `@0x/contract-artifacts`: Update IZeroEx artifact

* `@0x/contract-wrappers`: Update IZeroExContract wrapper

* `@0x/contracts-zero-ex`: Address review feedback

* `@0x/contracts-utils`: Add `LibSafeMathV06.safeDowncastToUint128()`

* `@0x/contracts-zero-ex`: Fix changelog and add cancelled get relevant state tests

* `@0x/contracts-utils`: Fix changelog

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-01-04 17:52:29 -05:00
Romain Butteaud
1249bf9ccc feat: adding UST, BBTC, OBTC, aDAI, aUSDC, aUSDT, sEUR, EURS, sETH pools (#103)
* feat: adding UST, BBTC, OBTC, aDAI, aUSDC, aUSDT, sEUR, EURS, sETH pools

* fix: comment seth curve pool

* fix: prettify, remove seth pool
2021-01-04 13:56:18 -08:00
Jacob Evans
681f6b3f07 chore: [asset-swapper] Update Shells to new version (#102) 2021-01-04 13:56:05 -08:00
Github Actions
d3ca1fe96b Publish
- @0x/contracts-integrations@2.7.21
 - @0x/asset-swapper@5.6.1
2020-12-31 04:02:02 +00:00
Github Actions
9e4f5815e4 Updated CHANGELOGS & MD docs 2020-12-31 04:01:53 +00:00
Jacob Evans
c3c27eaedc fix: [asset-swapper] Encoded Buy fillAmount (#106) 2020-12-31 13:18:25 +10:00
Github Actions
4bf6a23d23 Publish
- @0x/contracts-integrations@2.7.20
 - @0x/asset-swapper@5.6.0
2020-12-27 23:59:31 +00:00
Github Actions
aaaf0d02de Updated CHANGELOGS & MD docs 2020-12-27 23:59:23 +00:00
Jacob Evans
825cc4d035 feat: [asset-swapper] Added Mooniswap V2 factory address (#100) 2020-12-28 09:23:52 +10:00
Github Actions
c2d44e5c10 Publish
- @0x/contracts-asset-proxy@3.7.2
 - @0x/contracts-broker@1.1.20
 - @0x/contracts-coordinator@3.1.21
 - @0x/contracts-dev-utils@1.3.19
 - @0x/contracts-erc1155@2.1.20
 - @0x/contracts-erc20@3.2.14
 - @0x/contracts-erc721@3.1.20
 - @0x/contracts-exchange-forwarder@4.2.21
 - @0x/contracts-exchange-libs@4.3.20
 - @0x/contracts-exchange@3.2.21
 - @0x/contracts-extensions@6.2.15
 - @0x/contracts-integrations@2.7.19
 - @0x/contracts-multisig@4.1.21
 - @0x/contracts-staking@2.0.28
 - @0x/contracts-test-utils@5.3.17
 - @0x/contracts-utils@4.6.5
 - @0x/contracts-zero-ex@0.16.0
 - @0x/asset-swapper@5.5.3
 - @0x/contract-addresses@5.8.0
 - @0x/contract-wrappers-test@12.2.32
 - @0x/contract-wrappers@13.11.2
 - @0x/migrations@6.5.8
 - @0x/order-utils@10.4.12
 - @0x/protocol-utils@1.1.2
2020-12-23 02:55:08 +00:00
Github Actions
0efd0860c8 Updated CHANGELOGS & MD docs 2020-12-23 02:55:01 +00:00
Lawrence Forman
a890a06664 @0x/contract-addresses: Redeploy FQT (#99)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-12-23 13:13:49 +11:00
Jacob Evans
5befb87071 fix: CryptoCom rollup (#98) 2020-12-23 11:43:11 +11:00
mintcloud
12ba4c373a Update staking.md
Changed epoch length
2020-12-18 11:14:49 -08:00
Github Actions
7fd25be02e Publish
- @0x/contracts-asset-proxy@3.7.1
 - @0x/contracts-broker@1.1.19
 - @0x/contracts-coordinator@3.1.20
 - @0x/contracts-dev-utils@1.3.18
 - @0x/contracts-erc1155@2.1.19
 - @0x/contracts-erc20@3.2.13
 - @0x/contracts-erc721@3.1.19
 - @0x/contracts-exchange-forwarder@4.2.20
 - @0x/contracts-exchange-libs@4.3.19
 - @0x/contracts-exchange@3.2.20
 - @0x/contracts-extensions@6.2.14
 - @0x/contracts-integrations@2.7.18
 - @0x/contracts-multisig@4.1.20
 - @0x/contracts-staking@2.0.27
 - @0x/contracts-test-utils@5.3.16
 - @0x/contracts-utils@4.6.4
 - @0x/contracts-zero-ex@0.15.0
 - @0x/asset-swapper@5.5.2
 - @0x/contract-addresses@5.7.0
 - @0x/contract-wrappers-test@12.2.31
 - @0x/contract-wrappers@13.11.1
 - @0x/migrations@6.5.7
 - @0x/order-utils@10.4.11
 - @0x/protocol-utils@1.1.1
2020-12-17 22:52:27 +00:00
Github Actions
aa688c4a92 Updated CHANGELOGS & MD docs 2020-12-17 22:52:20 +00:00
mzhu25
fb437551c9 Bancor FQT rollup (#91)
* Add MixinBancor for BridgeAdapter

* Update changelog

* Use 0.6 call value syntax

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

* feat: Rollup CoFiX (#92)

* `@0x/contract-addreses`: update FQT addresses

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Jacob Evans <jacob@dekz.net>
2020-12-17 17:12:40 -05:00
Greg Hysz
6fa1de7889 Emergency docs (#94) 2020-12-17 10:24:16 -08:00
mzhu25
7a42df9a65 Only use subgraph query result to populate function history (#93)
* Only use subgraph query result to populate function history

* Fix rollback for functions with no rollback history
2020-12-16 23:14:19 -08:00
Github Actions
15a508f3ea Publish
- @0x/contracts-integrations@2.7.17
 - @0x/contracts-zero-ex@0.14.0
 - @0x/asset-swapper@5.5.1
 - @0x/contract-wrappers-test@12.2.30
 - @0x/migrations@6.5.6
 - @0x/protocol-utils@1.1.0
2020-12-16 20:09:57 +00:00
Github Actions
b3c20ff909 Updated CHANGELOGS & MD docs 2020-12-16 20:09:48 +00:00
Lawrence Forman
682c07cb73 Add mtx tooling to @0x/protocol-utils (#90)
* `@0x/contracts-zero-ex`: Use the `MetaTransaction` class from `@0x/protocol-utils` in tests.

* `@0x/protocol-utils`: Add the `MetaTransaction` class for EP mtxs + refactors

* update changelogs

* `@0x/protocol-utils`: Add mtx tests

* `@0x/protocol-utils`: Rename `mtx.ts` to `meta_transactions.ts` and misc review feedback

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-12-16 14:22:00 -05:00
Jacob Evans
602605ab4b Disable Bancor Service for non-mainnet (#89)
* Disable Bancor Service for non-mainnet

* Fix import

* Fix mocked tests
2020-12-16 21:58:39 +10:00
Github Actions
0eff2548d5 Publish
- @0x/contracts-asset-proxy@3.7.0
 - @0x/contracts-broker@1.1.18
 - @0x/contracts-coordinator@3.1.19
 - @0x/contracts-dev-utils@1.3.17
 - @0x/contracts-exchange-forwarder@4.2.19
 - @0x/contracts-exchange@3.2.19
 - @0x/contracts-extensions@6.2.13
 - @0x/contracts-integrations@2.7.16
 - @0x/contracts-multisig@4.1.19
 - @0x/contracts-staking@2.0.26
 - @0x/contracts-zero-ex@0.13.0
 - @0x/asset-swapper@5.5.0
 - @0x/contract-wrappers-test@12.2.29
 - @0x/migrations@6.5.5
2020-12-16 08:03:31 +00:00
Github Actions
93ee681204 Updated CHANGELOGS & MD docs 2020-12-16 08:03:25 +00:00
Jacob Evans
d7bea98075 fix: [asset-swapper] Rework Bancor to only use paths and sample best path (#88)
* Rework Bancor to only use paths and sample best path

* Deployed address

* Clean up and pin bancor sdk

* CHANGELOGs
2020-12-16 17:34:47 +10:00
Lawrence Forman
437a3b048d EP: Address audit feedback (#82)
* `@0x/contracts-zero-ex`: Address audit feedback (1/2)

* `@0x/contracts-zero-ex`: Cap the ETH transfer amount to a liquidity provider to `msg.value`

* `@0x/contracts-zero-ex`: Bump feature contract versions

* `@0x/contracts-zero-ex`: Always transfer msg.value to the liqudity provider in LiquiidityProviderFeature

* Remove PLP backwards-compatibility (#85)

* Remove backwards-compatibility from MixinZeroExBridge and LiquidityProviderSandbox

* `@0x/contracts-zero-ex`: Update CHANGELOG

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

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
2020-12-16 01:37:39 -05:00
Daniel Pyrathon
f55a9454b5 fix: Fix quote report (#87)
* updates market side liquidity with the appropriate firm and indicative quotes for reporting

* linting and fixing

* linting and fixing
2020-12-15 16:57:54 -08:00
Daniel Pyrathon
3b03ad0db4 fix: added SRA schema for V4 orders (#86)
* added SRA schema for V4 orders

* address comments
2020-12-14 17:39:42 -08:00
mzhu25
27d679e1f1 Rollback CLI tools (#79)
* Rollback CLI tools

* Refactor

* Address PR feedback

* Sort deployment history

* Rollback specific deployment

* Split calldata
2020-12-10 19:42:00 -08:00
131 changed files with 4807 additions and 860 deletions

View File

@@ -1,4 +1,41 @@
[
{
"timestamp": 1609802516,
"version": "3.7.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "3.7.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "3.7.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.7.0",
"changes": [
{
"note": "Fix Bancor support of ETH",
"pr": 88
}
],
"timestamp": 1608105788
},
{
"timestamp": 1607485227,
"version": "3.6.9",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.7.3 - _January 4, 2021_
* Dependencies updated
## v3.7.2 - _December 23, 2020_
* Dependencies updated
## v3.7.1 - _December 17, 2020_
* Dependencies updated
## v3.7.0 - _December 16, 2020_
* Fix Bancor support of ETH (#88)
## v3.6.9 - _December 9, 2020_
* Dependencies updated

View File

@@ -21,6 +21,7 @@ pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.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";
@@ -36,6 +37,20 @@ contract BancorBridge is
struct TransferState {
address bancorNetworkAddress;
address[] path;
IEtherToken weth;
}
/// @dev Bancor ETH pseudo-address.
address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// solhint-disable no-empty-blocks
/// @dev Payable fallback to receive ETH from Bancor/WETH.
function ()
external
payable
{
// Poor man's receive in 0.5.9
require(msg.data.length == 0);
}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
@@ -60,7 +75,6 @@ contract BancorBridge is
{
// hold variables to get around stack depth limitations
TransferState memory state;
// Decode the bridge data.
(
state.path,
@@ -68,34 +82,42 @@ contract BancorBridge is
// solhint-disable indent
) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
state.weth = IEtherToken(_getWethAddress());
require(state.path.length > 0, "BancorBridge/PATH_MUST_EXIST");
// Just transfer the tokens if they're the same.
if (state.path[0] == toTokenAddress) {
LibERC20Token.transfer(state.path[0], to, amount);
return BRIDGE_SUCCESS;
require(state.path.length >= 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO");
// Grant an allowance to the Bancor Network to spend `fromTokenAddress` token.
uint256 fromTokenBalance;
uint256 payableAmount = 0;
// If it's ETH in the path then withdraw from WETH
// The Bancor path will have ETH as the 0xeee address
// Bancor expects to be paid in ETH not WETH
if (state.path[0] == BANCOR_ETH_ADDRESS) {
fromTokenBalance = state.weth.balanceOf(address(this));
state.weth.withdraw(fromTokenBalance);
payableAmount = fromTokenBalance;
} else {
fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance);
}
// Otherwise use Bancor to convert
require(state.path.length > 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "BancorBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
// // Grant an allowance to the Bancor Network to spend `fromTokenAddress` token.
uint256 fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance);
// Convert the tokens
uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath(
uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath.value(payableAmount)(
state.path, // path originating with source token and terminating in destination token
fromTokenBalance, // amount of source token to trade
amount, // minimum amount of destination token expected to receive
to, // beneficiary
state.path[state.path.length-1] == BANCOR_ETH_ADDRESS ? address(this) : to, // beneficiary
address(0), // affiliateAccount; no fee paid
0 // affiliateFee; no fee paid
);
if (state.path[state.path.length-1] == BANCOR_ETH_ADDRESS) {
state.weth.deposit.value(boughtAmount)();
state.weth.transfer(to, boughtAmount);
}
emit ERC20BridgeTransfer(
state.path[0], // fromTokenAddress
state.path[0] == BANCOR_ETH_ADDRESS ? address(state.weth) : state.path[0],
toTokenAddress,
fromTokenBalance,
boughtAmount,
@@ -118,5 +140,5 @@ contract BancorBridge is
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@@ -56,11 +56,14 @@ contract KyberBridge is
uint256 constant private KYBER_RATE_BASE = 10 ** 18;
// solhint-disable no-empty-blocks
/// @dev Payable fallback to receive ETH from Kyber.
/// @dev Payable fallback to receive ETH from Kyber/WETH.
function ()
external
payable
{}
{
// Poor man's receive in 0.5.9
require(msg.data.length == 0);
}
/// @dev Callback for `IKyberBridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the opposing asset

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.6.9",
"version": "3.7.3",
"engines": {
"node": ">=6.12"
},
@@ -52,10 +52,10 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contract-wrappers": "^13.11.0",
"@0x/contract-wrappers": "^13.12.0",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
@@ -80,11 +80,11 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-erc1155": "^2.1.18",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-erc721": "^3.1.18",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/order-utils": "^10.4.10",
"@0x/contracts-erc1155": "^2.1.21",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-erc721": "^3.1.21",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/order-utils": "^10.4.13",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.1.1",

View File

@@ -12,13 +12,11 @@ import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { TestBancorBridgeContract } from './generated-wrappers/test_bancor_bridge';
import {
TestBancorBridgeConvertByPathInputEventArgs as ConvertByPathArgs,
TestBancorBridgeEvents as ContractEvents,
TestBancorBridgeTokenApproveEventArgs as TokenApproveArgs,
TestBancorBridgeTokenTransferEventArgs as TokenTransferArgs,
} from './wrappers';
blockchainTests.resets('Bancor unit tests', env => {
@@ -128,24 +126,6 @@ blockchainTests.resets('Bancor unit tests', env => {
expect(result).to.eq(AssetProxyId.ERC20Bridge);
});
it('performs transfer when both tokens are the same', async () => {
const createTokenFn = testContract.createToken(constants.NULL_ADDRESS);
const tokenAddress = await createTokenFn.callAsync();
await createTokenFn.awaitTransactionSuccessAsync();
const { opts, result, logs } = await transferFromAsync({
tokenAddressesPath: [tokenAddress, tokenAddress],
});
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer);
expect(transfers.length).to.eq(1);
expect(transfers[0].token).to.eq(tokenAddress, 'input token address');
expect(transfers[0].from).to.eq(testContract.address);
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount');
});
describe('token -> token', async () => {
it('calls BancorNetwork.convertByPath()', async () => {
const { opts, result, logs } = await transferFromAsync();

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "1.1.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "1.1.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "1.1.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "1.1.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "1.1.17",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.1.21 - _January 4, 2021_
* Dependencies updated
## v1.1.20 - _December 23, 2020_
* Dependencies updated
## v1.1.19 - _December 17, 2020_
* Dependencies updated
## v1.1.18 - _December 16, 2020_
* Dependencies updated
## v1.1.17 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-broker",
"version": "1.1.17",
"version": "1.1.21",
"engines": {
"node": ">=6.12"
},
@@ -52,14 +52,14 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-erc721": "^3.1.18",
"@0x/contracts-exchange": "^3.2.18",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-erc721": "^3.1.21",
"@0x/contracts-exchange": "^3.2.22",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -85,7 +85,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.1.1",
"ethereum-types": "^3.4.0"

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "3.1.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "3.1.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "3.1.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "3.1.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "3.1.18",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.22 - _January 4, 2021_
* Dependencies updated
## v3.1.21 - _December 23, 2020_
* Dependencies updated
## v3.1.20 - _December 17, 2020_
* Dependencies updated
## v3.1.19 - _December 16, 2020_
* Dependencies updated
## v3.1.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-coordinator",
"version": "3.1.18",
"version": "3.1.22",
"engines": {
"node": ">=6.12"
},
@@ -53,12 +53,12 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-dev-utils": "^1.3.16",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-dev-utils": "^1.3.20",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-gen": "^2.0.24",
"@0x/dev-utils": "^4.1.3",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -84,10 +84,10 @@
"dependencies": {
"@0x/assert": "^3.0.19",
"@0x/base-contract": "^6.2.14",
"@0x/contract-addresses": "^5.6.0",
"@0x/contracts-exchange": "^3.2.18",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contract-addresses": "^5.8.0",
"@0x/contracts-exchange": "^3.2.22",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/json-schemas": "^5.3.4",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "1.3.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "1.3.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "1.3.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "1.3.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "1.3.16",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.3.20 - _January 4, 2021_
* Dependencies updated
## v1.3.19 - _December 23, 2020_
* Dependencies updated
## v1.3.18 - _December 17, 2020_
* Dependencies updated
## v1.3.17 - _December 16, 2020_
* Dependencies updated
## v1.3.16 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-dev-utils",
"version": "1.3.16",
"version": "1.3.20",
"engines": {
"node": ">=6.12"
},
@@ -43,10 +43,10 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/assert": "^3.0.19",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1609802516,
"version": "2.1.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "2.1.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "2.1.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "2.1.18",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.1.21 - _January 4, 2021_
* Dependencies updated
## v2.1.20 - _December 23, 2020_
* Dependencies updated
## v2.1.19 - _December 17, 2020_
* Dependencies updated
## v2.1.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc1155",
"version": "2.1.18",
"version": "2.1.21",
"engines": {
"node": ">=6.12"
},
@@ -54,7 +54,7 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
@@ -81,7 +81,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/utils": "^6.1.1",
"@0x/web3-wrapper": "^7.3.0",
"lodash": "^4.17.11"

View File

@@ -1,4 +1,32 @@
[
{
"version": "3.3.0",
"changes": [
{
"note": "Allow for excess return data in `LibERC20TokenV06` compat* functions",
"pr": 97
}
],
"timestamp": 1609802516
},
{
"timestamp": 1608692071,
"version": "3.2.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "3.2.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "3.2.12",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.3.0 - _January 4, 2021_
* Allow for excess return data in `LibERC20TokenV06` compat* functions (#97)
## v3.2.14 - _December 23, 2020_
* Dependencies updated
## v3.2.13 - _December 17, 2020_
* Dependencies updated
## v3.2.12 - _December 9, 2020_
* Dependencies updated

View File

@@ -118,7 +118,7 @@ library LibERC20TokenV06 {
{
tokenDecimals = 18;
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
if (didSucceed && resultData.length == 32) {
if (didSucceed && resultData.length >= 32) {
tokenDecimals = uint8(LibBytesV06.readUint256(resultData, 0));
}
}
@@ -141,7 +141,7 @@ library LibERC20TokenV06 {
spender
)
);
if (didSucceed && resultData.length == 32) {
if (didSucceed && resultData.length >= 32) {
allowance_ = LibBytesV06.readUint256(resultData, 0);
}
}
@@ -162,7 +162,7 @@ library LibERC20TokenV06 {
owner
)
);
if (didSucceed && resultData.length == 32) {
if (didSucceed && resultData.length >= 32) {
balance = LibBytesV06.readUint256(resultData, 0);
}
}
@@ -180,7 +180,7 @@ library LibERC20TokenV06 {
if (resultData.length == 0) {
return true;
}
if (resultData.length == 32) {
if (resultData.length >= 32) {
uint256 result = LibBytesV06.readUint256(resultData, 0);
if (result == 1) {
return true;

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "3.2.12",
"version": "3.3.0",
"engines": {
"node": ">=6.12"
},
@@ -53,8 +53,8 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1609802516,
"version": "3.1.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "3.1.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "3.1.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "3.1.18",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.21 - _January 4, 2021_
* Dependencies updated
## v3.1.20 - _December 23, 2020_
* Dependencies updated
## v3.1.19 - _December 17, 2020_
* Dependencies updated
## v3.1.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc721",
"version": "3.1.18",
"version": "3.1.21",
"engines": {
"node": ">=6.12"
},
@@ -54,8 +54,8 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "4.2.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "4.2.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "4.2.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "4.2.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "4.2.18",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.2.22 - _January 4, 2021_
* Dependencies updated
## v4.2.21 - _December 23, 2020_
* Dependencies updated
## v4.2.20 - _December 17, 2020_
* Dependencies updated
## v4.2.19 - _December 16, 2020_
* Dependencies updated
## v4.2.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-forwarder",
"version": "4.2.18",
"version": "4.2.22",
"engines": {
"node": ">=6.12"
},
@@ -53,18 +53,18 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-dev-utils": "^1.3.16",
"@0x/contracts-erc1155": "^2.1.18",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-erc721": "^3.1.18",
"@0x/contracts-exchange": "^3.2.18",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-dev-utils": "^1.3.20",
"@0x/contracts-erc1155": "^2.1.21",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-erc721": "^3.1.21",
"@0x/contracts-exchange": "^3.2.22",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1609802516,
"version": "4.3.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "4.3.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "4.3.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "4.3.18",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.3.21 - _January 4, 2021_
* Dependencies updated
## v4.3.20 - _December 23, 2020_
* Dependencies updated
## v4.3.19 - _December 17, 2020_
* Dependencies updated
## v4.3.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-libs",
"version": "4.3.18",
"version": "4.3.21",
"engines": {
"node": ">=6.12"
},
@@ -81,9 +81,9 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/order-utils": "^10.4.10",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/order-utils": "^10.4.13",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.1.1",

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "3.2.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "3.2.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "3.2.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "3.2.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "3.2.18",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.22 - _January 4, 2021_
* Dependencies updated
## v3.2.21 - _December 23, 2020_
* Dependencies updated
## v3.2.20 - _December 17, 2020_
* Dependencies updated
## v3.2.19 - _December 16, 2020_
* Dependencies updated
## v3.2.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange",
"version": "3.2.18",
"version": "3.2.22",
"engines": {
"node": ">=6.12"
},
@@ -53,13 +53,13 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-multisig": "^4.1.18",
"@0x/contracts-staking": "^2.0.25",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-multisig": "^4.1.22",
"@0x/contracts-staking": "^2.0.29",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
@@ -89,11 +89,11 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-dev-utils": "^1.3.16",
"@0x/contracts-erc1155": "^2.1.18",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-erc721": "^3.1.18",
"@0x/order-utils": "^10.4.10",
"@0x/contracts-dev-utils": "^1.3.20",
"@0x/contracts-erc1155": "^2.1.21",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-erc721": "^3.1.21",
"@0x/order-utils": "^10.4.13",
"@0x/utils": "^6.1.1",
"lodash": "^4.17.11"
},

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "6.2.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "6.2.15",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "6.2.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "6.2.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "6.2.12",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.2.16 - _January 4, 2021_
* Dependencies updated
## v6.2.15 - _December 23, 2020_
* Dependencies updated
## v6.2.14 - _December 17, 2020_
* Dependencies updated
## v6.2.13 - _December 16, 2020_
* Dependencies updated
## v6.2.12 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-extensions",
"version": "6.2.12",
"version": "6.2.16",
"engines": {
"node": ">=6.12"
},
@@ -53,16 +53,16 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-dev-utils": "^1.3.16",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-erc721": "^3.1.18",
"@0x/contracts-exchange": "^3.2.18",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-dev-utils": "^1.3.20",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-erc721": "^3.1.21",
"@0x/contracts-exchange": "^3.2.22",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -91,7 +91,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/typescript-typings": "^5.1.6",
"ethereum-types": "^3.4.0"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-integrations",
"version": "2.7.15",
"version": "2.7.22",
"private": true,
"engines": {
"node": ">=6.12"
@@ -53,21 +53,21 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contract-addresses": "^5.6.0",
"@0x/contract-wrappers": "^13.11.0",
"@0x/contracts-broker": "^1.1.17",
"@0x/contracts-coordinator": "^3.1.18",
"@0x/contracts-dev-utils": "^1.3.16",
"@0x/contracts-exchange-forwarder": "^4.2.18",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-extensions": "^6.2.12",
"@0x/contract-addresses": "^5.8.0",
"@0x/contract-wrappers": "^13.12.0",
"@0x/contracts-broker": "^1.1.21",
"@0x/contracts-coordinator": "^3.1.22",
"@0x/contracts-dev-utils": "^1.3.20",
"@0x/contracts-exchange-forwarder": "^4.2.22",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-extensions": "^6.2.16",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-utils": "^4.7.0",
"@0x/coordinator-server": "^1.0.5",
"@0x/dev-utils": "^4.1.3",
"@0x/migrations": "^6.5.4",
"@0x/order-utils": "^10.4.10",
"@0x/protocol-utils": "^1.0.1",
"@0x/migrations": "^6.5.9",
"@0x/order-utils": "^10.4.13",
"@0x/protocol-utils": "^1.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/tslint-config": "^4.1.3",
"@0x/web3-wrapper": "^7.3.0",
@@ -93,17 +93,17 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/asset-swapper": "^5.4.2",
"@0x/asset-swapper": "^5.6.2",
"@0x/base-contract": "^6.2.14",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-erc1155": "^2.1.18",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-erc721": "^3.1.18",
"@0x/contracts-exchange": "^3.2.18",
"@0x/contracts-multisig": "^4.1.18",
"@0x/contracts-staking": "^2.0.25",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-zero-ex": "^0.12.0",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-erc1155": "^2.1.21",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-erc721": "^3.1.21",
"@0x/contracts-exchange": "^3.2.22",
"@0x/contracts-multisig": "^4.1.22",
"@0x/contracts-staking": "^2.0.29",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-zero-ex": "^0.17.0",
"@0x/subproviders": "^6.2.3",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "4.1.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "4.1.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "4.1.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "4.1.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "4.1.18",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.1.22 - _January 4, 2021_
* Dependencies updated
## v4.1.21 - _December 23, 2020_
* Dependencies updated
## v4.1.20 - _December 17, 2020_
* Dependencies updated
## v4.1.19 - _December 16, 2020_
* Dependencies updated
## v4.1.18 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-multisig",
"version": "4.1.18",
"version": "4.1.22",
"engines": {
"node": ">=6.12"
},
@@ -50,11 +50,11 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/sol-compiler": "^4.4.1",
"@0x/tslint-config": "^4.1.3",

View File

@@ -1,4 +1,40 @@
[
{
"timestamp": 1609802516,
"version": "2.0.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "2.0.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "2.0.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "2.0.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "2.0.25",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.29 - _January 4, 2021_
* Dependencies updated
## v2.0.28 - _December 23, 2020_
* Dependencies updated
## v2.0.27 - _December 17, 2020_
* Dependencies updated
## v2.0.26 - _December 16, 2020_
* Dependencies updated
## v2.0.25 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-staking",
"version": "2.0.25",
"version": "2.0.29",
"engines": {
"node": ">=6.12"
},
@@ -54,14 +54,14 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-dev-utils": "^1.3.16",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-dev-utils": "^1.3.20",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-utils": "^4.7.0",
"@0x/dev-utils": "^4.1.3",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
@@ -88,7 +88,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/typescript-typings": "^5.1.6",
"@0x/utils": "^6.1.1",
"ethereum-types": "^3.4.0",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1609802516,
"version": "5.3.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "5.3.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "5.3.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "5.3.15",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.3.18 - _January 4, 2021_
* Dependencies updated
## v5.3.17 - _December 23, 2020_
* Dependencies updated
## v5.3.16 - _December 17, 2020_
* Dependencies updated
## v5.3.15 - _December 9, 2020_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.3.15",
"version": "5.3.18",
"engines": {
"node": ">=6.12"
},
@@ -44,10 +44,10 @@
"dependencies": {
"@0x/assert": "^3.0.19",
"@0x/base-contract": "^6.2.14",
"@0x/contract-addresses": "^5.6.0",
"@0x/contract-addresses": "^5.8.0",
"@0x/dev-utils": "^4.1.3",
"@0x/json-schemas": "^5.3.4",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/sol-coverage": "^4.0.24",
"@0x/sol-profiler": "^4.1.14",
"@0x/sol-trace": "^3.0.24",

View File

@@ -1,4 +1,32 @@
[
{
"version": "4.7.0",
"changes": [
{
"note": "Add `LibSafeMathV06.safeDowncastToUint128()`",
"pr": 97
}
],
"timestamp": 1609802516
},
{
"timestamp": 1608692071,
"version": "4.6.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "4.6.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "4.6.3",

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.7.0 - _January 4, 2021_
* Add `LibSafeMathV06.safeDowncastToUint128()` (#97)
## v4.6.5 - _December 23, 2020_
* Dependencies updated
## v4.6.4 - _December 17, 2020_
* Dependencies updated
## v4.6.3 - _December 9, 2020_
* Dependencies updated

View File

@@ -187,4 +187,18 @@ library LibSafeMathV06 {
{
return a < b ? a : b;
}
function safeDowncastToUint128(uint256 a)
internal
pure
returns (uint128)
{
if (a > type(uint128).max) {
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256DowncastError(
LibSafeMathRichErrorsV06.DowncastErrorCodes.VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT128,
a
));
}
return uint128(a);
}
}

View File

@@ -39,7 +39,8 @@ library LibSafeMathRichErrorsV06 {
enum DowncastErrorCodes {
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT32,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT128
}
// solhint-disable func-name-mixedcase

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.6.3",
"version": "4.7.0",
"engines": {
"node": ">=6.12"
},
@@ -52,9 +52,9 @@
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/dev-utils": "^4.1.3",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/sol-compiler": "^4.4.1",
"@0x/tslint-config": "^4.1.3",
"@0x/types": "^3.3.1",

View File

@@ -8,3 +8,4 @@
# Blacklist tests in lib
/lib/test/*
# Package specific ignore
/lib/scripts/*

View File

@@ -1,4 +1,65 @@
[
{
"version": "0.17.0",
"changes": [
{
"note": "Add DevUtils-like functions to `NativeOrdersFeature`",
"pr": 97
}
],
"timestamp": 1609802516
},
{
"version": "0.16.0",
"changes": [
{
"note": "Fix CryptoCom rollup"
}
],
"timestamp": 1608692071
},
{
"version": "0.15.0",
"changes": [
{
"note": "Add MixinBancor to BridgeAdapter",
"pr": 91
},
{
"note": "Add MixinCoFiX to BridgeAdapter",
"pr": 92
}
],
"timestamp": 1608245516
},
{
"version": "0.14.0",
"changes": [
{
"note": "Use the `MetaTransaction` class from `@0x/protocol-utils` in tests.",
"pr": 90
}
],
"timestamp": 1608149382
},
{
"version": "0.13.0",
"changes": [
{
"note": "Address audit feedback in UniswapFeature",
"pr": 82
},
{
"note": "Always transfer `msg.value` to the liquidity provider contract in LiquidityProviderFeature to",
"pr": 82
},
{
"note": "Remove backwards compatibility with old PLP/bridge interface in `LiquidityProviderFeature` and `MixinZeroExBridge`",
"pr": 85
}
],
"timestamp": 1608105788
},
{
"version": "0.12.0",
"changes": [

View File

@@ -5,6 +5,29 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.17.0 - _January 4, 2021_
* Add DevUtils-like functions to `NativeOrdersFeature` (#97)
## v0.16.0 - _December 23, 2020_
* Fix CryptoCom rollup
## v0.15.0 - _December 17, 2020_
* Add MixinBancor to BridgeAdapter (#91)
* Add MixinCoFiX to BridgeAdapter (#92)
## v0.14.0 - _December 16, 2020_
* Use the `MetaTransaction` class from `@0x/protocol-utils` in tests. (#90)
## v0.13.0 - _December 16, 2020_
* Address audit feedback in UniswapFeature (#82)
* Always transfer `msg.value` to the liquidity provider contract in LiquidityProviderFeature to (#82)
* Remove backwards compatibility with old PLP/bridge interface in `LiquidityProviderFeature` and `MixinZeroExBridge` (#85)
## v0.12.0 - _December 9, 2020_
* Add test for selector collisions on the proxy (#74)

View File

@@ -57,7 +57,6 @@ contract FeeCollector is AuthorizableV06 {
external
onlyAuthorized
{
// Leave 1 wei behind to avoid expensive zero-->non-zero state change.
if (address(this).balance > 0) {
weth.deposit{value: address(this).balance}();
}

View File

@@ -68,21 +68,13 @@ contract LiquidityProviderSandbox is
onlyOwner
override
{
try ILiquidityProvider(provider).sellTokenForToken(
ILiquidityProvider(provider).sellTokenForToken(
inputToken,
outputToken,
recipient,
minBuyAmount,
auxiliaryData
) {} catch {
IERC20Bridge(provider).bridgeTransferFrom(
outputToken,
provider,
recipient,
minBuyAmount,
auxiliaryData
);
}
);
}
/// @dev Calls `sellEthForToken` on the given `provider` contract to

View File

@@ -346,4 +346,81 @@ interface INativeOrdersFeature {
view
returns (uint32 multiplier);
/// @dev Get order info, fillable amount, and signature validity for a limit order.
/// Fillable amount is determined using balances and allowances of the maker.
/// @param order The limit order.
/// @param signature The order signature.
/// @return orderInfo Info about the order.
/// @return actualFillableTakerTokenAmount How much of the order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValid Whether the signature is valid.
function getLimitOrderRelevantState(
LibNativeOrder.LimitOrder calldata order,
LibSignature.Signature calldata signature
)
external
view
returns (
LibNativeOrder.OrderInfo memory orderInfo,
uint128 actualFillableTakerTokenAmount,
bool isSignatureValid
);
/// @dev Get order info, fillable amount, and signature validity for an RFQ order.
/// Fillable amount is determined using balances and allowances of the maker.
/// @param order The RFQ order.
/// @param signature The order signature.
/// @return orderInfo Info about the order.
/// @return actualFillableTakerTokenAmount How much of the order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValid Whether the signature is valid.
function getRfqOrderRelevantState(
LibNativeOrder.RfqOrder calldata order,
LibSignature.Signature calldata signature
)
external
view
returns (
LibNativeOrder.OrderInfo memory orderInfo,
uint128 actualFillableTakerTokenAmount,
bool isSignatureValid
);
/// @dev Batch version of `getLimitOrderRelevantState()`.
/// @param orders The limit orders.
/// @param signatures The order signatures.
/// @return orderInfos Info about the orders.
/// @return actualFillableTakerTokenAmounts How much of each order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValids Whether each signature is valid for the order.
function batchGetLimitOrderRelevantStates(
LibNativeOrder.LimitOrder[] calldata orders,
LibSignature.Signature[] calldata signatures
)
external
view
returns (
LibNativeOrder.OrderInfo[] memory orderInfos,
uint128[] memory actualFillableTakerTokenAmounts,
bool[] memory isSignatureValids
);
/// @dev Batch version of `getRfqOrderRelevantState()`.
/// @param orders The RFQ orders.
/// @param signatures The order signatures.
/// @return orderInfos Info about the orders.
/// @return actualFillableTakerTokenAmounts How much of each order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValids Whether each signature is valid for the order.
function batchGetRfqOrderRelevantStates(
LibNativeOrder.RfqOrder[] calldata orders,
LibSignature.Signature[] calldata signatures
)
external
view
returns (
LibNativeOrder.OrderInfo[] memory orderInfos,
uint128[] memory actualFillableTakerTokenAmounts,
bool[] memory isSignatureValids
);
}

View File

@@ -44,7 +44,7 @@ contract LiquidityProviderFeature is
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "LiquidityProviderFeature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1);
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 2);
/// @dev ETH pseudo-token address.
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
@@ -111,9 +111,13 @@ contract LiquidityProviderFeature is
recipient = msg.sender;
}
if (inputToken == ETH_TOKEN_ADDRESS) {
provider.transfer(sellAmount);
} else {
// Forward all attached ETH to the provider.
if (msg.value > 0) {
provider.transfer(msg.value);
}
if (inputToken != ETH_TOKEN_ADDRESS) {
// Transfer input ERC20 tokens to the provider.
_transferERC20Tokens(
IERC20TokenV06(inputToken),
msg.sender,

View File

@@ -51,6 +51,7 @@ contract NativeOrdersFeature is
using LibSafeMathV06 for uint256;
using LibSafeMathV06 for uint128;
using LibRichErrorsV06 for bytes;
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Params for `_settleOrder()`.
struct SettleOrderInfo {
@@ -97,6 +98,15 @@ contract NativeOrdersFeature is
uint128 takerTokenFeeFilledAmount;
}
// @dev Params for `_getActualFillableTakerTokenAmount()`.
struct GetActualFillableTakerTokenAmountParams {
address maker;
IERC20TokenV06 makerToken;
uint128 orderMakerAmount;
uint128 orderTakerAmount;
LibNativeOrder.OrderInfo orderInfo;
}
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "LimitOrders";
/// @dev Version of this feature.
@@ -148,6 +158,10 @@ contract NativeOrdersFeature is
_registerFeatureFunction(this.getRfqOrderHash.selector);
_registerFeatureFunction(this.getProtocolFeeMultiplier.selector);
_registerFeatureFunction(this.registerAllowedRfqOrigins.selector);
_registerFeatureFunction(this.getLimitOrderRelevantState.selector);
_registerFeatureFunction(this.getRfqOrderRelevantState.selector);
_registerFeatureFunction(this.batchGetLimitOrderRelevantStates.selector);
_registerFeatureFunction(this.batchGetRfqOrderRelevantStates.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
@@ -687,6 +701,148 @@ contract NativeOrdersFeature is
);
}
/// @dev Get order info, fillable amount, and signature validity for a limit order.
/// Fillable amount is determined using balances and allowances of the maker.
/// @param order The limit order.
/// @param signature The order signature.
/// @return orderInfo Info about the order.
/// @return actualFillableTakerTokenAmount How much of the order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValid Whether the signature is valid.
function getLimitOrderRelevantState(
LibNativeOrder.LimitOrder memory order,
LibSignature.Signature calldata signature
)
public
override
view
returns (
LibNativeOrder.OrderInfo memory orderInfo,
uint128 actualFillableTakerTokenAmount,
bool isSignatureValid
)
{
orderInfo = getLimitOrderInfo(order);
actualFillableTakerTokenAmount = _getActualFillableTakerTokenAmount(
GetActualFillableTakerTokenAmountParams({
maker: order.maker,
makerToken: order.makerToken,
orderMakerAmount: order.makerAmount,
orderTakerAmount: order.takerAmount,
orderInfo: orderInfo
})
);
isSignatureValid = order.maker ==
LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
}
/// @dev Get order info, fillable amount, and signature validity for an RFQ order.
/// Fillable amount is determined using balances and allowances of the maker.
/// @param order The RFQ order.
/// @param signature The order signature.
/// @return orderInfo Info about the order.
/// @return actualFillableTakerTokenAmount How much of the order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValid Whether the signature is valid.
function getRfqOrderRelevantState(
LibNativeOrder.RfqOrder memory order,
LibSignature.Signature memory signature
)
public
override
view
returns (
LibNativeOrder.OrderInfo memory orderInfo,
uint128 actualFillableTakerTokenAmount,
bool isSignatureValid
)
{
orderInfo = getRfqOrderInfo(order);
actualFillableTakerTokenAmount = _getActualFillableTakerTokenAmount(
GetActualFillableTakerTokenAmountParams({
maker: order.maker,
makerToken: order.makerToken,
orderMakerAmount: order.makerAmount,
orderTakerAmount: order.takerAmount,
orderInfo: orderInfo
})
);
isSignatureValid = order.maker ==
LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
}
/// @dev Batch version of `getLimitOrderRelevantState()`.
/// @param orders The limit orders.
/// @param signatures The order signatures.
/// @return orderInfos Info about the orders.
/// @return actualFillableTakerTokenAmounts How much of each order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValids Whether each signature is valid for the order.
function batchGetLimitOrderRelevantStates(
LibNativeOrder.LimitOrder[] calldata orders,
LibSignature.Signature[] calldata signatures
)
external
override
view
returns (
LibNativeOrder.OrderInfo[] memory orderInfos,
uint128[] memory actualFillableTakerTokenAmounts,
bool[] memory isSignatureValids
)
{
require(
orders.length == signatures.length,
"NativeOrdersFeature/MISMATCHED_ARRAY_LENGTHS"
);
orderInfos = new LibNativeOrder.OrderInfo[](orders.length);
actualFillableTakerTokenAmounts = new uint128[](orders.length);
isSignatureValids = new bool[](orders.length);
for (uint256 i = 0; i < orders.length; ++i) {
(
orderInfos[i],
actualFillableTakerTokenAmounts[i],
isSignatureValids[i]
) = getLimitOrderRelevantState(orders[i], signatures[i]);
}
}
/// @dev Batch version of `getRfqOrderRelevantState()`.
/// @param orders The RFQ orders.
/// @param signatures The order signatures.
/// @return orderInfos Info about the orders.
/// @return actualFillableTakerTokenAmounts How much of each order is fillable
/// based on maker funds, in taker tokens.
/// @return isSignatureValids Whether each signature is valid for the order.
function batchGetRfqOrderRelevantStates(
LibNativeOrder.RfqOrder[] calldata orders,
LibSignature.Signature[] calldata signatures
)
external
override
view
returns (
LibNativeOrder.OrderInfo[] memory orderInfos,
uint128[] memory actualFillableTakerTokenAmounts,
bool[] memory isSignatureValids
)
{
require(
orders.length == signatures.length,
"NativeOrdersFeature/MISMATCHED_ARRAY_LENGTHS"
);
orderInfos = new LibNativeOrder.OrderInfo[](orders.length);
actualFillableTakerTokenAmounts = new uint128[](orders.length);
isSignatureValids = new bool[](orders.length);
for (uint256 i = 0; i < orders.length; ++i) {
(
orderInfos[i],
actualFillableTakerTokenAmounts[i],
isSignatureValids[i]
) = getRfqOrderRelevantState(orders[i], signatures[i]);
}
}
/// @dev Get the protocol fee multiplier. This should be multiplied by the
/// gas price to arrive at the required protocol fee to fill a native order.
/// @return multiplier The protocol fee multiplier.
@@ -751,6 +907,48 @@ contract NativeOrdersFeature is
orderInfo.status = LibNativeOrder.OrderStatus.FILLABLE;
}
/// @dev Calculate the actual fillable taker token amount of an order
/// based on maker allowance and balances.
function _getActualFillableTakerTokenAmount(
GetActualFillableTakerTokenAmountParams memory params
)
private
view
returns (uint128 actualFillableTakerTokenAmount)
{
if (params.orderMakerAmount == 0 || params.orderTakerAmount == 0) {
// Empty order.
return 0;
}
if (params.orderInfo.status != LibNativeOrder.OrderStatus.FILLABLE) {
// Not fillable.
return 0;
}
// Get the fillable maker amount based on the order quantities and
// previously filled amount
uint256 fillableMakerTokenAmount = LibMathV06.getPartialAmountFloor(
uint256(
params.orderTakerAmount
- params.orderInfo.takerTokenFilledAmount
),
uint256(params.orderTakerAmount),
uint256(params.orderMakerAmount)
);
// Clamp it to the amount of maker tokens we can spend on behalf of the
// maker.
fillableMakerTokenAmount = LibSafeMathV06.min256(
fillableMakerTokenAmount,
_getSpendableERC20BalanceOf(params.makerToken, params.maker)
);
// Convert to taker token amount.
return LibMathV06.getPartialAmountCeil(
fillableMakerTokenAmount,
uint256(params.orderMakerAmount),
uint256(params.orderTakerAmount)
).safeDowncastToUint128();
}
/// @dev Cancel a limit or RFQ order directly by its order hash.
/// @param orderHash The order's order hash.
/// @param maker The order's maker.

View File

@@ -37,7 +37,7 @@ contract UniswapFeature is
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "UniswapFeature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 1);
/// @dev A bloom filter for tokens that consume all gas when `transferFrom()` fails.
bytes32 public immutable GREEDY_TOKENS_BLOOM_FILTER;
/// @dev WETH contract.
@@ -167,8 +167,13 @@ contract UniswapFeature is
}
if iszero(i) {
// This is the first token in the path.
switch eq(sellToken, ETH_TOKEN_ADDRESS_32)
case 0 { // Not selling ETH. Selling an ERC20 instead.
// Make sure ETH was not attached to the call.
if gt(callvalue(), 0) {
revert(0, 0)
}
// For the first pair we need to transfer sellTokens into the
// pair contract.
moveTakerTokensTo(sellToken, pair, sellAmount)
@@ -203,6 +208,10 @@ contract UniswapFeature is
if iszero(staticcall(gas(), pair, 0xB00, 0x4, 0xC00, 0x40)) {
bubbleRevert()
}
// Revert if the pair contract does not return two words.
if iszero(eq(returndatasize(), 0x40)) {
revert(0,0)
}
// Sell amount for this hop is the previous buy amount.
let pairSellAmount := buyAmount
@@ -374,11 +383,15 @@ contract UniswapFeature is
mstore(0xB00, ALLOWANCE_CALL_SELECTOR_32)
mstore(0xB04, caller())
mstore(0xB24, address())
let success := call(gas(), token, 0, 0xB00, 0x44, 0xC00, 0x20)
let success := staticcall(gas(), token, 0xB00, 0x44, 0xC00, 0x20)
if iszero(success) {
// Call to allowance() failed.
bubbleRevert()
}
// Make sure the allowance call returned a single word.
if iszero(eq(returndatasize(), 0x20)) {
revert(0, 0)
}
// Call succeeded.
// Result is stored in 0xC00-0xC20.
if lt(mload(0xC00), amount) {
@@ -397,8 +410,6 @@ contract UniswapFeature is
mstore(0xB44, amount)
let success := call(
// Cap the gas limit to prvent all gas being consumed
// if the token reverts.
gas(),
token,
0,

View File

@@ -21,6 +21,8 @@ pragma experimental ABIEncoderV2;
import "./mixins/MixinAdapterAddresses.sol";
import "./mixins/MixinBalancer.sol";
import "./mixins/MixinBancor.sol";
import "./mixins/MixinCoFiX.sol";
import "./mixins/MixinCurve.sol";
import "./mixins/MixinCryptoCom.sol";
import "./mixins/MixinDodo.sol";
@@ -37,6 +39,8 @@ import "./mixins/MixinZeroExBridge.sol";
contract BridgeAdapter is
MixinAdapterAddresses,
MixinBalancer,
MixinBancor,
MixinCoFiX,
MixinCurve,
MixinCryptoCom,
MixinDodo,
@@ -51,7 +55,25 @@ contract BridgeAdapter is
MixinZeroExBridge
{
/// @dev Emitted when a trade occurs.
/// @param inputToken The token the bridge is converting from.
/// @param outputToken The token the bridge is converting to.
/// @param inputTokenAmount Amount of input token.
/// @param outputTokenAmount Amount of output token.
/// @param from The bridge address, indicating the underlying source of the fill.
/// @param to The `to` address, currrently `address(this)`
event ERC20BridgeTransfer(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address from,
address to
);
address private immutable BALANCER_BRIDGE_ADDRESS;
address private immutable BANCOR_BRIDGE_ADDRESS;
address private immutable COFIX_BRIDGE_ADDRESS;
address private immutable CREAM_BRIDGE_ADDRESS;
address private immutable CURVE_BRIDGE_ADDRESS;
address private immutable CRYPTO_COM_BRIDGE_ADDRESS;
@@ -70,8 +92,10 @@ contract BridgeAdapter is
constructor(AdapterAddresses memory addresses)
public
MixinBalancer()
MixinBancor(addresses)
MixinCoFiX()
MixinCurve()
MixinCryptoCom(addresses)
MixinCryptoCom()
MixinDodo(addresses)
MixinKyber(addresses)
MixinMooniswap(addresses)
@@ -84,6 +108,8 @@ contract BridgeAdapter is
MixinZeroExBridge()
{
BALANCER_BRIDGE_ADDRESS = addresses.balancerBridge;
BANCOR_BRIDGE_ADDRESS = addresses.bancorBridge;
COFIX_BRIDGE_ADDRESS = addresses.cofixBridge;
CURVE_BRIDGE_ADDRESS = addresses.curveBridge;
CRYPTO_COM_BRIDGE_ADDRESS = addresses.cryptoComBridge;
KYBER_BRIDGE_ADDRESS = addresses.kyberBridge;
@@ -196,6 +222,18 @@ contract BridgeAdapter is
sellAmount,
bridgeData
);
} else if (bridgeAddress == BANCOR_BRIDGE_ADDRESS) {
boughtAmount = _tradeBancor(
buyToken,
sellAmount,
bridgeData
);
} else if (bridgeAddress == COFIX_BRIDGE_ADDRESS) {
boughtAmount = _tradeCoFiX(
buyToken,
sellAmount,
bridgeData
);
} else {
boughtAmount = _tradeZeroExBridge(
bridgeAddress,
@@ -204,9 +242,6 @@ contract BridgeAdapter is
sellAmount,
bridgeData
);
// Old bridge contracts should emit an `ERC20BridgeTransfer` themselves,
// otherwise an event will be emitted from `_tradeZeroExBridge`.
return boughtAmount;
}
emit ERC20BridgeTransfer(

View File

@@ -24,6 +24,8 @@ contract MixinAdapterAddresses
struct AdapterAddresses {
// Bridges
address balancerBridge;
address bancorBridge;
address cofixBridge;
address creamBridge;
address curveBridge;
address cryptoComBridge;

View File

@@ -0,0 +1,111 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface IBancorNetwork {
function convertByPath(
address[] calldata _path,
uint256 _amount,
uint256 _minReturn,
address _beneficiary,
address _affiliateAccount,
uint256 _affiliateFee
)
external
payable
returns (uint256);
}
contract MixinBancor is
MixinAdapterAddresses
{
/// @dev Bancor ETH pseudo-address.
address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
IEtherTokenV06 private immutable WETH;
constructor(AdapterAddresses memory addresses)
public
{
WETH = IEtherTokenV06(addresses.weth);
}
function _tradeBancor(
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
// Decode the bridge data.
(
address[] memory path,
address bancorNetworkAddress
// solhint-disable indent
) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
require(path.length >= 2, "MixinBancor/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
path[path.length - 1] == address(buyToken) ||
(path[path.length - 1] == BANCOR_ETH_ADDRESS && address(buyToken) == address(WETH)),
"MixinBancor/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
uint256 payableAmount = 0;
// If it's ETH in the path then withdraw from WETH
// The Bancor path will have ETH as the 0xeee address
// Bancor expects to be paid in ETH not WETH
if (path[0] == BANCOR_ETH_ADDRESS) {
WETH.withdraw(sellAmount);
payableAmount = sellAmount;
} else {
// Grant an allowance to the Bancor Network.
LibERC20TokenV06.approveIfBelow(
IERC20TokenV06(path[0]),
bancorNetworkAddress,
sellAmount
);
}
// Convert the tokens
boughtAmount = IBancorNetwork(bancorNetworkAddress).convertByPath{value: payableAmount}(
path, // path originating with source token and terminating in destination token
sellAmount, // amount of source token to trade
1, // minimum amount of destination token expected to receive
address(this), // beneficiary
address(0), // affiliateAccount; no fee paid
0 // affiliateFee; no fee paid
);
if (path[path.length - 1] == BANCOR_ETH_ADDRESS) {
WETH.deposit{value: boughtAmount}();
}
return boughtAmount;
}
}

View File

@@ -0,0 +1,86 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "./MixinAdapterAddresses.sol";
interface ICoFiXRouter {
// msg.value = fee
function swapExactTokensForETH(
address token,
uint amountIn,
uint amountOutMin,
address to,
address rewardTo,
uint deadline
) external payable returns (uint _amountIn, uint _amountOut);
// msg.value = amountIn + fee
function swapExactETHForTokens(
address token,
uint amountIn,
uint amountOutMin,
address to,
address rewardTo,
uint deadline
) external payable returns (uint _amountIn, uint _amountOut);
}
interface ICoFiXPair {
function swapWithExact(address outToken, address to)
external
payable
returns (uint amountIn, uint amountOut, uint oracleFeeChange, uint256[4] memory tradeInfo);
}
contract MixinCoFiX is
MixinAdapterAddresses
{
using LibERC20TokenV06 for IERC20TokenV06;
function _tradeCoFiX(
IERC20TokenV06 buyToken,
uint256 sellAmount,
bytes memory bridgeData
)
internal
returns (uint256 boughtAmount)
{
(address fromTokenAddress, uint256 fee, address pool) = abi.decode(bridgeData, (address, uint256, address));
// Transfer tokens into the pool
LibERC20TokenV06.compatTransfer(
IERC20TokenV06(fromTokenAddress),
pool,
sellAmount);
// Call the swap exact with the tokens now in the pool
// pay the NEST Oracle fee with ETH
(/* In */, boughtAmount, , ) = ICoFiXPair(pool).swapWithExact{value: fee}(
address(buyToken),
address(this)
);
return boughtAmount;
}
}

View File

@@ -22,23 +22,12 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./MixinAdapterAddresses.sol";
import "./MixinUniswapV2.sol";
contract MixinCryptoCom is
MixinAdapterAddresses
contract MixinCryptoCom
{
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Mainnet address of the `CryptoComRouter` contract.
IUniswapV2Router02 private immutable CRYPTOCOM_ROUTER;
constructor(AdapterAddresses memory addresses)
public
{
CRYPTOCOM_ROUTER = IUniswapV2Router02(addresses.cryptoComBridge);
}
function _tradeCryptoCom(
IERC20TokenV06 buyToken,
uint256 sellAmount,
@@ -48,7 +37,9 @@ contract MixinCryptoCom is
returns (uint256 boughtAmount)
{
// solhint-disable indent
address[] memory path = abi.decode(bridgeData, (address[]));
address[] memory path;
address router;
(path, router) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
require(path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
@@ -56,13 +47,10 @@ contract MixinCryptoCom is
path[path.length - 1] == address(buyToken),
"CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the Uniswap router an allowance to sell the first token.
IERC20TokenV06(path[0]).approveIfBelow(
address(CRYPTOCOM_ROUTER),
sellAmount
);
// Grant the CryptoCom router an allowance to sell the first token.
IERC20TokenV06(path[0]).approveIfBelow(router, sellAmount);
uint[] memory amounts = CRYPTOCOM_ROUTER.swapExactTokensForTokens(
uint[] memory amounts = IUniswapV2Router02(router).swapExactTokensForTokens(
// Sell all tokens we hold.
sellAmount,
// Minimum buy amount.

View File

@@ -22,7 +22,6 @@ import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../../vendor/ILiquidityProvider.sol";
import "../../../vendor/v3/IERC20Bridge.sol";
contract MixinZeroExBridge {
@@ -30,22 +29,6 @@ contract MixinZeroExBridge {
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
/// @dev Emitted when a trade occurs.
/// @param inputToken The token the bridge is converting from.
/// @param outputToken The token the bridge is converting to.
/// @param inputTokenAmount Amount of input token.
/// @param outputTokenAmount Amount of output token.
/// @param from The bridge address, indicating the underlying source of the fill.
/// @param to The `to` address, currrently `address(this)`
event ERC20BridgeTransfer(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
address from,
address to
);
function _tradeZeroExBridge(
address bridgeAddress,
IERC20TokenV06 sellToken,
@@ -61,32 +44,12 @@ contract MixinZeroExBridge {
bridgeAddress,
sellAmount
);
try ILiquidityProvider(bridgeAddress).sellTokenForToken(
address(sellToken),
address(buyToken),
address(this), // recipient
1, // minBuyAmount
bridgeData
) returns (uint256 _boughtAmount) {
boughtAmount = _boughtAmount;
emit ERC20BridgeTransfer(
sellToken,
buyToken,
sellAmount,
boughtAmount,
bridgeAddress,
address(this)
);
} catch {
uint256 balanceBefore = buyToken.balanceOf(address(this));
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
address(buyToken),
bridgeAddress,
address(this), // recipient
1, // minBuyAmount
bridgeData
);
boughtAmount = buyToken.balanceOf(address(this)).safeSub(balanceBefore);
}
boughtAmount = ILiquidityProvider(bridgeAddress).sellTokenForToken(
address(sellToken),
address(buyToken),
address(this), // recipient
1, // minBuyAmount
bridgeData
);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-zero-ex",
"version": "0.12.0",
"version": "0.17.0",
"engines": {
"node": ">=6.12"
},
@@ -37,12 +37,13 @@
"compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES",
"publish:private": "yarn build && gitpkg publish"
"publish:private": "yarn build && gitpkg publish",
"rollback": "node ./lib/scripts/rollback.js"
},
"config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITokenSpenderFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,TokenSpenderFeature,AffiliateFeeTransformer,SignatureValidatorFeature,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|BootstrapFeature|BridgeAdapter|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IAllowanceTarget|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|INativeOrdersFeature|IOwnableFeature|ISignatureValidatorFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOrderHash|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinAdapterAddresses|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinKyber|MixinMStable|MixinMooniswap|MixinOasis|MixinShell|MixinSushiswap|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|NativeOrdersFeature|OwnableFeature|PayTakerTransformer|PermissionlessTransformerDeployer|SignatureValidatorFeature|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestNativeOrdersFeature|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpenderFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json"
},
"repository": {
"type": "git",
@@ -55,18 +56,24 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex",
"devDependencies": {
"@0x/abi-gen": "^5.4.13",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contract-addresses": "^5.8.0",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/dev-utils": "^4.1.3",
"@0x/order-utils": "^10.4.13",
"@0x/sol-compiler": "^4.4.1",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.3",
"@types/isomorphic-fetch": "^0.0.35",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/prompts": "^2.0.9",
"isomorphic-fetch": "^3.0.0",
"lodash": "^4.17.11",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
"prompts": "^2.4.0",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"truffle": "^5.0.32",
@@ -76,8 +83,7 @@
},
"dependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/order-utils": "^10.4.10",
"@0x/protocol-utils": "^1.0.1",
"@0x/protocol-utils": "^1.1.3",
"@0x/subproviders": "^6.2.3",
"@0x/types": "^3.3.1",
"@0x/typescript-typings": "^5.1.6",

View File

@@ -0,0 +1,427 @@
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { constants } from '@0x/contracts-test-utils';
import { RPCSubprovider, SupportedProvider, Web3ProviderEngine } from '@0x/subproviders';
import { AbiEncoder, BigNumber, logUtils, providerUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { MethodAbi } from 'ethereum-types';
import * as fetch from 'isomorphic-fetch';
import * as _ from 'lodash';
import * as prompts from 'prompts';
import * as wrappers from '../src/wrappers';
const SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/mzhu25/zeroex-migrations';
const ownableFeature = new wrappers.OwnableFeatureContract(constants.NULL_ADDRESS, new Web3ProviderEngine());
const simpleFunctionRegistryFeature = new wrappers.SimpleFunctionRegistryFeatureContract(
constants.NULL_ADDRESS,
new Web3ProviderEngine(),
);
const DO_NOT_ROLLBACK = [
ownableFeature.getSelector('migrate'),
ownableFeature.getSelector('transferOwnership'),
simpleFunctionRegistryFeature.getSelector('rollback'),
simpleFunctionRegistryFeature.getSelector('extend'),
];
const governorEncoder = AbiEncoder.create('(bytes[], address[], uint256[])');
const selectorToSignature: { [selector: string]: string } = {};
for (const wrapper of Object.values(wrappers)) {
if (typeof wrapper === 'function') {
const contract = new wrapper(constants.NULL_ADDRESS, new Web3ProviderEngine());
contract.abi
.filter(abiDef => abiDef.type === 'function')
.map(method => {
const methodName = (method as MethodAbi).name;
const selector = contract.getSelector(methodName);
const signature = contract.getFunctionSignature(methodName);
selectorToSignature[selector] = signature;
});
}
}
interface ProxyFunctionEntity {
id: string;
currentImpl: string;
fullHistory: Array<{ impl: string; timestamp: string }>;
}
interface Deployment {
time: string;
updates: Array<{ selector: string; signature?: string; previousImpl: string; newImpl: string }>;
}
async function querySubgraphAsync(): Promise<ProxyFunctionEntity[]> {
const query = `
{
proxyFunctions {
id
currentImpl
fullHistory {
impl
timestamp
}
}
}
`;
const response = await fetch(SUBGRAPH_URL, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
}),
});
const {
data: { proxyFunctions },
} = await response.json();
// Sort the history in chronological order
proxyFunctions.map((fn: ProxyFunctionEntity) =>
fn.fullHistory.sort((a, b) => Number.parseInt(a.timestamp, 10) - Number.parseInt(b.timestamp, 10)),
);
return proxyFunctions;
}
function reconstructDeployments(proxyFunctions: ProxyFunctionEntity[]): Deployment[] {
const deploymentsByTimestamp: { [timestamp: string]: Deployment } = {};
proxyFunctions.map(fn => {
fn.fullHistory.map((update, i) => {
const { updates } = (deploymentsByTimestamp[update.timestamp] = deploymentsByTimestamp[
update.timestamp
] || { time: timestampToUTC(update.timestamp), updates: [] });
updates.push({
selector: fn.id,
signature: selectorToSignature[fn.id],
previousImpl: i > 0 ? fn.fullHistory[i - 1].impl : constants.NULL_ADDRESS,
newImpl: update.impl,
});
});
});
return Object.keys(deploymentsByTimestamp)
.sort()
.map(timestamp => deploymentsByTimestamp[timestamp]);
}
function timestampToUTC(timestamp: string): string {
return new Date(Number.parseInt(timestamp, 10) * 1000).toUTCString();
}
enum CommandLineActions {
History = 'History',
Function = 'Function',
Current = 'Current',
Rollback = 'Rollback',
Emergency = 'Emergency',
Exit = 'Exit',
}
async function confirmRollbackAsync(
rollbackTargets: { [selector: string]: string },
proxyFunctions: ProxyFunctionEntity[],
): Promise<boolean> {
const { confirmed } = await prompts({
type: 'confirm',
name: 'confirmed',
message: `Are these the correct rollbacks?\n${Object.entries(rollbackTargets)
.map(
([selector, target]) =>
`[${selector}] ${selectorToSignature[selector] || '(function signature not found)'} \n ${
proxyFunctions.find(fn => fn.id === selector)!.currentImpl
} => ${target}`,
)
.join('\n')}`,
});
return confirmed;
}
async function printRollbackCalldataAsync(
rollbackTargets: { [selector: string]: string },
zeroEx: wrappers.IZeroExContract,
): Promise<void> {
const numRollbacks = Object.keys(rollbackTargets).length;
const { numTxns } = await prompts({
type: 'number',
name: 'numTxns',
message:
'To avoid limitations on calldata size, the full rollback can be split into multiple transactions. How many transactions would you like to split it into?',
initial: 1,
style: 'default',
min: 1,
max: numRollbacks,
});
for (let i = 0; i < numTxns; i++) {
const startIndex = i * Math.trunc(numRollbacks / numTxns);
const endIndex = startIndex + Math.trunc(numRollbacks / numTxns) + (i < numRollbacks % numTxns ? 1 : 0);
const rollbacks = Object.entries(rollbackTargets).slice(startIndex, endIndex);
const rollbackCallData = governorEncoder.encode([
rollbacks.map(([selector, target]) => zeroEx.rollback(selector, target).getABIEncodedTransactionData()),
new Array(rollbacks.length).fill(zeroEx.address),
new Array(rollbacks.length).fill(constants.ZERO_AMOUNT),
]);
if (numTxns > 1) {
logUtils.log(`======================== Governor Calldata #${i + 1} ========================`);
}
logUtils.log(rollbackCallData);
}
}
async function deploymentHistoryAsync(deployments: Deployment[], proxyFunctions: ProxyFunctionEntity[]): Promise<void> {
const { index } = await prompts({
type: 'select',
name: 'index',
message: 'Choose a deployment:',
choices: deployments.map((deployment, i) => ({
title: deployment.time,
value: i,
})),
});
const { action } = await prompts({
type: 'select',
name: 'action',
message: 'What would you like to do?',
choices: [
{ title: 'Deployment info', value: 'info' },
{ title: 'Rollback this deployment', value: 'rollback' },
],
});
if (action === 'info') {
logUtils.log(
deployments[index].updates.map(update => ({
selector: update.selector,
signature: update.signature || '(function signature not found)',
update: `${update.previousImpl} => ${update.newImpl}`,
})),
);
} else {
const zeroEx = await getMainnetContractAsync();
const rollbackTargets: { [selector: string]: string } = {};
for (const update of deployments[index].updates) {
rollbackTargets[update.selector] = update.previousImpl;
const rollbackLength = (await zeroEx.getRollbackLength(update.selector).callAsync()).toNumber();
for (let i = rollbackLength - 1; i >= 0; i--) {
const entry = await zeroEx.getRollbackEntryAtIndex(update.selector, new BigNumber(i)).callAsync();
if (entry === update.previousImpl) {
break;
} else if (i === 0) {
logUtils.log(
'Cannot rollback this deployment. The following update from this deployment cannot be rolled back:',
);
logUtils.log(`\t[${update.selector}] ${update.signature || '(function signature not found)'}`);
logUtils.log(`\t${update.previousImpl} => ${update.newImpl}`);
logUtils.log(
`Cannot find ${
update.previousImpl
} in the selector's rollback history. It itself may have been previously rolled back.`,
);
return;
}
}
}
const isConfirmed = await confirmRollbackAsync(rollbackTargets, proxyFunctions);
if (isConfirmed) {
await printRollbackCalldataAsync(rollbackTargets, zeroEx);
}
}
}
async function functionHistoryAsync(proxyFunctions: ProxyFunctionEntity[]): Promise<void> {
const { fnSelector } = await prompts({
type: 'autocomplete',
name: 'fnSelector',
message: 'Enter the selector or name of the function:',
choices: [
...proxyFunctions.map(fn => ({
title: fn.id,
value: fn.id,
description: selectorToSignature[fn.id] || '(function signature not found)',
})),
...proxyFunctions.map(fn => ({
title: selectorToSignature[fn.id] || '(function signature not found)',
value: fn.id,
description: fn.id,
})),
],
});
const functionEntity = proxyFunctions.find(fn => fn.id === fnSelector);
if (functionEntity === undefined) {
logUtils.log(`Couldn't find deployment history for selector ${fnSelector}`);
} else {
logUtils.log(
functionEntity.fullHistory.map(update => ({
date: timestampToUTC(update.timestamp),
impl: update.impl,
})),
);
}
}
async function currentFunctionsAsync(proxyFunctions: ProxyFunctionEntity[]): Promise<void> {
const currentFunctions: {
[selector: string]: { signature: string; impl: string; lastUpdated: string };
} = {};
proxyFunctions
.filter(fn => fn.currentImpl !== constants.NULL_ADDRESS)
.map(fn => {
currentFunctions[fn.id] = {
signature: selectorToSignature[fn.id] || '(function signature not found)',
impl: fn.currentImpl,
lastUpdated: timestampToUTC(fn.fullHistory.slice(-1)[0].timestamp),
};
});
logUtils.log(currentFunctions);
}
async function generateRollbackAsync(proxyFunctions: ProxyFunctionEntity[]): Promise<void> {
const zeroEx = await getMainnetContractAsync();
const { selected } = await prompts({
type: 'autocompleteMultiselect',
name: 'selected',
message: 'Select the functions to rollback:',
choices: _.flatMap(proxyFunctions.filter(fn => fn.currentImpl !== constants.NULL_ADDRESS), fn => [
{
title: [
`[${fn.id}]`,
`Implemented @ ${fn.currentImpl}`,
selectorToSignature[fn.id] || '(function signature not found)',
].join('\n\t\t\t\t'),
value: fn.id,
},
]),
});
const rollbackTargets: { [selector: string]: string } = {};
for (const selector of selected) {
const rollbackLength = (await zeroEx.getRollbackLength(selector).callAsync()).toNumber();
const rollbackHistory = await Promise.all(
_.range(rollbackLength).map(async i =>
zeroEx.getRollbackEntryAtIndex(selector, new BigNumber(i)).callAsync(),
),
);
const fullHistory = proxyFunctions.find(fn => fn.id === selector)!.fullHistory;
const previousImpl = rollbackHistory[rollbackLength - 1];
const { target } = await prompts({
type: 'select',
name: 'target',
message: 'Select the implementation to rollback to',
hint: `[${selector}] ${selectorToSignature[selector] || '(function signature not found)'}`,
choices: [
{
title: 'DISABLE',
value: constants.NULL_ADDRESS,
description: 'Rolls back to address(0)',
},
...(previousImpl !== constants.NULL_ADDRESS
? [
{
title: 'PREVIOUS',
value: previousImpl,
description: `${previousImpl} (${timestampToUTC(
_.findLast(fullHistory, update => update.impl === previousImpl)!.timestamp,
)})`,
},
]
: []),
...[...new Set(rollbackHistory)]
.filter(impl => impl !== constants.NULL_ADDRESS)
.map(impl => ({
title: impl,
value: impl,
description: timestampToUTC(_.findLast(fullHistory, update => update.impl === impl)!.timestamp),
})),
],
});
rollbackTargets[selector] = target;
}
const isConfirmed = await confirmRollbackAsync(rollbackTargets, proxyFunctions);
if (isConfirmed) {
await printRollbackCalldataAsync(rollbackTargets, zeroEx);
}
}
async function generateEmergencyRollbackAsync(proxyFunctions: ProxyFunctionEntity[]): Promise<void> {
const zeroEx = new wrappers.IZeroExContract(
getContractAddressesForChainOrThrow(1).exchangeProxy,
new Web3ProviderEngine(),
);
const allSelectors = proxyFunctions
.filter(fn => fn.currentImpl !== constants.NULL_ADDRESS && !DO_NOT_ROLLBACK.includes(fn.id))
.map(fn => fn.id);
await printRollbackCalldataAsync(
_.zipObject(allSelectors, new Array(allSelectors.length).fill(constants.NULL_ADDRESS)),
zeroEx,
);
}
let provider: SupportedProvider | undefined = process.env.RPC_URL ? createWeb3Provider(process.env.RPC_URL) : undefined;
function createWeb3Provider(rpcUrl: string): SupportedProvider {
const providerEngine = new Web3ProviderEngine();
providerEngine.addProvider(new RPCSubprovider(rpcUrl));
providerUtils.startProviderEngine(providerEngine);
return providerEngine;
}
async function getMainnetContractAsync(): Promise<wrappers.IZeroExContract> {
if (provider === undefined) {
const { rpcUrl } = await prompts({
type: 'text',
name: 'rpcUrl',
message: 'Enter an RPC endpoint:',
});
provider = createWeb3Provider(rpcUrl);
}
const chainId = await new Web3Wrapper(provider).getChainIdAsync();
const { exchangeProxy } = getContractAddressesForChainOrThrow(chainId);
return new wrappers.IZeroExContract(exchangeProxy, provider);
}
(async () => {
const proxyFunctions = await querySubgraphAsync();
const deployments = reconstructDeployments(proxyFunctions);
while (true) {
const { action } = await prompts({
type: 'select',
name: 'action',
message: 'What would you like to do?',
choices: [
{ title: '🚢 Deployment history', value: CommandLineActions.History },
{ title: '📜 Function history', value: CommandLineActions.Function },
{ title: '🗺️ Currently registered functions', value: CommandLineActions.Current },
{ title: '🔙 Generate rollback calldata', value: CommandLineActions.Rollback },
{ title: '🚨 Emergency shutdown calldata', value: CommandLineActions.Emergency },
{ title: '👋 Exit', value: CommandLineActions.Exit },
],
});
switch (action) {
case CommandLineActions.History:
await deploymentHistoryAsync(deployments, proxyFunctions);
break;
case CommandLineActions.Function:
await functionHistoryAsync(proxyFunctions);
break;
case CommandLineActions.Current:
await currentFunctionsAsync(proxyFunctions);
break;
case CommandLineActions.Rollback:
await generateRollbackAsync(proxyFunctions);
break;
case CommandLineActions.Emergency:
await generateEmergencyRollbackAsync(proxyFunctions);
break;
case CommandLineActions.Exit:
default:
process.exit(0);
}
}
})().catch(err => {
logUtils.log(err);
process.exit(1);
});

View File

@@ -76,6 +76,8 @@ import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadata
import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json';
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json';
import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json';
import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json';
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
import * as MixinDodo from '../test/generated-artifacts/MixinDodo.json';
@@ -216,6 +218,8 @@ export const artifacts = {
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact,
MixinBalancer: MixinBalancer as ContractArtifact,
MixinBancor: MixinBancor as ContractArtifact,
MixinCoFiX: MixinCoFiX as ContractArtifact,
MixinCryptoCom: MixinCryptoCom as ContractArtifact,
MixinCurve: MixinCurve as ContractArtifact,
MixinDodo: MixinDodo as ContractArtifact,

View File

@@ -9,8 +9,6 @@ import { abis } from '../utils/abis';
import { fullMigrateAsync } from '../utils/migration';
import {
LiquidityProviderSandboxContract,
TestBridgeContract,
TestBridgeEvents,
TestLiquidityProviderContract,
TestLiquidityProviderEvents,
TestWethContract,
@@ -148,41 +146,6 @@ blockchainTests('LiquidityProvider feature', env => {
TestLiquidityProviderEvents.SellTokenForToken,
);
});
it('Successfully executes an ERC20-ERC20 swap (backwards-compatibility)', async () => {
const bridge = await TestBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestBridge,
env.provider,
env.txDefaults,
artifacts,
weth.address,
token.address,
);
const tx = await feature
.sellToLiquidityProvider(
token.address,
weth.address,
bridge.address,
constants.NULL_ADDRESS,
constants.ONE_ETHER,
constants.ZERO_AMOUNT,
constants.NULL_BYTES,
)
.awaitTransactionSuccessAsync({ from: taker });
verifyEventsFromLogs(
tx.logs,
[
{
inputToken: token.address,
outputToken: weth.address,
inputTokenAmount: constants.ONE_ETHER,
outputTokenAmount: constants.ZERO_AMOUNT,
from: bridge.address,
to: taker,
},
],
TestBridgeEvents.ERC20BridgeTransfer,
);
});
it('Reverts if cannot fulfill the minimum buy amount', async () => {
const minBuyAmount = new BigNumber(1);
const tx = feature

View File

@@ -6,9 +6,7 @@ import {
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { getExchangeProxyMetaTransactionHash, signatureUtils } from '@0x/order-utils';
import { Signature } from '@0x/protocol-utils';
import { ExchangeProxyMetaTransaction } from '@0x/types';
import { MetaTransaction, MetaTransactionFields } from '@0x/protocol-utils';
import { BigNumber, hexUtils, StringRevertError, ZeroExRevertErrors } from '@0x/utils';
import * as _ from 'lodash';
@@ -31,6 +29,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
let owner: string;
let maker: string;
let sender: string;
let notSigner: string;
let signers: string[];
let zeroEx: IZeroExContract;
let feature: MetaTransactionsFeatureContract;
@@ -45,7 +44,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
const REENTRANCY_FLAG_MTX = 0x1;
before(async () => {
[owner, maker, sender, ...signers] = await env.getAccountAddressesAsync();
[owner, maker, sender, notSigner, ...signers] = await env.getAccountAddressesAsync();
transformERC20Feature = await TestMetaTransactionsTransformERC20FeatureContract.deployFrom0xArtifactAsync(
artifacts.TestMetaTransactionsTransformERC20Feature,
env.provider,
@@ -83,19 +82,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
);
});
function sigstruct(signature: string): Signature {
return {
v: parseInt(hexUtils.slice(signature, 0, 1), 16),
signatureType: parseInt(hexUtils.slice(signature, 65, 66), 16),
r: hexUtils.slice(signature, 1, 33),
s: hexUtils.slice(signature, 33, 65),
};
}
function getRandomMetaTransaction(
fields: Partial<ExchangeProxyMetaTransaction> = {},
): ExchangeProxyMetaTransaction {
return {
function getRandomMetaTransaction(fields: Partial<MetaTransactionFields> = {}): MetaTransaction {
return new MetaTransaction({
signer: _.sampleSize(signers)[0],
sender,
minGasPrice: getRandomInteger('2', '1e9'),
@@ -106,28 +94,16 @@ blockchainTests.resets('MetaTransactions feature', env => {
value: getRandomInteger(1, '1e18'),
feeToken: feeToken.address,
feeAmount: getRandomInteger(1, MAX_FEE_AMOUNT),
domain: {
chainId: 1, // Ganache's `chainid` opcode is hardcoded as 1
verifyingContract: zeroEx.address,
},
chainId: 1, // Ganache's `chainid` opcode is hardcoded as 1
verifyingContract: zeroEx.address,
...fields,
};
}
async function signMetaTransactionAsync(mtx: ExchangeProxyMetaTransaction, signer?: string): Promise<Signature> {
return sigstruct(
await signatureUtils.ecSignHashAsync(
env.provider,
getExchangeProxyMetaTransactionHash(mtx),
signer || mtx.signer,
),
);
});
}
describe('getMetaTransactionHash()', () => {
it('generates the correct hash', async () => {
const mtx = getRandomMetaTransaction();
const expected = getExchangeProxyMetaTransactionHash(mtx);
const expected = mtx.getHash();
const actual = await feature.getMetaTransactionHash(mtx).callAsync();
expect(actual).to.eq(expected);
});
@@ -163,7 +139,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
const mtx = getRandomMetaTransaction({
callData: nativeOrdersFeature.fillLimitOrder(order, sig, fillAmount).getABIEncodedTransactionData(),
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -198,7 +174,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
callData: nativeOrdersFeature.fillRfqOrder(order, sig, fillAmount).getABIEncodedTransactionData(),
value: ZERO_AMOUNT,
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: 0,
@@ -237,7 +213,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -275,7 +251,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData();
const mtx = getRandomMetaTransaction({ callData });
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -315,7 +291,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -340,7 +316,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -363,8 +339,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -393,8 +369,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
const mtx = getRandomMetaTransaction({
callData: transformERC20Feature.createTransformWallet().getABIEncodedTransactionData(),
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -421,8 +397,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -439,8 +415,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
it('fails if not enough ETH provided', async () => {
const mtx = getRandomMetaTransaction();
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value.minus(1),
@@ -457,8 +433,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
it('fails if gas price too low', async () => {
const mtx = getRandomMetaTransaction();
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice.minus(1),
value: mtx.value,
@@ -476,8 +452,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
it('fails if gas price too high', async () => {
const mtx = getRandomMetaTransaction();
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice.plus(1),
value: mtx.value,
@@ -497,8 +473,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
const mtx = getRandomMetaTransaction({
expirationTimeSeconds: new BigNumber(Math.floor(_.now() / 1000 - 60)),
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -518,8 +494,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
const mtx = getRandomMetaTransaction({
sender: requiredSender,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -536,8 +512,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
it('fails if signature is wrong', async () => {
const mtx = getRandomMetaTransaction({ signer: signers[0] });
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx, signers[1]);
const mtxHash = mtx.getHash();
const signature = await mtx.clone({ signer: notSigner }).getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -567,8 +543,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_REENTER_VALUE,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -600,8 +576,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_BATCH_REENTER_VALUE,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -633,8 +609,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_REENTER_VALUE,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -666,8 +642,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_BATCH_REENTER_VALUE,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -703,7 +679,9 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
});
});
const signatures = await Promise.all(mtxs.map(async mtx => signMetaTransactionAsync(mtx)));
const signatures = await Promise.all(
mtxs.map(async mtx => mtx.getSignatureWithProviderAsync(env.provider)),
);
const callOpts = {
gasPrice: BigNumber.max(...mtxs.map(mtx => mtx.minGasPrice)),
value: BigNumber.sum(...mtxs.map(mtx => mtx.value)),
@@ -728,9 +706,9 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
});
})();
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const mtxHash = mtx.getHash();
const mtxs = _.times(2, () => mtx);
const signatures = await Promise.all(mtxs.map(async m => signMetaTransactionAsync(m)));
const signatures = await Promise.all(mtxs.map(async m => m.getSignatureWithProviderAsync(env.provider)));
const callOpts = {
gasPrice: BigNumber.max(...mtxs.map(m => m.minGasPrice)),
value: BigNumber.sum(...mtxs.map(m => m.value)),
@@ -756,8 +734,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -786,8 +764,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_REENTER_VALUE,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -819,8 +797,8 @@ blockchainTests.resets('MetaTransactions feature', env => {
.getABIEncodedTransactionData(),
value: TRANSFORM_ERC20_BATCH_REENTER_VALUE,
});
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const signature = await signMetaTransactionAsync(mtx);
const mtxHash = mtx.getHash();
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.maxGasPrice,
value: mtx.value,
@@ -859,7 +837,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
@@ -873,7 +851,7 @@ blockchainTests.resets('MetaTransactions feature', env => {
describe('getMetaTransactionHashExecutedBlock()', () => {
it('returns zero for an unexecuted mtx', async () => {
const mtx = getRandomMetaTransaction();
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const mtxHash = mtx.getHash();
const block = await feature.getMetaTransactionHashExecutedBlock(mtxHash).callAsync();
expect(block).to.bignumber.eq(0);
});
@@ -891,13 +869,13 @@ blockchainTests.resets('MetaTransactions feature', env => {
)
.getABIEncodedTransactionData(),
});
const signature = await signMetaTransactionAsync(mtx);
const signature = await mtx.getSignatureWithProviderAsync(env.provider);
const callOpts = {
gasPrice: mtx.minGasPrice,
value: mtx.value,
};
const receipt = await feature.executeMetaTransaction(mtx, signature).awaitTransactionSuccessAsync(callOpts);
const mtxHash = getExchangeProxyMetaTransactionHash(mtx);
const mtxHash = mtx.getHash();
const block = await feature.getMetaTransactionHashExecutedBlock(mtxHash).callAsync();
expect(block).to.bignumber.eq(receipt.blockNumber);
});

View File

@@ -1366,14 +1366,332 @@ blockchainTests.resets('NativeOrdersFeature', env => {
});
});
it.skip('RFQ gas benchmark', async () => {
const orders = [...new Array(2)].map(() =>
getTestRfqOrder({ pool: '0x0000000000000000000000000000000000000000000000000000000000000000' }),
);
// Fill one to warm up the fee pool.
await fillRfqOrderAsync(orders[0]);
const receipt = await fillRfqOrderAsync(orders[1]);
// tslint:disable-next-line: no-console
console.log(receipt.gasUsed);
async function fundOrderMakerAsync(
order: LimitOrder | RfqOrder,
balance: BigNumber = order.makerAmount,
allowance: BigNumber = order.makerAmount,
): Promise<void> {
await makerToken.burn(maker, await makerToken.balanceOf(maker).callAsync()).awaitTransactionSuccessAsync();
await makerToken.mint(maker, balance).awaitTransactionSuccessAsync();
await makerToken.approve(zeroEx.address, allowance).awaitTransactionSuccessAsync({ from: maker });
}
function getFillableMakerTokenAmount(
order: LimitOrder | RfqOrder,
takerTokenFilledAmount: BigNumber = ZERO_AMOUNT,
): BigNumber {
return order.takerAmount
.minus(takerTokenFilledAmount)
.times(order.makerAmount)
.div(order.takerAmount)
.integerValue(BigNumber.ROUND_DOWN);
}
function getActualFillableTakerTokenAmount(
order: LimitOrder | RfqOrder,
makerBalance: BigNumber = order.makerAmount,
makerAllowance: BigNumber = order.makerAmount,
takerTokenFilledAmount: BigNumber = ZERO_AMOUNT,
): BigNumber {
const fillableMakerTokenAmount = getFillableMakerTokenAmount(order, takerTokenFilledAmount);
return BigNumber.min(fillableMakerTokenAmount, makerBalance, makerAllowance)
.times(order.takerAmount)
.div(order.makerAmount)
.integerValue(BigNumber.ROUND_UP);
}
function getRandomFraction(precision: number = 2): string {
return Math.random().toPrecision(precision);
}
describe('getLimitOrderRelevantState()', () => {
it('works with an empty order', async () => {
const order = getTestLimitOrder({
takerAmount: ZERO_AMOUNT,
});
await fundOrderMakerAsync(order);
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getLimitOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Filled,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(0);
expect(isSignatureValid).to.eq(true);
});
it('works with cancelled order', async () => {
const order = getTestLimitOrder();
await fundOrderMakerAsync(order);
await zeroEx.cancelLimitOrder(order).awaitTransactionSuccessAsync({ from: maker });
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getLimitOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Cancelled,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(0);
expect(isSignatureValid).to.eq(true);
});
it('works with a bad signature', async () => {
const order = getTestLimitOrder();
await fundOrderMakerAsync(order);
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getLimitOrderRelevantState(
order,
await order.clone({ maker: notMaker }).getSignatureWithProviderAsync(env.provider),
)
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(order.takerAmount);
expect(isSignatureValid).to.eq(false);
});
it('works with an unfilled order', async () => {
const order = getTestLimitOrder();
await fundOrderMakerAsync(order);
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getLimitOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(order.takerAmount);
expect(isSignatureValid).to.eq(true);
});
it('works with a fully filled order', async () => {
const order = getTestLimitOrder();
// Fully Fund maker and taker.
await fundOrderMakerAsync(order);
await takerToken
.mint(taker, order.takerAmount.plus(order.takerTokenFeeAmount))
.awaitTransactionSuccessAsync();
await fillLimitOrderAsync(order);
// Partially fill the order.
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getLimitOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Filled,
takerTokenFilledAmount: order.takerAmount,
});
expect(fillableTakerAmount).to.bignumber.eq(0);
expect(isSignatureValid).to.eq(true);
});
it('works with an under-funded, partially-filled order', async () => {
const order = getTestLimitOrder();
// Fully Fund maker and taker.
await fundOrderMakerAsync(order);
await takerToken
.mint(taker, order.takerAmount.plus(order.takerTokenFeeAmount))
.awaitTransactionSuccessAsync();
// Partially fill the order.
const fillAmount = order.takerAmount.times(getRandomFraction()).integerValue();
await fillLimitOrderAsync(order, { fillAmount });
// Reduce maker funds to be < remaining.
const remainingMakerAmount = getFillableMakerTokenAmount(order, fillAmount);
const balance = remainingMakerAmount.times(getRandomFraction()).integerValue();
const allowance = remainingMakerAmount.times(getRandomFraction()).integerValue();
await fundOrderMakerAsync(order, balance, allowance);
// Get order state.
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getLimitOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: fillAmount,
});
expect(fillableTakerAmount).to.bignumber.eq(
getActualFillableTakerTokenAmount(order, balance, allowance, fillAmount),
);
expect(isSignatureValid).to.eq(true);
});
});
describe('getRfqOrderRelevantState()', () => {
it('works with an empty order', async () => {
const order = getTestRfqOrder({
takerAmount: ZERO_AMOUNT,
});
await fundOrderMakerAsync(order);
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getRfqOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Filled,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(0);
expect(isSignatureValid).to.eq(true);
});
it('works with cancelled order', async () => {
const order = getTestRfqOrder();
await fundOrderMakerAsync(order);
await zeroEx.cancelRfqOrder(order).awaitTransactionSuccessAsync({ from: maker });
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getRfqOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Cancelled,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(0);
expect(isSignatureValid).to.eq(true);
});
it('works with a bad signature', async () => {
const order = getTestRfqOrder();
await fundOrderMakerAsync(order);
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getRfqOrderRelevantState(
order,
await order.clone({ maker: notMaker }).getSignatureWithProviderAsync(env.provider),
)
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(order.takerAmount);
expect(isSignatureValid).to.eq(false);
});
it('works with an unfilled order', async () => {
const order = getTestRfqOrder();
await fundOrderMakerAsync(order);
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getRfqOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmount).to.bignumber.eq(order.takerAmount);
expect(isSignatureValid).to.eq(true);
});
it('works with a fully filled order', async () => {
const order = getTestRfqOrder();
// Fully Fund maker and taker.
await fundOrderMakerAsync(order);
await takerToken.mint(taker, order.takerAmount);
await fillRfqOrderAsync(order);
// Partially fill the order.
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getRfqOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Filled,
takerTokenFilledAmount: order.takerAmount,
});
expect(fillableTakerAmount).to.bignumber.eq(0);
expect(isSignatureValid).to.eq(true);
});
it('works with an under-funded, partially-filled order', async () => {
const order = getTestRfqOrder();
// Fully Fund maker and taker.
await fundOrderMakerAsync(order);
await takerToken.mint(taker, order.takerAmount).awaitTransactionSuccessAsync();
// Partially fill the order.
const fillAmount = order.takerAmount.times(getRandomFraction()).integerValue();
await fillRfqOrderAsync(order, fillAmount);
// Reduce maker funds to be < remaining.
const remainingMakerAmount = getFillableMakerTokenAmount(order, fillAmount);
const balance = remainingMakerAmount.times(getRandomFraction()).integerValue();
const allowance = remainingMakerAmount.times(getRandomFraction()).integerValue();
await fundOrderMakerAsync(order, balance, allowance);
// Get order state.
const [orderInfo, fillableTakerAmount, isSignatureValid] = await zeroEx
.getRfqOrderRelevantState(order, await order.getSignatureWithProviderAsync(env.provider))
.callAsync();
expect(orderInfo).to.deep.eq({
orderHash: order.getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: fillAmount,
});
expect(fillableTakerAmount).to.bignumber.eq(
getActualFillableTakerTokenAmount(order, balance, allowance, fillAmount),
);
expect(isSignatureValid).to.eq(true);
});
});
async function batchFundOrderMakerAsync(orders: Array<LimitOrder | RfqOrder>): Promise<void> {
await makerToken.burn(maker, await makerToken.balanceOf(maker).callAsync()).awaitTransactionSuccessAsync();
const balance = BigNumber.sum(...orders.map(o => o.makerAmount));
await makerToken.mint(maker, balance).awaitTransactionSuccessAsync();
await makerToken.approve(zeroEx.address, balance).awaitTransactionSuccessAsync({ from: maker });
}
describe('batchGetLimitOrderRelevantStates()', () => {
it('works with multiple orders', async () => {
const orders = new Array(3).fill(0).map(() => getTestLimitOrder());
await batchFundOrderMakerAsync(orders);
const [orderInfos, fillableTakerAmounts, isSignatureValids] = await zeroEx
.batchGetLimitOrderRelevantStates(
orders,
await Promise.all(orders.map(async o => o.getSignatureWithProviderAsync(env.provider))),
)
.callAsync();
expect(orderInfos).to.be.length(orders.length);
expect(fillableTakerAmounts).to.be.length(orders.length);
expect(isSignatureValids).to.be.length(orders.length);
for (let i = 0; i < orders.length; ++i) {
expect(orderInfos[i]).to.deep.eq({
orderHash: orders[i].getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmounts[i]).to.bignumber.eq(orders[i].takerAmount);
expect(isSignatureValids[i]).to.eq(true);
}
});
});
describe('batchGetRfqOrderRelevantStates()', () => {
it('works with multiple orders', async () => {
const orders = new Array(3).fill(0).map(() => getTestRfqOrder());
await batchFundOrderMakerAsync(orders);
const [orderInfos, fillableTakerAmounts, isSignatureValids] = await zeroEx
.batchGetRfqOrderRelevantStates(
orders,
await Promise.all(orders.map(async o => o.getSignatureWithProviderAsync(env.provider))),
)
.callAsync();
expect(orderInfos).to.be.length(orders.length);
expect(fillableTakerAmounts).to.be.length(orders.length);
expect(isSignatureValids).to.be.length(orders.length);
for (let i = 0; i < orders.length; ++i) {
expect(orderInfos[i]).to.deep.eq({
orderHash: orders[i].getHash(),
status: OrderStatus.Fillable,
takerTokenFilledAmount: ZERO_AMOUNT,
});
expect(fillableTakerAmounts[i]).to.bignumber.eq(orders[i].takerAmount);
expect(isSignatureValids[i]).to.eq(true);
}
});
});
});

View File

@@ -78,6 +78,8 @@ blockchainTests.resets('FillQuoteTransformer', env => {
dodoHelper: NULL_ADDRESS,
snowSwapBridge: NULL_ADDRESS,
cryptoComBridge: NULL_ADDRESS,
bancorBridge: NULL_ADDRESS,
cofixBridge: NULL_ADDRESS,
},
);
transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(

View File

@@ -74,6 +74,8 @@ export * from '../test/generated-wrappers/log_metadata_transformer';
export * from '../test/generated-wrappers/meta_transactions_feature';
export * from '../test/generated-wrappers/mixin_adapter_addresses';
export * from '../test/generated-wrappers/mixin_balancer';
export * from '../test/generated-wrappers/mixin_bancor';
export * from '../test/generated-wrappers/mixin_co_fi_x';
export * from '../test/generated-wrappers/mixin_crypto_com';
export * from '../test/generated-wrappers/mixin_curve';
export * from '../test/generated-wrappers/mixin_dodo';

View File

@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig",
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*", "./scripts/**/*"],
"files": [
"generated-artifacts/AffiliateFeeTransformer.json",
"generated-artifacts/BridgeAdapter.json",
@@ -103,6 +103,8 @@
"test/generated-artifacts/MetaTransactionsFeature.json",
"test/generated-artifacts/MixinAdapterAddresses.json",
"test/generated-artifacts/MixinBalancer.json",
"test/generated-artifacts/MixinBancor.json",
"test/generated-artifacts/MixinCoFiX.json",
"test/generated-artifacts/MixinCryptoCom.json",
"test/generated-artifacts/MixinCurve.json",
"test/generated-artifacts/MixinDodo.json",

File diff suppressed because one or more lines are too long

View File

@@ -137,4 +137,34 @@ In both cases, the ``@0x/protocol-utils`` package simplifies generating these si
The Orderbook
=======================
Orders are shared through a decentralized and permissionless network, called `0x Mesh <https://0x.org/mesh>`_. The simplest way to post and discover orders is through `0x API <https://0x.org/api>`_. See `this guide <https://0x.org/docs/guides/market-making-on-0x>`_ tailored for Market Makers.
Orders are shared through a decentralized and permissionless network, called `0x Mesh <https://0x.org/mesh>`_. The simplest way to post and discover orders is through `0x API <https://0x.org/api>`_. See `this guide <https://0x.org/docs/guides/market-making-on-0x>`_ tailored for Market Makers.
Orders are usually represented as a JSON object off-chain. Below is a table represention and example of how orders should be formatted off-chain.
JSON representation of RFQ Orders
*********************************
A ``RFQOrder`` should be serialized to JSON as following:
.. code-block:: typescript
interface RfqOrderJson {
"maker": string,
"taker": string,
"makerToken": string,
"takerToken": string,
"makerAmount": string,
"takerAmount": string,
"txOrigin": string,
"pool": string,
"expiry": number,
"salt": string,
"chainId": number, // Ethereum Chain Id where the transaction is submitted.
"verifyingContract": string, // Address of the contract where the transaction should be sent.
"signature": {
"signatureType": number,
"v": number,
"s": string,
"r": string,
}
}

View File

@@ -65,6 +65,7 @@ Chat with our team privately on `Discord <https://discord.com/invite/d3FTX3M>`_
additional/contributing.rst
additional/exceptional_erc20s.rst
additional/releases.rst
additional/emergency.rst
.. toctree::
:maxdepth: 1

View File

@@ -80,7 +80,7 @@ Staking aligns all market participants with the long-term mission and objectives
Token holders stake their ZRX to unlock utility within the 0x ecosystem. This includes earning liquidity rewards through market making on the 0x protocol and participating in governance over the protocol.
A market maker provides liquidity by creating 0x orders that are filled by takers through the [`Exchange`](../v3/v3-specifications.md#exchange) contract. The `Exchange` charges a fee to the taker on each fill and forwards it to the [`Staking`](#staking) contract. The fee is attributed to the maker so long as they have created a staking pool that holds at least 100 ZRX. After every 10 day epoch, the fees are aggregated and distributed to the makers as a liquidity reward: the reward is proportional to the maker's collected fees and stake relative to other makers.
A market maker provides liquidity by creating 0x orders that are filled by takers through the [`Exchange`](../v3/v3-specifications.md#exchange) contract. The `Exchange` charges a fee to the taker on each fill and forwards it to the [`Staking`](#staking) contract. The fee is attributed to the maker so long as they have created a staking pool that holds at least 100 ZRX. After every 7 day epoch, the fees are aggregated and distributed to the makers as a liquidity reward: the reward is proportional to the maker's collected fees and stake relative to other makers.
Governance over the protocol is conducted by voting on [ZEIPs (ZeroEx Improvement Proposals)](https://github.com/0xProject/ZEIPs). A ZEIP generally corresponds to a modification or upgrade to the 0x protocol. The ecosystem votes on the proposal, collectively deciding whether the feature will be included in a future version of the protocol. One Staked ZRX equals one vote.
@@ -215,7 +215,7 @@ function validExchanges(address addr)
## Epochs & Scheduling
All processes in the system are segmented into contiguous time intervals, called epochs. Epochs have a fixed minimum period (10 days at time of writing), which is configurable via [MixinParams](https://github.com/0xProject/0x-monorepo/blob/development/contracts/staking/contracts/src/sys/MixinParams.sol). Epochs serve as the basis for all other timeframes within the system, which provides a more stable and consistent scheduling metric than blocks or block timestamps.
All processes in the system are segmented into contiguous time intervals, called epochs. Epochs have a fixed minimum period (7 days at time of writing), which is configurable via [MixinParams](https://github.com/0xProject/0x-monorepo/blob/development/contracts/staking/contracts/src/sys/MixinParams.sol). Epochs serve as the basis for all other timeframes within the system, which provides a more stable and consistent scheduling metric than blocks or block timestamps.
<p align="center"><img src="../_static/staking/Epochs.png" width="700" /></p>
@@ -1481,4 +1481,4 @@ The amount that can be unstaked is equal to `min(undelegated.cur, undelegated.ne
The figure below illustrates how these fields are updated to track a user's stake.
<p align="center"><img src="../_static/staking/StakeManagementExample2.png" width="640" /></p>
<p align="center"><img src="../_static/staking/StakeManagementExample2.png" width="640" /></p>

View File

@@ -1,4 +1,69 @@
[
{
"timestamp": 1609802516,
"version": "5.6.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "5.6.1",
"changes": [
{
"note": "Fix fillAmount `ExchangeProxySwapQuoteConsumer` encoding when quote is a BuyQuote"
}
],
"timestamp": 1609387311
},
{
"version": "5.6.0",
"changes": [
{
"note": "Added Mooniswap V2 factory address",
"pr": 100
}
],
"timestamp": 1609113560
},
{
"timestamp": 1608692071,
"version": "5.5.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "5.5.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608149382,
"version": "5.5.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "5.5.0",
"changes": [
{
"note": "Bancor now supported in all pairs",
"pr": 88
}
],
"timestamp": 1608105788
},
{
"timestamp": 1607485227,
"version": "5.4.2",

View File

@@ -5,6 +5,34 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.6.2 - _January 4, 2021_
* Dependencies updated
## v5.6.1 - _December 31, 2020_
* Fix fillAmount `ExchangeProxySwapQuoteConsumer` encoding when quote is a BuyQuote
## v5.6.0 - _December 27, 2020_
* Added Mooniswap V2 factory address (#100)
## v5.5.3 - _December 23, 2020_
* Dependencies updated
## v5.5.2 - _December 17, 2020_
* Dependencies updated
## v5.5.1 - _December 16, 2020_
* Dependencies updated
## v5.5.0 - _December 16, 2020_
* Bancor now supported in all pairs (#88)
## v5.4.2 - _December 9, 2020_
* Dependencies updated

View File

@@ -0,0 +1,131 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "./DeploymentConstants.sol";
import "./interfaces/IBancor.sol";
contract BancorSampler is
DeploymentConstants
{
/// @dev Base gas limit for Bancor calls.
uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k
address constant private BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Sample sell quotes from Bancor.
/// @param paths The paths to check for Bancor. Only the best is used
/// @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 bancorNetwork the Bancor Network address
/// @return path the selected conversion path from bancor
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromBancor(
address[][] memory paths,
address takerToken,
address makerToken,
uint256[] memory takerTokenAmounts
)
public
view
returns (address bancorNetwork, address[] memory path, uint256[] memory makerTokenAmounts)
{
bancorNetwork = _getBancorNetwork();
if (paths.length == 0) {
return (bancorNetwork, path, makerTokenAmounts);
}
uint256 maxBoughtAmount = 0;
// Find the best path by selling the largest taker amount
for (uint256 i = 0; i < paths.length; i++) {
if (paths[i].length < 2) {
continue;
}
try
IBancorNetwork(bancorNetwork)
.rateByPath
{gas: BANCOR_CALL_GAS}
(paths[i], takerTokenAmounts[takerTokenAmounts.length-1])
returns (uint256 amount)
{
if (amount > maxBoughtAmount) {
maxBoughtAmount = amount;
path = paths[i];
}
} catch {
// Swallow failures, leaving all results as zero.
continue;
}
}
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
try
IBancorNetwork(bancorNetwork)
.rateByPath
{gas: BANCOR_CALL_GAS}
(path, takerTokenAmounts[i])
returns (uint256 amount)
{
makerTokenAmounts[i] = amount;
} catch {
// Swallow failures, leaving all results as zero.
break;
}
}
return (bancorNetwork, path, makerTokenAmounts);
}
/// @dev Sample buy quotes from Bancor. Unimplemented
/// @param paths The paths to check for Bancor. Only the best is used
/// @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 bancorNetwork the Bancor Network address
/// @return path the selected conversion path from bancor
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.
function sampleBuysFromBancor(
address[][] memory paths,
address takerToken,
address makerToken,
uint256[] memory makerTokenAmounts
)
public
view
returns (address bancorNetwork, address[] memory path, uint256[] memory takerTokenAmounts)
{
}
function _getBancorNetwork()
private
view
returns (address)
{
IBancorRegistry registry = IBancorRegistry(_getBancorRegistryAddress());
return registry.getAddress(registry.BANCOR_NETWORK());
}
}

View File

@@ -62,6 +62,8 @@ contract DeploymentConstants {
address constant private DODO_REGISTRY = 0x3A97247DF274a17C59A3bd12735ea3FcDFb49950;
/// @dev Mainnet address of the DODO Helper contract
address constant private DODO_HELPER = 0x533dA777aeDCE766CEAe696bf90f8541A4bA80Eb;
/// @dev Mainnet address of the Bancor Registry contract
address constant private BANCOR_REGISTRY = 0x52Ae12ABe5D8BD778BD5397F99cA900624CfADD4;
// // Ropsten addresses ///////////////////////////////////////////////////////
// /// @dev Mainnet address of the WETH contract.
@@ -337,4 +339,14 @@ contract DeploymentConstants {
{
return DODO_HELPER;
}
/// @dev An overridable way to retrieve the Bancor Registry contract address.
/// @return registry The Bancor registry contract address.
function _getBancorRegistryAddress()
internal
view
returns (address registry)
{
return BANCOR_REGISTRY;
}
}

View File

@@ -20,6 +20,7 @@ pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "./BalancerSampler.sol";
import "./BancorSampler.sol";
import "./CurveSampler.sol";
import "./DODOSampler.sol";
import "./Eth2DaiSampler.sol";
@@ -38,6 +39,7 @@ import "./UniswapV2Sampler.sol";
contract ERC20BridgeSampler is
BalancerSampler,
BancorSampler,
CurveSampler,
DODOSampler,
Eth2DaiSampler,

View File

@@ -34,6 +34,7 @@ contract MooniswapSampler is
uint256 constant private MOONISWAP_CALL_GAS = 150e3; // 150k
/// @dev Sample sell quotes from Mooniswap.
/// @param registry Address of the Mooniswap Registry.
/// @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.
@@ -41,6 +42,7 @@ contract MooniswapSampler is
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromMooniswap(
address registry,
address takerToken,
address makerToken,
uint256[] memory takerTokenAmounts
@@ -58,6 +60,7 @@ contract MooniswapSampler is
for (uint256 i = 0; i < numSamples; i++) {
uint256 buyAmount = sampleSingleSellFromMooniswapPool(
registry,
mooniswapTakerToken,
mooniswapMakerToken,
takerTokenAmounts[i]
@@ -70,11 +73,12 @@ contract MooniswapSampler is
}
pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(mooniswapTakerToken, mooniswapMakerToken)
IMooniswapRegistry(registry).pools(mooniswapTakerToken, mooniswapMakerToken)
);
}
function sampleSingleSellFromMooniswapPool(
address registry,
address mooniswapTakerToken,
address mooniswapMakerToken,
uint256 takerTokenAmount
@@ -85,7 +89,7 @@ contract MooniswapSampler is
{
// Find the pool for the pair.
IMooniswap pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(mooniswapTakerToken, mooniswapMakerToken)
IMooniswapRegistry(registry).pools(mooniswapTakerToken, mooniswapMakerToken)
);
// If there is no pool then return early
if (address(pool) == address(0)) {
@@ -113,6 +117,7 @@ contract MooniswapSampler is
}
/// @dev Sample buy quotes from Mooniswap.
/// @param registry Address of the Mooniswap Registry.
/// @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.
@@ -120,6 +125,7 @@ contract MooniswapSampler is
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.
function sampleBuysFromMooniswap(
address registry,
address takerToken,
address makerToken,
uint256[] memory makerTokenAmounts
@@ -137,15 +143,15 @@ contract MooniswapSampler is
takerTokenAmounts = _sampleApproximateBuys(
ApproximateBuyQuoteOpts({
makerTokenData: abi.encode(mooniswapMakerToken),
takerTokenData: abi.encode(mooniswapTakerToken),
makerTokenData: abi.encode(registry, mooniswapMakerToken),
takerTokenData: abi.encode(registry, mooniswapTakerToken),
getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap
}),
makerTokenAmounts
);
pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(mooniswapTakerToken, mooniswapMakerToken)
IMooniswapRegistry(registry).pools(mooniswapTakerToken, mooniswapMakerToken)
);
}
@@ -158,9 +164,10 @@ contract MooniswapSampler is
view
returns (uint256 buyAmount)
{
address mooniswapTakerToken = abi.decode(takerTokenData, (address));
address mooniswapMakerToken = abi.decode(makerTokenData, (address));
(address registry, address mooniswapTakerToken) = abi.decode(takerTokenData, (address, address));
(address _registry, address mooniswapMakerToken) = abi.decode(makerTokenData, (address, address));
return sampleSingleSellFromMooniswapPool(
registry,
mooniswapTakerToken,
mooniswapMakerToken,
sellAmount

View File

@@ -0,0 +1,32 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6;
interface IBancor {}
interface IBancorNetwork {
function conversionPath(address _sourceToken, address _targetToken) external view returns (address[] memory);
function rateByPath(address[] memory _path, uint256 _amount) external view returns (uint256);
}
interface IBancorRegistry {
function getAddress(bytes32 _contractName) external view returns (address);
function BANCOR_NETWORK() external view returns (bytes32);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/asset-swapper",
"version": "5.4.2",
"version": "5.6.2",
"engines": {
"node": ">=6.12"
},
@@ -38,7 +38,7 @@
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DeploymentConstants|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
"postpublish": {
"assets": []
}
@@ -59,11 +59,11 @@
"dependencies": {
"@0x/assert": "^3.0.19",
"@0x/base-contract": "^6.2.14",
"@0x/contract-addresses": "^5.6.0",
"@0x/contract-wrappers": "^13.11.0",
"@0x/contract-addresses": "^5.8.0",
"@0x/contract-wrappers": "^13.12.0",
"@0x/dev-utils": "^4.1.3",
"@0x/json-schemas": "^5.3.4",
"@0x/order-utils": "^10.4.10",
"@0x/order-utils": "^10.4.13",
"@0x/orderbook": "0xProject/gitpkg-registry#0x-orderbook-v2.2.7-e10a81023",
"@0x/quote-server": "^3.1.0",
"@0x/types": "^3.3.1",
@@ -71,7 +71,7 @@
"@0x/utils": "^6.1.1",
"@0x/web3-wrapper": "^7.3.0",
"@balancer-labs/sor": "0.3.2",
"@bancor/sdk": "^0.2.9",
"@bancor/sdk": "0.2.9",
"@ethersproject/abi": "^5.0.1",
"@ethersproject/address": "^5.0.1",
"@ethersproject/contracts": "^5.0.1",
@@ -87,16 +87,16 @@
},
"devDependencies": {
"@0x/base-contract": "^6.2.14",
"@0x/contracts-asset-proxy": "^3.6.9",
"@0x/contracts-erc20": "^3.2.12",
"@0x/contracts-exchange": "^3.2.18",
"@0x/contracts-exchange-libs": "^4.3.18",
"@0x/contracts-asset-proxy": "^3.7.3",
"@0x/contracts-erc20": "^3.3.0",
"@0x/contracts-exchange": "^3.2.22",
"@0x/contracts-exchange-libs": "^4.3.21",
"@0x/contracts-gen": "^2.0.24",
"@0x/contracts-test-utils": "^5.3.15",
"@0x/contracts-utils": "^4.6.3",
"@0x/contracts-zero-ex": "^0.12.0",
"@0x/contracts-test-utils": "^5.3.18",
"@0x/contracts-utils": "^4.7.0",
"@0x/contracts-zero-ex": "^0.17.0",
"@0x/mesh-rpc-client": "^9.4.2",
"@0x/migrations": "^6.5.4",
"@0x/migrations": "^6.5.9",
"@0x/sol-compiler": "^4.4.1",
"@0x/subproviders": "^6.2.3",
"@0x/ts-doc-gen": "^0.0.28",

View File

@@ -205,7 +205,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
buyToken,
refundReceiver: refundReceiver || NULL_ADDRESS,
side: isBuyQuote(quote) ? FillQuoteTransformerSide.Buy : FillQuoteTransformerSide.Sell,
fillAmount: shouldSellEntireBalance ? MAX_UINT256 : fillAmount,
fillAmount: !isBuyQuote(quote) && shouldSellEntireBalance ? MAX_UINT256 : fillAmount,
maxOrderFillAmounts: [],
rfqtTakerAddress: NULL_ADDRESS,
orders: quote.orders,

View File

@@ -1,4 +1,4 @@
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { DevUtilsContract } from '@0x/contract-wrappers';
import { schemas } from '@0x/json-schemas';
import { assetDataUtils, SignedOrder } from '@0x/order-utils';
@@ -26,6 +26,7 @@ import {
import { assert } from './utils/assert';
import { calculateLiquidity } from './utils/calculate_liquidity';
import { MarketOperationUtils } from './utils/market_operation_utils';
import { BancorService } from './utils/market_operation_utils/bancor_service';
import { createDummyOrderForSampler } from './utils/market_operation_utils/orders';
import { DexOrderSampler } from './utils/market_operation_utils/sampler';
import { SourceFilters } from './utils/market_operation_utils/source_filters';
@@ -208,16 +209,18 @@ export class SwapQuoter {
gas: samplerGasLimit,
},
);
this._marketOperationUtils = new MarketOperationUtils(
new DexOrderSampler(
samplerContract,
samplerOverrides,
provider,
undefined,
undefined,
undefined,
undefined, // balancer pool cache
undefined, // cream pool cache
tokenAdjacencyGraph,
liquidityProviderRegistry,
this.chainId === ChainId.Mainnet // Enable Bancor only on Mainnet
? async () => BancorService.createAsync(provider)
: async () => undefined,
),
this._contractAddresses,
{

View File

@@ -1,26 +1,17 @@
import { SupportedProvider } from '@0x/dev-utils';
import { BigNumber } from '@0x/utils';
import { SDK } from '@bancor/sdk';
import { Ethereum, getDecimals } from '@bancor/sdk/dist/blockchains/ethereum';
import { fromWei, toWei } from '@bancor/sdk/dist/helpers';
import { BlockchainType, Token } from '@bancor/sdk/dist/types';
import { Ethereum } from '@bancor/sdk/dist/blockchains/ethereum';
import { BlockchainType } from '@bancor/sdk/dist/types';
import { BancorFillData, Quote } from './types';
import { TOKENS } from './constants';
/**
* Converts an address to a Bancor Token type
*/
export function token(address: string, blockchainType: BlockchainType = BlockchainType.Ethereum): Token {
return {
blockchainType,
blockchainId: address,
};
}
const findToken = (tokenAddress: string, graph: object): string =>
// If we're looking for WETH it is stored by Bancor as the 0xeee address
tokenAddress.toLowerCase() === TOKENS.WETH.toLowerCase()
? '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'
: Object.keys(graph).filter(k => k.toLowerCase() === tokenAddress.toLowerCase())[0];
export class BancorService {
// Bancor recommends setting this value to 2% under the expected return amount
public minReturnAmountBufferPercentage = 0.99;
public static async createAsync(provider: SupportedProvider): Promise<BancorService> {
const sdk = await SDK.create({ ethereumNodeEndpoint: provider });
const service = new BancorService(sdk);
@@ -28,38 +19,16 @@ export class BancorService {
}
constructor(public sdk: SDK) {}
public async getQuotesAsync(
fromToken: string,
toToken: string,
amounts: BigNumber[],
): Promise<Array<Quote<BancorFillData>>> {
const sdk = this.sdk;
const blockchain = sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum;
const sourceDecimals = await getDecimals(blockchain, fromToken);
const quotes = await sdk.pricing.getPathAndRates(
token(fromToken),
token(toToken),
amounts.map(amt => fromWei(amt.toString(), sourceDecimals)),
);
const targetDecimals = await getDecimals(blockchain, toToken);
const networkAddress = this.getBancorNetworkAddress();
return quotes.map(quote => {
const { path, rate } = quote;
const output = toWei(rate, targetDecimals);
return {
amount: new BigNumber(output).multipliedBy(this.minReturnAmountBufferPercentage).dp(0),
fillData: {
path: path.map(p => p.blockchainId),
networkAddress,
},
};
});
}
public getBancorNetworkAddress(): string {
const blockchain = this.sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum;
return blockchain.bancorNetwork._address;
public getPaths(_fromToken: string, _toToken: string): string[][] {
// HACK: We reach into the blockchain object and pull in it's cache of tokens
// and we use it's internal non-async getPathsFunc
try {
const blockchain = this.sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum;
const fromToken = findToken(_fromToken, blockchain.graph);
const toToken = findToken(_toToken, blockchain.graph);
return blockchain.getPathsFunc.bind(blockchain)(fromToken, toToken);
} catch (e) {
return [];
}
}
}

View File

@@ -5,6 +5,7 @@ import { BridgeContractAddresses } from '../../types';
import { SourceFilters } from './source_filters';
import {
BancorFillData,
CurveFillData,
CurveFunctionSelectors,
CurveInfo,
@@ -34,8 +35,7 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
ERC20BridgeSource.Kyber,
ERC20BridgeSource.Curve,
ERC20BridgeSource.Balancer,
// Bancor is sampled off-chain, but this list should only include on-chain sources (used in ERC20BridgeSampler)
// ERC20BridgeSource.Bancor,
ERC20BridgeSource.Bancor,
ERC20BridgeSource.MStable,
ERC20BridgeSource.Mooniswap,
ERC20BridgeSource.Swerve,
@@ -60,7 +60,7 @@ export const BUY_SOURCE_FILTER = new SourceFilters([
ERC20BridgeSource.Kyber,
ERC20BridgeSource.Curve,
ERC20BridgeSource.Balancer,
// ERC20BridgeSource.Bancor, // FIXME: Disabled until Bancor SDK supports buy quotes
// ERC20BridgeSource.Bancor, // FIXME: Bancor Buys not implemented in Sampler
ERC20BridgeSource.MStable,
ERC20BridgeSource.Mooniswap,
ERC20BridgeSource.Shell,
@@ -105,36 +105,55 @@ export const TOKENS = {
HUSD: '0xdf574c24545e5ffecb9a659c229253d4111d87e1',
mUSD: '0xe2f2a5c287993345a840db3b0845fbc70f5935a5',
USDN: '0x674c6ad92fd080e4004b2312b45f796a192d27a0',
dUSD: '0x5bc25f649fc4e26069ddf4cf4010f9f706c23831',
UST: '0xa47c8bf37f92abed4a126bda807a7b7498661acd',
// Bitcoins
WBTC: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
RenBTC: '0xeb4c2781e4eba804ce9a9803c67d0893436bb27d',
sBTC: '0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6',
tBTC: '0x8daebade922df735c38c80c7ebd708af50815faa',
hBTC: '0x0316eb71485b0ab14103307bf65a021042c6d380',
pBTC: '0xde5331ac4b3630f94853ff322b66407e0d6331e8',
bBTC: '0x9be89d2a4cd102d8fecc6bf9da793be995c22541',
oBTC: '0x8064d9ae6cdf087b1bcd5bdf3531bd5d8c537a68',
// aTokens (Aave)
aDAI: '0x028171bca77440897b824ca71d1c56cac55b68a3',
aUSDC: '0xbcca60bb61934080951369a648fb03df4f96263c',
aUSDT: '0x3ed3b47dd13ec9a98b44e6204a523e766b225811',
// Other
MKR: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
EURS: '0xdb25f211ab05b1c97d595516f45794528a807ad8',
sEUR: '0xd71ecff9342a5ced620049e616c5035f1db98620',
sETH: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
};
export const POOLS = {
// following the same order in curve.fi:
curve_compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56',
// curve_USDT: '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c',
curve_PAX: '0x06364f10b501e868329afbc005b3492902d6c763',
curve_y: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51',
curve_BUSD: '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27',
curve_sUSD: '0xa5407eae9ba41422680e2e00537571bcc53efbfd',
curve_renBTC: '0x93054188d876f558f4a66b2ef1d97d16edf0895b',
curve_sBTC: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714',
curve_HBTC: '0x4ca9b3063ec5866a4b82e437059d2c43d1be596f',
curve_TRI: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7',
curve_GUSD: '0x4f062658eaaf2c1ccf8c8e36d6824cdf41167956',
curve_HUSD: '0x3ef6a01a0f81d6046290f3e2a8c5b843e738e604',
curve_compound: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56', // 0.Compound
// 1.USDT is dead
curve_PAX: '0x06364f10b501e868329afbc005b3492902d6c763', // 2.PAX
curve_y: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51', // 3.Y
curve_BUSD: '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27', // 4.BUSD
curve_sUSD: '0xa5407eae9ba41422680e2e00537571bcc53efbfd', // 5.sUSD
curve_renBTC: '0x93054188d876f558f4a66b2ef1d97d16edf0895b', // 6.ren
curve_sBTC: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714', // 7.sbtc
curve_HBTC: '0x4ca9b3063ec5866a4b82e437059d2c43d1be596f', // 8.hbtc
curve_TRI: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7', // 9.3pool
curve_GUSD: '0x4f062658eaaf2c1ccf8c8e36d6824cdf41167956', // 10.gusd
curve_HUSD: '0x3ef6a01a0f81d6046290f3e2a8c5b843e738e604', // 11.husd
// 12.usdk is dead
curve_USDN: '0x0f9cb53ebe405d49a0bbdbd291a65ff571bc83e1',
curve_USDN: '0x0f9cb53ebe405d49a0bbdbd291a65ff571bc83e1', // 13.usdn
// 14.linkusd is dead
curve_mUSD: '0x8474ddbe98f5aa3179b3b3f5942d724afcdec9f6',
curve_mUSD: '0x8474ddbe98f5aa3179b3b3f5942d724afcdec9f6', // 15.musd
// 16.rsv is dead
curve_tBTC: '0xc25099792e9349c7dd09759744ea681c7de2cb66',
curve_tBTC: '0xc25099792e9349c7dd09759744ea681c7de2cb66', // 17.tbtc
curve_dUSD: '0x8038c01a0390a8c547446a0b2c18fc9aefecc10c', // 18.dusd
curve_pBTC: '0x5228a22e72ccc52d415ecfd199f99d0665e7733b', // 19.pbtc
curve_bBTC: '0x071c661b4deefb59e2a3ddb20db036821eee8f4b', // 20.bbtc
curve_oBTC: '0xd81da8d904b52208541bade1bd6595d8a251f8dd', // 21.obtc
curve_UST: '0x890f4e345b1daed0367a877a1612f86a1f86985f', // 22.ust
curve_eurs: '0x0ce6a5ff5217e38315f87032cf90686c96627caa', // 23.eurs
// curve_seth: '0xc5424b857f758e906013f3555dad202e4bdb4567', // 24.seth
curve_aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave
};
/**
@@ -151,17 +170,6 @@ export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
tokens: [TOKENS.DAI, TOKENS.USDC],
metaToken: undefined,
},
// USDT: {
// exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
// sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
// buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
// poolAddress: '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c',
// tokens: [
// TOKENS.DAI,
// TOKENS.USDC,
// TOKENS.USDT,
// ],
// },
[POOLS.curve_PAX]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
@@ -226,7 +234,6 @@ export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: undefined,
},
// Metapools
[POOLS.curve_GUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
@@ -267,6 +274,78 @@ export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
tokens: [TOKENS.tBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
metaToken: TOKENS.tBTC,
},
[POOLS.curve_dUSD]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_dUSD,
tokens: [TOKENS.dUSD, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: TOKENS.dUSD,
},
[POOLS.curve_pBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_pBTC,
tokens: [TOKENS.pBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
metaToken: TOKENS.pBTC,
},
[POOLS.curve_bBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_bBTC,
tokens: [TOKENS.bBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
metaToken: TOKENS.bBTC,
},
[POOLS.curve_oBTC]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_oBTC,
tokens: [TOKENS.oBTC, TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
metaToken: TOKENS.oBTC,
},
[POOLS.curve_UST]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_UST,
tokens: [TOKENS.UST, TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: TOKENS.UST,
},
[POOLS.curve_eurs]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_eurs,
tokens: [TOKENS.EURS, TOKENS.sEUR],
metaToken: undefined,
},
// [POOLS.curve_seth]: {
// exchangeFunctionSelector: CurveFunctionSelectors.exchange,
// sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
// buyQuoteFunctionSelector: CurveFunctionSelectors.None,
// poolAddress: POOLS.curve_seth,
// tokens: [TOKENS.ETH, TOKENS.sETH],
// metaToken: undefined,
// },
[POOLS.curve_aave]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_aave,
tokens: [TOKENS.DAI, TOKENS.USDC, TOKENS.USDT],
metaToken: undefined,
},
[POOLS.curve_aave]: {
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
poolAddress: POOLS.curve_aave,
tokens: [TOKENS.aDAI, TOKENS.aUSDC, TOKENS.aUSDT],
metaToken: undefined,
},
};
export const MAINNET_SWERVE_INFOS: { [name: string]: CurveInfo } = {
@@ -357,13 +436,16 @@ export const LIQUIDITY_PROVIDER_REGISTRY: LiquidityProviderRegistry = {};
export const MAINNET_SUSHI_SWAP_ROUTER = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
export const MAINNET_CRYPTO_COM_ROUTER = '0xCeB90E4C17d626BE0fACd78b79c9c87d7ca181b3';
export const MAINNET_MOONISWAP_REGISTRY = '0x71CD6666064C3A1354a3B4dca5fA1E2D3ee7D303';
export const MAINNET_MOONISWAP_V2_REGISTRY = '0xc4a8b7e29e3c8ec560cd4945c1cf3461a85a148d';
export const MAINNET_SHELL_POOLS = {
StableCoins: {
poolAddress: '0x2E703D658f8dd21709a7B458967aB4081F8D3d05',
poolAddress: '0x8f26d7bab7a73309141a291525c965ecdea7bf42',
tokens: [TOKENS.USDC, TOKENS.USDT, TOKENS.sUSD, TOKENS.DAI],
},
Bitcoin: {
poolAddress: '0x02Af7C867d6Ddd2c87dEcec2E4AFF809ee118FBb',
poolAddress: '0xc2d019b901f8d4fdb2b9a65b5d226ad88c66ee8d',
tokens: [TOKENS.RenBTC, TOKENS.WBTC, TOKENS.sBTC],
},
};
@@ -410,7 +492,7 @@ export const BRIDGE_ADDRESSES_BY_CHAIN: { [chainId in ChainId]: BridgeContractAd
curveBridge: '0x1796cd592d19e3bcd744fbb025bb61a6d8cb2c09',
multiBridge: '0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1',
balancerBridge: '0xfe01821ca163844203220cd08e4f2b2fb43ae4e4',
bancorBridge: '0x259897d9699553edbdf8538599242354e957fb94',
bancorBridge: '0xc880c252db7c51f74161633338a3bdafa8e65276',
mStableBridge: '0x2bf04fcea05f0989a14d9afa37aa376baca6b2b3',
mooniswapBridge: '0x02b7eca484ad960fca3f7709e0b2ac81eec3069c',
sushiswapBridge: '0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5',
@@ -460,13 +542,6 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
case POOLS.curve_HBTC:
case POOLS.curve_TRI:
return 150e3;
case POOLS.curve_compound:
return 750e3;
case POOLS.curve_PAX:
case POOLS.curve_y:
case POOLS.curve_BUSD:
return 850e3;
// Metapools
case POOLS.curve_USDN:
case POOLS.curve_mUSD:
return 300e3;
@@ -475,6 +550,22 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
return 310e3;
case POOLS.curve_tBTC:
return 370e3;
case POOLS.curve_UST:
return 500e3;
case POOLS.curve_dUSD:
case POOLS.curve_bBTC:
case POOLS.curve_oBTC:
case POOLS.curve_eurs:
return 600e3;
case POOLS.curve_compound:
return 750e3;
case POOLS.curve_aave:
return 800e3;
case POOLS.curve_PAX:
case POOLS.curve_y:
case POOLS.curve_BUSD:
return 850e3;
// case POOLS.curve_seth:
default:
throw new Error(`Unrecognized Curve address: ${poolAddress}`);
}
@@ -539,7 +630,14 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
throw new Error('Unrecognized SnowSwap address');
}
},
[ERC20BridgeSource.Bancor]: () => 300e3,
[ERC20BridgeSource.Bancor]: (fillData?: FillData) => {
let gas = 200e3;
const path = (fillData as BancorFillData).path;
if (path.length > 2) {
gas += (path.length - 2) * 60e3; // +60k for each hop.
}
return gas;
},
};
export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = Object.assign(

View File

@@ -81,13 +81,12 @@ export class MarketOperationUtils {
private readonly _feeSources = new SourceFilters(FEE_QUOTE_SOURCES);
private static _computeQuoteReport(
nativeOrders: SignedOrder[],
quoteRequestor: QuoteRequestor | undefined,
marketSideLiquidity: MarketSideLiquidity,
optimizerResult: OptimizerResult,
comparisonPrice?: BigNumber | undefined,
): QuoteReport {
const { side, dexQuotes, twoHopQuotes, orderFillableAmounts } = marketSideLiquidity;
const { side, dexQuotes, twoHopQuotes, orderFillableAmounts, nativeOrders } = marketSideLiquidity;
const { liquidityDelivered } = optimizerResult;
return generateQuoteReport(
side,
@@ -204,23 +203,12 @@ export class MarketOperationUtils {
? this._sampler.getCreamSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
: Promise.resolve([]);
const offChainBancorPromise = quoteSourceFilters.isAllowed(ERC20BridgeSource.Bancor)
? this._sampler.getBancorSellQuotesOffChainAsync(makerToken, takerToken, [takerAmount])
: Promise.resolve([]);
const [
[tokenDecimals, orderFillableAmounts, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes, twoHopQuotes],
rfqtIndicativeQuotes,
offChainBalancerQuotes,
offChainCreamQuotes,
offChainBancorQuotes,
] = await Promise.all([
samplerPromise,
rfqtPromise,
offChainBalancerPromise,
offChainCreamPromise,
offChainBancorPromise,
]);
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise]);
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
return {
@@ -228,7 +216,7 @@ export class MarketOperationUtils {
inputAmount: takerAmount,
inputToken: takerToken,
outputToken: makerToken,
dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, ...offChainCreamQuotes, offChainBancorQuotes]),
dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, ...offChainCreamQuotes]),
nativeOrders,
orderFillableAmounts,
ethToOutputRate: ethToMakerAssetRate,
@@ -630,7 +618,7 @@ export class MarketOperationUtils {
side === MarketOperation.Sell
? this.getMarketSellLiquidityAsync.bind(this)
: this.getMarketBuyLiquidityAsync.bind(this);
const marketSideLiquidity: MarketSideLiquidity = await marketLiquidityFnAsync(nativeOrders, amount, _opts);
let marketSideLiquidity: MarketSideLiquidity = await marketLiquidityFnAsync(nativeOrders, amount, _opts);
let optimizerResult: OptimizerResult | undefined;
try {
optimizerResult = await this._generateOptimizedOrdersAsync(marketSideLiquidity, optimizerOpts);
@@ -673,13 +661,11 @@ export class MarketOperationUtils {
);
// Re-run optimizer with the new indicative quote
if (indicativeQuotes.length > 0) {
optimizerResult = await this._generateOptimizedOrdersAsync(
{
...marketSideLiquidity,
rfqtIndicativeQuotes: indicativeQuotes,
},
optimizerOpts,
);
marketSideLiquidity = {
...marketSideLiquidity,
rfqtIndicativeQuotes: indicativeQuotes,
};
optimizerResult = await this._generateOptimizedOrdersAsync(marketSideLiquidity, optimizerOpts);
}
} else if (!rfqt.isIndicative && isFirmPriceAwareEnabled) {
// A firm quote is being requested, and firm quotes price-aware enabled. Ensure that `intentOnFilling` is enabled.
@@ -707,19 +693,18 @@ export class MarketOperationUtils {
? firmQuoteSignedOrders.map(signedOrder => signedOrder.takerAssetAmount)
: await rfqt.firmQuoteValidator.getRfqtTakerFillableAmountsAsync(firmQuoteSignedOrders);
marketSideLiquidity = {
...marketSideLiquidity,
nativeOrders: marketSideLiquidity.nativeOrders.concat(firmQuoteSignedOrders),
orderFillableAmounts: marketSideLiquidity.orderFillableAmounts.concat(
rfqOrderFillableAmounts,
),
};
// Re-run optimizer with the new firm quote. This is the second and last time
// we run the optimized in a block of code. In this case, we don't catch a potential `NoOptimalPath` exception
// and we let it bubble up if it happens.
optimizerResult = await this._generateOptimizedOrdersAsync(
{
...marketSideLiquidity,
nativeOrders: marketSideLiquidity.nativeOrders.concat(firmQuoteSignedOrders),
orderFillableAmounts: marketSideLiquidity.orderFillableAmounts.concat(
rfqOrderFillableAmounts,
),
},
optimizerOpts,
);
optimizerResult = await this._generateOptimizedOrdersAsync(marketSideLiquidity, optimizerOpts);
}
}
}
@@ -735,7 +720,6 @@ export class MarketOperationUtils {
let quoteReport: QuoteReport | undefined;
if (_opts.shouldGenerateQuoteReport) {
quoteReport = MarketOperationUtils._computeQuoteReport(
nativeOrders,
_opts.rfqt ? _opts.rfqt.quoteRequestor : undefined,
marketSideLiquidity,
optimizerResult,

View File

@@ -1,4 +1,3 @@
import { SupportedProvider } from '@0x/dev-utils';
import { BigNumber, NULL_BYTES } from '@0x/utils';
import { SamplerOverrides } from '../../types';
@@ -36,21 +35,19 @@ export class DexOrderSampler extends SamplerOperations {
constructor(
_samplerContract: ERC20BridgeSamplerContract,
private readonly _samplerOverrides?: SamplerOverrides,
provider?: SupportedProvider,
balancerPoolsCache?: BalancerPoolsCache,
creamPoolsCache?: CreamPoolsCache,
getBancorServiceFn?: () => BancorService,
tokenAdjacencyGraph?: TokenAdjacencyGraph,
liquidityProviderRegistry?: LiquidityProviderRegistry,
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
) {
super(
_samplerContract,
provider,
balancerPoolsCache,
creamPoolsCache,
getBancorServiceFn,
tokenAdjacencyGraph,
liquidityProviderRegistry,
bancorServiceFn,
);
}

View File

@@ -1,4 +1,3 @@
import { SupportedProvider } from '@0x/dev-utils';
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
@@ -10,6 +9,8 @@ import { BancorService } from './bancor_service';
import {
LIQUIDITY_PROVIDER_REGISTRY,
MAINNET_CRYPTO_COM_ROUTER,
MAINNET_MOONISWAP_REGISTRY,
MAINNET_MOONISWAP_V2_REGISTRY,
MAINNET_SUSHI_SWAP_ROUTER,
MAX_UINT256,
ZERO_AMOUNT,
@@ -81,25 +82,16 @@ export class SamplerOperations {
constructor(
protected readonly _samplerContract: ERC20BridgeSamplerContract,
public readonly provider?: SupportedProvider,
public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(),
public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(),
protected readonly getBancorServiceFn?: () => BancorService, // for dependency injection in tests
protected readonly tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [] },
public readonly liquidityProviderRegistry: LiquidityProviderRegistry = LIQUIDITY_PROVIDER_REGISTRY,
) {}
public async getBancorServiceAsync(): Promise<BancorService> {
if (this.getBancorServiceFn !== undefined) {
return this.getBancorServiceFn();
}
if (this.provider === undefined) {
throw new Error('Cannot sample liquidity from Bancor; no provider supplied.');
}
if (this._bancorService === undefined) {
this._bancorService = await BancorService.createAsync(this.provider);
}
return this._bancorService;
bancorServiceFn: () => Promise<BancorService | undefined> = async () => undefined,
) {
// Initialize the Bancor service, fetching paths in the background
bancorServiceFn()
.then(service => (this._bancorService = service))
.catch(/* do nothing */);
}
public getTokenDecimals(makerTokenAddress: string, takerTokenAddress: string): BatchedOperation<BigNumber[]> {
@@ -588,31 +580,52 @@ export class SamplerOperations {
});
}
public async getBancorSellQuotesOffChainAsync(
public getBancorSellQuotes(
makerToken: string,
takerToken: string,
takerFillAmounts: BigNumber[],
): Promise<Array<DexSample<BancorFillData>>> {
const bancorService = await this.getBancorServiceAsync();
try {
const quotes = await bancorService.getQuotesAsync(takerToken, makerToken, takerFillAmounts);
return quotes.map((quote, i) => ({
source: ERC20BridgeSource.Bancor,
output: quote.amount,
input: takerFillAmounts[i],
fillData: quote.fillData,
}));
} catch (e) {
return takerFillAmounts.map(input => ({
source: ERC20BridgeSource.Bancor,
output: ZERO_AMOUNT,
input,
fillData: { path: [], networkAddress: '' },
}));
}
): SourceQuoteOperation<BancorFillData> {
const paths = this._bancorService ? this._bancorService.getPaths(takerToken, makerToken) : [];
return new SamplerContractOperation({
source: ERC20BridgeSource.Bancor,
contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromBancor,
params: [paths, takerToken, makerToken, takerFillAmounts],
callback: (callResults: string, fillData: BancorFillData): BigNumber[] => {
const [networkAddress, path, samples] = this._samplerContract.getABIDecodedReturnData<
[string, string[], BigNumber[]]
>('sampleSellsFromBancor', callResults);
fillData.networkAddress = networkAddress;
fillData.path = path;
return samples;
},
});
}
// Unimplemented
public getBancorBuyQuotes(
makerToken: string,
takerToken: string,
makerFillAmounts: BigNumber[],
): SourceQuoteOperation<BancorFillData> {
return new SamplerContractOperation({
source: ERC20BridgeSource.Bancor,
contract: this._samplerContract,
function: this._samplerContract.sampleBuysFromBancor,
params: [[], takerToken, makerToken, makerFillAmounts],
callback: (callResults: string, fillData: BancorFillData): BigNumber[] => {
const [networkAddress, path, samples] = this._samplerContract.getABIDecodedReturnData<
[string, string[], BigNumber[]]
>('sampleSellsFromBancor', callResults);
fillData.networkAddress = networkAddress;
fillData.path = path;
return samples;
},
});
}
public getMooniswapSellQuotes(
registry: string,
makerToken: string,
takerToken: string,
takerFillAmounts: BigNumber[],
@@ -621,7 +634,7 @@ export class SamplerOperations {
source: ERC20BridgeSource.Mooniswap,
contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromMooniswap,
params: [takerToken, makerToken, takerFillAmounts],
params: [registry, takerToken, makerToken, takerFillAmounts],
callback: (callResults: string, fillData: MooniswapFillData): BigNumber[] => {
const [poolAddress, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
'sampleSellsFromMooniswap',
@@ -634,6 +647,7 @@ export class SamplerOperations {
}
public getMooniswapBuyQuotes(
registry: string,
makerToken: string,
takerToken: string,
makerFillAmounts: BigNumber[],
@@ -642,7 +656,7 @@ export class SamplerOperations {
source: ERC20BridgeSource.Mooniswap,
contract: this._samplerContract,
function: this._samplerContract.sampleBuysFromMooniswap,
params: [takerToken, makerToken, makerFillAmounts],
params: [registry, takerToken, makerToken, makerFillAmounts],
callback: (callResults: string, fillData: MooniswapFillData): BigNumber[] => {
const [poolAddress, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
'sampleBuysFromMooniswap',
@@ -1083,7 +1097,20 @@ export class SamplerOperations {
case ERC20BridgeSource.MStable:
return this.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts);
case ERC20BridgeSource.Mooniswap:
return this.getMooniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
return [
this.getMooniswapSellQuotes(
MAINNET_MOONISWAP_REGISTRY,
makerToken,
takerToken,
takerFillAmounts,
),
this.getMooniswapSellQuotes(
MAINNET_MOONISWAP_V2_REGISTRY,
makerToken,
takerToken,
takerFillAmounts,
),
];
case ERC20BridgeSource.Balancer:
return this.balancerPoolsCache
.getCachedPoolAddressesForPair(takerToken, makerToken)!
@@ -1114,6 +1141,8 @@ export class SamplerOperations {
);
case ERC20BridgeSource.Dodo:
return this.getDODOSellQuotes(makerToken, takerToken, takerFillAmounts);
case ERC20BridgeSource.Bancor:
return this.getBancorSellQuotes(makerToken, takerToken, takerFillAmounts);
default:
throw new Error(`Unsupported sell sample source: ${source}`);
}
@@ -1206,7 +1235,20 @@ export class SamplerOperations {
case ERC20BridgeSource.MStable:
return this.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts);
case ERC20BridgeSource.Mooniswap:
return this.getMooniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
return [
this.getMooniswapBuyQuotes(
MAINNET_MOONISWAP_REGISTRY,
makerToken,
takerToken,
makerFillAmounts,
),
this.getMooniswapBuyQuotes(
MAINNET_MOONISWAP_V2_REGISTRY,
makerToken,
takerToken,
makerFillAmounts,
),
];
case ERC20BridgeSource.Balancer:
return this.balancerPoolsCache
.getCachedPoolAddressesForPair(takerToken, makerToken)!
@@ -1237,6 +1279,8 @@ export class SamplerOperations {
);
case ERC20BridgeSource.Dodo:
return this.getDODOBuyQuotes(makerToken, takerToken, makerFillAmounts);
case ERC20BridgeSource.Bancor:
return this.getBancorBuyQuotes(makerToken, takerToken, makerFillAmounts);
default:
throw new Error(`Unsupported buy sample source: ${source}`);
}

View File

@@ -8,6 +8,7 @@ import { ContractArtifact } from 'ethereum-types';
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
import * as BalanceChecker from '../test/generated-artifacts/BalanceChecker.json';
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
import * as BancorSampler from '../test/generated-artifacts/BancorSampler.json';
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
@@ -15,6 +16,7 @@ import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquid
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
import * as IBalancer from '../test/generated-artifacts/IBalancer.json';
import * as IBancor from '../test/generated-artifacts/IBancor.json';
import * as ICurve from '../test/generated-artifacts/ICurve.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
@@ -42,6 +44,7 @@ export const artifacts = {
ApproximateBuys: ApproximateBuys as ContractArtifact,
BalanceChecker: BalanceChecker as ContractArtifact,
BalancerSampler: BalancerSampler as ContractArtifact,
BancorSampler: BancorSampler as ContractArtifact,
CurveSampler: CurveSampler as ContractArtifact,
DODOSampler: DODOSampler as ContractArtifact,
DeploymentConstants: DeploymentConstants as ContractArtifact,
@@ -60,6 +63,7 @@ export const artifacts = {
UniswapSampler: UniswapSampler as ContractArtifact,
UniswapV2Sampler: UniswapV2Sampler as ContractArtifact,
IBalancer: IBalancer as ContractArtifact,
IBancor: IBancor as ContractArtifact,
ICurve: ICurve as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetwork: IKyberNetwork as ContractArtifact,

View File

@@ -1,72 +0,0 @@
import { web3Factory, Web3ProviderEngine } from '@0x/dev-utils';
import { Ethereum, getDecimals } from '@bancor/sdk/dist/blockchains/ethereum';
import { fromWei, toWei } from '@bancor/sdk/dist/helpers';
import { BlockchainType } from '@bancor/sdk/dist/types';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import { BancorFillData, BigNumber } from '../src';
import { BancorService, token } from '../src/utils/market_operation_utils/bancor_service';
import { chaiSetup } from './utils/chai_setup';
chaiSetup.configure();
const expect = chai.expect;
const ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i;
const RPC_URL = `https://mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`;
const provider: Web3ProviderEngine = web3Factory.getRpcProvider({ rpcUrl: RPC_URL });
// tslint:disable:custom-no-magic-numbers
let bancorService: BancorService;
// These tests test the bancor SDK against mainnet
// TODO (xianny): After we move asset-swapper out of the monorepo, we should add an env variable to circle CI to run this test
describe.skip('Bancor Service', () => {
const eth = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
const bnt = '0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c';
it('should retrieve the bancor network address', async () => {
bancorService = await BancorService.createAsync(provider);
const networkAddress = bancorService.getBancorNetworkAddress();
expect(networkAddress).to.match(ADDRESS_REGEX);
});
it('should retrieve a quote', async () => {
const amt = new BigNumber(10e18);
const quotes = await bancorService.getQuotesAsync(eth, bnt, [amt]);
const fillData = quotes[0].fillData as BancorFillData;
// get rate from the bancor sdk
const blockchain = bancorService.sdk._core.blockchains[BlockchainType.Ethereum] as Ethereum;
const sourceDecimals = await getDecimals(blockchain, token(eth));
const rate = await bancorService.sdk.pricing.getRateByPath(
fillData.path.map(p => token(p)),
fromWei(amt.toString(), sourceDecimals),
);
const expectedRate = toWei(rate, await getDecimals(blockchain, token(bnt)));
expect(fillData.networkAddress).to.match(ADDRESS_REGEX);
expect(fillData.path[0].toLowerCase()).to.eq(eth);
expect(fillData.path[2].toLowerCase()).to.eq(bnt);
expect(fillData.path.length).to.eq(3); // eth -> bnt should be single hop!
expect(quotes[0].amount.dp(0)).to.bignumber.eq(
new BigNumber(expectedRate).multipliedBy(bancorService.minReturnAmountBufferPercentage).dp(0),
);
});
// HACK (xianny): for exploring SDK results
it('should retrieve multiple quotes', async () => {
const amts = [1, 10, 100, 1000].map(a => new BigNumber(a).multipliedBy(10e18));
const quotes = await bancorService.getQuotesAsync(eth, bnt, amts);
quotes.map((q, i) => {
// tslint:disable:no-console
const fillData = q.fillData as BancorFillData;
console.log(
`Input ${amts[i].toExponential()}; Output: ${q.amount}; Ratio: ${q.amount.dividedBy(amts[i])}, Path: ${
fillData.path.length
}\nPath: ${JSON.stringify(fillData.path)}`,
);
// tslint:enable:no-console
});
});
});

View File

@@ -17,9 +17,7 @@ import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation
import { ERC20BridgeSource, TokenAdjacencyGraph } from '../src/utils/market_operation_utils/types';
import { MockBalancerPoolsCache } from './utils/mock_balancer_pools_cache';
import { MockBancorService } from './utils/mock_bancor_service';
import { MockSamplerContract } from './utils/mock_sampler_contract';
import { provider } from './utils/web3_wrapper';
const CHAIN_ID = 1;
// tslint:disable: custom-no-magic-numbers
@@ -104,7 +102,15 @@ describe('DexSampler tests', () => {
return expectedFillableAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getOrderFillableMakerAmounts(ORDERS, exchangeAddress),
);
@@ -120,7 +126,15 @@ describe('DexSampler tests', () => {
return expectedFillableAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getOrderFillableTakerAmounts(ORDERS, exchangeAddress),
);
@@ -140,7 +154,15 @@ describe('DexSampler tests', () => {
return ['0x', expectedMakerFillAmounts];
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getKyberSellQuotes(
'0x',
@@ -171,9 +193,10 @@ describe('DexSampler tests', () => {
undefined,
undefined,
undefined,
undefined,
undefined,
{ [poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost } },
{
[poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost },
},
async () => undefined,
);
const [result] = await dexOrderSampler.executeAsync(
dexOrderSampler.getSellQuotes(
@@ -214,9 +237,10 @@ describe('DexSampler tests', () => {
undefined,
undefined,
undefined,
undefined,
undefined,
{ [poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost } },
{
[poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost },
},
async () => undefined,
);
const [result] = await dexOrderSampler.executeAsync(
dexOrderSampler.getBuyQuotes(
@@ -251,7 +275,15 @@ describe('DexSampler tests', () => {
return expectedMakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getEth2DaiSellQuotes(expectedMakerToken, expectedTakerToken, expectedTakerFillAmounts),
);
@@ -271,7 +303,15 @@ describe('DexSampler tests', () => {
return expectedMakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getUniswapSellQuotes(expectedMakerToken, expectedTakerToken, expectedTakerFillAmounts),
);
@@ -290,7 +330,15 @@ describe('DexSampler tests', () => {
return expectedMakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getUniswapV2SellQuotes(
[expectedMakerToken, expectedTakerToken],
@@ -313,7 +361,15 @@ describe('DexSampler tests', () => {
return expectedTakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getEth2DaiBuyQuotes(expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts),
);
@@ -333,7 +389,15 @@ describe('DexSampler tests', () => {
return expectedTakerFillAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getUniswapBuyQuotes(expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts),
);
@@ -385,9 +449,9 @@ describe('DexSampler tests', () => {
undefined,
undefined,
undefined,
undefined,
undefined,
tokenAdjacencyGraph,
undefined,
async () => undefined,
);
const [quotes] = await dexOrderSampler.executeAsync(
dexOrderSampler.getSellQuotes(
@@ -441,8 +505,11 @@ describe('DexSampler tests', () => {
const dexOrderSampler = new DexOrderSampler(
new MockSamplerContract({}),
undefined,
undefined,
balancerPoolsCache,
undefined,
undefined,
undefined,
async () => undefined,
);
const quotes = await dexOrderSampler.getBalancerSellQuotesOffChainAsync(
expectedMakerToken,
@@ -451,45 +518,6 @@ describe('DexSampler tests', () => {
);
expect(quotes).to.have.lengthOf(0);
});
it('getSellQuotes() uses samples from Bancor', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
const networkAddress = randomAddress();
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
const rate = getRandomFloat(0, 100);
const bancorService = await MockBancorService.createMockAsync({
getQuotesAsync: async (fromToken: string, toToken: string, amounts: BigNumber[]) => {
expect(fromToken).equal(expectedTakerToken);
expect(toToken).equal(expectedMakerToken);
return Promise.resolve(
amounts.map(a => ({
fillData: { path: [fromToken, toToken], networkAddress },
amount: a.multipliedBy(rate),
})),
);
},
});
const dexOrderSampler = new DexOrderSampler(
new MockSamplerContract({}),
undefined, // sampler overrides
provider,
undefined, // balancer cache
undefined, // cream cache
() => bancorService,
);
const quotes = await dexOrderSampler.getBancorSellQuotesOffChainAsync(
expectedMakerToken,
expectedTakerToken,
expectedTakerFillAmounts,
);
const expectedQuotes = expectedTakerFillAmounts.map(a => ({
source: ERC20BridgeSource.Bancor,
input: a,
output: a.multipliedBy(rate),
fillData: { path: [expectedTakerToken, expectedMakerToken], networkAddress },
}));
expect(quotes).to.deep.eq(expectedQuotes);
});
it('getBuyQuotes()', async () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
@@ -530,9 +558,9 @@ describe('DexSampler tests', () => {
undefined,
undefined,
undefined,
undefined,
undefined,
tokenAdjacencyGraph,
undefined,
async () => undefined,
);
const [quotes] = await dexOrderSampler.executeAsync(
dexOrderSampler.getBuyQuotes(sources, expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts),
@@ -577,8 +605,11 @@ describe('DexSampler tests', () => {
const dexOrderSampler = new DexOrderSampler(
new MockSamplerContract({}),
undefined,
undefined,
balancerPoolsCache,
undefined,
undefined,
undefined,
async () => undefined,
);
const quotes = await dexOrderSampler.getBalancerBuyQuotesOffChainAsync(
expectedMakerToken,
@@ -605,7 +636,15 @@ describe('DexSampler tests', () => {
return expectedFillableTakerAmounts;
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const dexOrderSampler = new DexOrderSampler(
sampler,
undefined,
undefined,
undefined,
undefined,
undefined,
async () => undefined,
);
const [fillableMakerAmounts, fillableTakerAmounts] = await dexOrderSampler.executeAsync(
dexOrderSampler.getOrderFillableMakerAmounts(ORDERS, exchangeAddress),
dexOrderSampler.getOrderFillableTakerAmounts(ORDERS, exchangeAddress),

View File

@@ -1,33 +0,0 @@
import { BigNumber } from '@0x/utils';
import { SDK } from '@bancor/sdk';
import { BancorService } from '../../src/utils/market_operation_utils/bancor_service';
import { BancorFillData, Quote } from '../../src/utils/market_operation_utils/types';
export interface Handlers {
getQuotesAsync: (fromToken: string, toToken: string, amount: BigNumber[]) => Promise<Array<Quote<BancorFillData>>>;
}
export class MockBancorService extends BancorService {
// Bancor recommends setting this value to 2% under the expected return amount
public minReturnAmountBufferPercentage = 0.98;
public static async createMockAsync(handlers: Partial<Handlers>): Promise<MockBancorService> {
const sdk = new SDK();
return new MockBancorService(sdk, handlers);
}
constructor(sdk: SDK, public handlers: Partial<Handlers>) {
super(sdk);
}
public async getQuotesAsync(
fromToken: string,
toToken: string,
amounts: BigNumber[],
): Promise<Array<Quote<BancorFillData>>> {
return this.handlers.getQuotesAsync
? this.handlers.getQuotesAsync(fromToken, toToken, amounts)
: super.getQuotesAsync(fromToken, toToken, amounts);
}
}

View File

@@ -6,6 +6,7 @@
export * from '../test/generated-wrappers/approximate_buys';
export * from '../test/generated-wrappers/balance_checker';
export * from '../test/generated-wrappers/balancer_sampler';
export * from '../test/generated-wrappers/bancor_sampler';
export * from '../test/generated-wrappers/curve_sampler';
export * from '../test/generated-wrappers/d_o_d_o_sampler';
export * from '../test/generated-wrappers/deployment_constants';
@@ -13,6 +14,7 @@ export * from '../test/generated-wrappers/dummy_liquidity_provider';
export * from '../test/generated-wrappers/erc20_bridge_sampler';
export * from '../test/generated-wrappers/eth2_dai_sampler';
export * from '../test/generated-wrappers/i_balancer';
export * from '../test/generated-wrappers/i_bancor';
export * from '../test/generated-wrappers/i_curve';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_network';

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