feat: mStable + FQT Rollup (#2662)
* feat: mStable * deploy and CHANGELOG * `@0x/contracts-utils`: Add more testnet addresses. * `@0x/contract-addresses`: Deply Mstable on testnets * `@0x/contract-addresses`: Remove testnet deployments of mStable :-) * move `erc20-bridge-sampler` into `asset-swapper` remove `DevUtils` dependency from sampler contract. * `@0x/asset-swapper`: Add ERC20BridgeSampler support for validating orders in maker fees denominated in non-maker assets. `@0x/asset-swapper`: Add tests for `NativeOrderSampler`. * `@0x/asset-swapper`: Return `0` sample if native order asset data is unsupported. * `@0x/asset-swapper`: Fix failing test. * feat: ExchangeProxy FQT fruit rollup (#2645) * feat: Optimize Bridges in ExchangeProxy * compile and most work * work around to trust the delecall contract * force allowances * Update Kyber/Eth2Dai bridges * Remove memory state where not required * cleanup * Combine Bridges into one adapter * mixins * refactor out ZeroExBridge * move out interface * comment out hacks * update migrations * remove simbot hacks * AdapterAddresses and mStable * Share constructor arg * fix migration * Remove whitespace * `@0x/contracts-zero-ex`: BridgeAdapter -- revert if bridge address is 0. * `@0x/contract-addresses`: Deploy FQT. Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: Lawrence Forman <lawrence@0xproject.com> * update ganache contract addresses * fix: asset-swapper empty batch call (#2669) * update ganache contract addresses * fix: asset-swapper prevent empty sampler batch call * add sampler to migrations * change migrations version * Use contract-wrappers and artifacts * remove extra data * remove deps, set sampler to NULL_ADDRESS * all the exports * noop sell rate too * update ganache contract addresses Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
This commit is contained in:
parent
458a014e6d
commit
7e8b56eef4
@ -40,10 +40,6 @@ lib
|
||||
/contracts/erc20/test/generated-wrappers
|
||||
/contracts/erc20/generated-artifacts
|
||||
/contracts/erc20/test/generated-artifacts
|
||||
/contracts/erc20-bridge-sampler/generated-wrappers
|
||||
/contracts/erc20-bridge-sampler/test/generated-wrappers
|
||||
/contracts/erc20-bridge-sampler/generated-artifacts
|
||||
/contracts/erc20-bridge-sampler/test/generated-artifacts
|
||||
/contracts/erc721/generated-wrappers
|
||||
/contracts/erc721/test/generated-wrappers
|
||||
/contracts/erc721/generated-artifacts
|
||||
@ -85,6 +81,10 @@ lib
|
||||
/packages/json-schemas/schemas
|
||||
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
|
||||
/packages/sra-spec/public/
|
||||
/packages/asset-swapper/generated-wrappers
|
||||
/packages/asset-swapper/test/generated-wrappers
|
||||
/packages/asset-swapper/generated-artifacts
|
||||
/packages/asset-swapper/test/generated-artifacts
|
||||
package.json
|
||||
scripts/postpublish_utils.js
|
||||
packages/sol-coverage/test/fixtures/artifacts
|
||||
|
@ -9,6 +9,10 @@
|
||||
{
|
||||
"note": "Export DexForwarderBridgeContract",
|
||||
"pr": 2656
|
||||
},
|
||||
{
|
||||
"note": "Added `MStableBridge`",
|
||||
"pr": 2662
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "../interfaces/IERC20Bridge.sol";
|
||||
import "../interfaces/IMStable.sol";
|
||||
|
||||
|
||||
contract MStableBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
/// @dev Swaps specified tokens against the mStable mUSD contract
|
||||
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
|
||||
/// @param from The maker (this contract).
|
||||
/// @param to The recipient of the bought tokens.
|
||||
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
|
||||
/// @param bridgeData The abi-encoded "from" token address.
|
||||
/// @return success The magic bytes if successful.
|
||||
// solhint-disable no-unused-vars
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
IMStable exchange = IMStable(_getMUsdAddress());
|
||||
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
|
||||
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
uint256 boughtAmount = exchange.swap(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
to
|
||||
);
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
fromTokenBalance,
|
||||
boughtAmount,
|
||||
from,
|
||||
to
|
||||
);
|
||||
return BRIDGE_SUCCESS;
|
||||
}
|
||||
|
||||
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
|
||||
/// and sign for itself in orders. Always succeeds.
|
||||
/// @return magicValue Magic success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
32
contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
Normal file
32
contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IMStable {
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _quantity,
|
||||
address _recipient
|
||||
)
|
||||
external
|
||||
returns (uint256 output);
|
||||
}
|
@ -38,7 +38,7 @@
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@ -28,6 +28,7 @@ import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
|
||||
import * as IGasToken from '../generated-artifacts/IGasToken.json';
|
||||
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
|
||||
import * as IMStable from '../generated-artifacts/IMStable.json';
|
||||
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
|
||||
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
|
||||
import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.json';
|
||||
@ -35,6 +36,7 @@ import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
|
||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json';
|
||||
import * as MStableBridge from '../generated-artifacts/MStableBridge.json';
|
||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../generated-artifacts/Ownable.json';
|
||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
|
||||
@ -66,6 +68,7 @@ export const artifacts = {
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
MStableBridge: MStableBridge as ContractArtifact,
|
||||
MixinGasToken: MixinGasToken as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
|
||||
@ -82,6 +85,7 @@ export const artifacts = {
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IGasToken: IGasToken as ContractArtifact,
|
||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IUniswapExchange: IUniswapExchange as ContractArtifact,
|
||||
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
|
@ -26,10 +26,12 @@ export * from '../generated-wrappers/i_erc20_bridge';
|
||||
export * from '../generated-wrappers/i_eth2_dai';
|
||||
export * from '../generated-wrappers/i_gas_token';
|
||||
export * from '../generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../generated-wrappers/i_m_stable';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../generated-wrappers/kyber_bridge';
|
||||
export * from '../generated-wrappers/m_stable_bridge';
|
||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../generated-wrappers/mixin_authorizable';
|
||||
export * from '../generated-wrappers/mixin_gas_token';
|
||||
|
@ -28,6 +28,7 @@ import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
|
||||
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
|
||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
|
||||
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
|
||||
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
|
||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
|
||||
@ -35,6 +36,7 @@ import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
|
||||
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
|
||||
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
|
||||
import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json';
|
||||
import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json';
|
||||
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
|
||||
import * as Ownable from '../test/generated-artifacts/Ownable.json';
|
||||
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
|
||||
@ -66,6 +68,7 @@ export const artifacts = {
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
KyberBridge: KyberBridge as ContractArtifact,
|
||||
MStableBridge: MStableBridge as ContractArtifact,
|
||||
MixinGasToken: MixinGasToken as ContractArtifact,
|
||||
UniswapBridge: UniswapBridge as ContractArtifact,
|
||||
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
|
||||
@ -82,6 +85,7 @@ export const artifacts = {
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IGasToken: IGasToken as ContractArtifact,
|
||||
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IUniswapExchange: IUniswapExchange as ContractArtifact,
|
||||
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
|
@ -26,10 +26,12 @@ export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_gas_token';
|
||||
export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../test/generated-wrappers/i_m_stable';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
|
||||
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../test/generated-wrappers/kyber_bridge';
|
||||
export * from '../test/generated-wrappers/m_stable_bridge';
|
||||
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
|
||||
export * from '../test/generated-wrappers/mixin_authorizable';
|
||||
export * from '../test/generated-wrappers/mixin_gas_token';
|
||||
|
@ -26,10 +26,12 @@
|
||||
"generated-artifacts/IEth2Dai.json",
|
||||
"generated-artifacts/IGasToken.json",
|
||||
"generated-artifacts/IKyberNetworkProxy.json",
|
||||
"generated-artifacts/IMStable.json",
|
||||
"generated-artifacts/IUniswapExchange.json",
|
||||
"generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"generated-artifacts/IUniswapV2Router01.json",
|
||||
"generated-artifacts/KyberBridge.json",
|
||||
"generated-artifacts/MStableBridge.json",
|
||||
"generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"generated-artifacts/MixinAuthorizable.json",
|
||||
"generated-artifacts/MixinGasToken.json",
|
||||
@ -70,10 +72,12 @@
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IGasToken.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
"test/generated-artifacts/IMStable.json",
|
||||
"test/generated-artifacts/IUniswapExchange.json",
|
||||
"test/generated-artifacts/IUniswapExchangeFactory.json",
|
||||
"test/generated-artifacts/IUniswapV2Router01.json",
|
||||
"test/generated-artifacts/KyberBridge.json",
|
||||
"test/generated-artifacts/MStableBridge.json",
|
||||
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
|
||||
"test/generated-artifacts/MixinAuthorizable.json",
|
||||
"test/generated-artifacts/MixinGasToken.json",
|
||||
|
@ -1,10 +0,0 @@
|
||||
# Blacklist all files
|
||||
.*
|
||||
*
|
||||
# Whitelist lib
|
||||
!lib/**/*
|
||||
# Whitelist Solidity contracts
|
||||
!contracts/src/**/*
|
||||
# Blacklist tests in lib
|
||||
/lib/test/*
|
||||
# Package specific ignore
|
@ -1,210 +0,0 @@
|
||||
[
|
||||
{
|
||||
"version": "1.8.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Refactor and support more varied curves",
|
||||
"pr": 2633
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.7.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Pass in `DevUtils` address to required functions",
|
||||
"pr": 2629
|
||||
},
|
||||
{
|
||||
"note": "Use new Kyber Katalyst functions",
|
||||
"pr": 2629
|
||||
}
|
||||
],
|
||||
"timestamp": 1594788383
|
||||
},
|
||||
{
|
||||
"version": "1.6.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Pass in `DevUtils` address as a constructor parameter",
|
||||
"pr": 2531
|
||||
},
|
||||
{
|
||||
"note": "Sample `Curve` for buy amounts",
|
||||
"pr": 2551
|
||||
},
|
||||
{
|
||||
"note": "Added `sampleBuysFromKyberNetwork`",
|
||||
"pr": 2551
|
||||
},
|
||||
{
|
||||
"note": "Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve",
|
||||
"pr": 2575
|
||||
},
|
||||
{
|
||||
"note": "Add UniswapV2",
|
||||
"pr": 2595
|
||||
},
|
||||
{
|
||||
"note": "Sample from MultiBridge",
|
||||
"pr": 2593
|
||||
}
|
||||
],
|
||||
"timestamp": 1592969527
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "1.5.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.5.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add generic liquidity provider sampling",
|
||||
"pr": 2487
|
||||
},
|
||||
{
|
||||
"note": "Use liquidity provider registry in sampler",
|
||||
"pr": 2499
|
||||
}
|
||||
],
|
||||
"timestamp": 1582837861
|
||||
},
|
||||
{
|
||||
"timestamp": 1582677073,
|
||||
"version": "1.4.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1582623685,
|
||||
"version": "1.4.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Added Curve contract sampling",
|
||||
"pr": 2483
|
||||
}
|
||||
],
|
||||
"timestamp": 1581748629
|
||||
},
|
||||
{
|
||||
"version": "1.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Catch reverts to `DevUtils` calls",
|
||||
"pr": 2476
|
||||
},
|
||||
{
|
||||
"note": "Remove wrapper functions and introduce `batchCall()`",
|
||||
"pr": 2477
|
||||
}
|
||||
],
|
||||
"timestamp": 1581204851
|
||||
},
|
||||
{
|
||||
"timestamp": 1580988106,
|
||||
"version": "1.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Make source IDs static on all networks, not inherited from `DeploymentConstants`.",
|
||||
"pr": 2459
|
||||
}
|
||||
],
|
||||
"timestamp": 1580811564
|
||||
},
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add batch functions to query quotes",
|
||||
"pr": 2427
|
||||
},
|
||||
{
|
||||
"note": "Early exit if a DEX sample fails",
|
||||
"pr": 2427
|
||||
}
|
||||
],
|
||||
"timestamp": 1579682890
|
||||
},
|
||||
{
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add gas limits to external quote calls.",
|
||||
"pr": 2405
|
||||
}
|
||||
],
|
||||
"timestamp": 1578272714
|
||||
},
|
||||
{
|
||||
"version": "1.0.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Do not query empty/unsigned orders. Swallow revets on DEX quotes.",
|
||||
"pr": 2395
|
||||
}
|
||||
],
|
||||
"timestamp": 1576540892
|
||||
},
|
||||
{
|
||||
"timestamp": 1575931811,
|
||||
"version": "1.0.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Created package.",
|
||||
"pr": 2344
|
||||
}
|
||||
],
|
||||
"timestamp": 1575296764
|
||||
},
|
||||
{
|
||||
"version": "1.0.0-beta.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
],
|
||||
"timestamp": 1575290197
|
||||
},
|
||||
{
|
||||
"version": "1.0.0-beta.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Created package.",
|
||||
"pr": 2344
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -1,83 +0,0 @@
|
||||
<!--
|
||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
|
||||
Edit the package's CHANGELOG.json file only.
|
||||
-->
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.7.0 - _July 15, 2020_
|
||||
|
||||
* Pass in `DevUtils` address to required functions (#2629)
|
||||
* Use new Kyber Katalyst functions (#2629)
|
||||
|
||||
## v1.6.0 - _June 24, 2020_
|
||||
|
||||
* Pass in `DevUtils` address as a constructor parameter (#2531)
|
||||
* Sample `Curve` for buy amounts (#2551)
|
||||
* Added `sampleBuysFromKyberNetwork` (#2551)
|
||||
* Use `searchBestRate` in Kyber samples. Return 0 when Uniswap/Eth2Dai reserve (#2575)
|
||||
* Add UniswapV2 (#2595)
|
||||
* Sample from MultiBridge (#2593)
|
||||
|
||||
## v1.5.1 - _March 3, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.5.0 - _February 27, 2020_
|
||||
|
||||
* Add generic liquidity provider sampling (#2487)
|
||||
* Use liquidity provider registry in sampler (#2499)
|
||||
|
||||
## v1.4.2 - _February 26, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.1 - _February 25, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.4.0 - _February 15, 2020_
|
||||
|
||||
* Added Curve contract sampling (#2483)
|
||||
|
||||
## v1.3.0 - _February 8, 2020_
|
||||
|
||||
* Catch reverts to `DevUtils` calls (#2476)
|
||||
* Remove wrapper functions and introduce `batchCall()` (#2477)
|
||||
|
||||
## v1.2.1 - _February 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.2.0 - _February 4, 2020_
|
||||
|
||||
* Make source IDs static on all networks, not inherited from `DeploymentConstants`. (#2459)
|
||||
|
||||
## v1.1.0 - _January 22, 2020_
|
||||
|
||||
* Add batch functions to query quotes (#2427)
|
||||
* Early exit if a DEX sample fails (#2427)
|
||||
|
||||
## v1.0.3 - _January 6, 2020_
|
||||
|
||||
* Add gas limits to external quote calls. (#2405)
|
||||
|
||||
## v1.0.2 - _December 17, 2019_
|
||||
|
||||
* Do not query empty/unsigned orders. Swallow revets on DEX quotes. (#2395)
|
||||
|
||||
## v1.0.1 - _December 9, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0 - _December 2, 2019_
|
||||
|
||||
* Created package. (#2344)
|
||||
|
||||
## v1.0.0-beta.2 - _December 2, 2019_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.0-beta.1 - _Invalid date_
|
||||
|
||||
* Created package. (#2344)
|
@ -1 +0,0 @@
|
||||
[]
|
@ -1,67 +0,0 @@
|
||||
## ERC20BridgeSampler
|
||||
|
||||
This package contains contracts used in DEX aggregation.
|
||||
|
||||
This is an MVP implementation, which agnostically samples DEXes for off-chain sorting and order generation. It is entirely read-only and never not touches any funds.
|
||||
|
||||
## Installation
|
||||
|
||||
**Install**
|
||||
|
||||
```bash
|
||||
npm install @0x/contracts-erc20-bridge-sampler --save
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||
|
||||
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
|
||||
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||
|
||||
```bash
|
||||
yarn config set workspaces-experimental true
|
||||
```
|
||||
|
||||
Then install dependencies
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-erc20-bridge-sampler yarn build
|
||||
```
|
||||
|
||||
Or continuously rebuild on change:
|
||||
|
||||
```bash
|
||||
PKG=@0x/contracts-erc20-bridge-sampler yarn watch
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
||||
```bash
|
||||
yarn clean
|
||||
```
|
||||
|
||||
### Lint
|
||||
|
||||
```bash
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Run Tests
|
||||
|
||||
```bash
|
||||
yarn test
|
||||
```
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IDevUtils {
|
||||
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||
/// @param order The order structure.
|
||||
/// @param signature Signature provided by maker that proves the order's authenticity.
|
||||
/// `0x01` can always be provided if the signature does not need to be validated.
|
||||
/// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order),
|
||||
/// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state),
|
||||
/// and isValidSignature (validity of the provided signature).
|
||||
/// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
|
||||
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
|
||||
/// amount of each asset that can be filled.
|
||||
function getOrderRelevantState(LibOrder.Order calldata order, bytes calldata signature)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
);
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "./IDevUtils.sol";
|
||||
|
||||
|
||||
contract NativeOrderSampler {
|
||||
|
||||
/// @dev Gas limit for DevUtils calls.
|
||||
uint256 constant internal DEV_UTILS_CALL_GAS = 500e3; // 500k
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// maker/taker asset amounts (returning 0).
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param devUtilsAddress Address to the DevUtils contract.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableTakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
address devUtilsAddress
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableTakerAssetAmounts)
|
||||
{
|
||||
orderFillableTakerAssetAmounts = new uint256[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// Ignore orders with no signature or empty maker/taker amounts.
|
||||
if (orderSignatures[i].length == 0 ||
|
||||
orders[i].makerAssetAmount == 0 ||
|
||||
orders[i].takerAssetAmount == 0) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
// solhint-disable indent
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
devUtilsAddress
|
||||
.staticcall
|
||||
.gas(DEV_UTILS_CALL_GAS)
|
||||
(abi.encodeWithSelector(
|
||||
IDevUtils(devUtilsAddress).getOrderRelevantState.selector,
|
||||
orders[i],
|
||||
orderSignatures[i]
|
||||
));
|
||||
// solhint-enable indent
|
||||
if (!didSucceed) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
(
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
) = abi.decode(
|
||||
resultData,
|
||||
(LibOrder.OrderInfo, uint256, bool)
|
||||
);
|
||||
// The fillable amount is zero if the order is not fillable or if the
|
||||
// signature is invalid.
|
||||
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE ||
|
||||
!isValidSignature) {
|
||||
orderFillableTakerAssetAmounts[i] = 0;
|
||||
} else {
|
||||
orderFillableTakerAssetAmounts[i] = fillableTakerAssetAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param devUtilsAddress Address to the DevUtils contract.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableMakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
address devUtilsAddress
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts)
|
||||
{
|
||||
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures,
|
||||
devUtilsAddress
|
||||
);
|
||||
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
|
||||
// convert them to maker asset amounts.
|
||||
for (uint256 i = 0; i < orders.length; ++i) {
|
||||
if (orderFillableMakerAssetAmounts[i] != 0) {
|
||||
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
|
||||
orderFillableMakerAssetAmounts[i],
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.7.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
"description": "Sampler contracts for the 0x asset-swapper",
|
||||
"main": "lib/src/index.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"build:ci": "yarn build",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s build test",
|
||||
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
|
||||
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
|
||||
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
|
||||
"compile": "sol-compiler",
|
||||
"watch": "sol-compiler -w",
|
||||
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"coverage:report:text": "istanbul report text",
|
||||
"coverage:report:html": "istanbul report html && open coverage/index.html",
|
||||
"profiler:report:html": "istanbul report html && open coverage/index.html",
|
||||
"coverage:report:lcov": "istanbul report lcov",
|
||||
"test:circleci": "yarn test",
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
|
||||
"compile:truffle": "truffle compile"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|ICurve|IDevUtils|IEth2Dai|IKyberHintHandler|IKyberNetwork|IKyberNetworkProxy|IKyberStorage|ILiquidityProvider|ILiquidityProviderRegistry|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|UniswapSampler|UniswapV2Sampler).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/0xProject/0x-monorepo.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x-monorepo/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.3.1",
|
||||
"@0x/contracts-asset-proxy": "^3.4.0",
|
||||
"@0x/contracts-erc20": "^3.2.1",
|
||||
"@0x/contracts-exchange": "^3.2.7",
|
||||
"@0x/contracts-exchange-libs": "^4.3.7",
|
||||
"@0x/contracts-gen": "^2.0.10",
|
||||
"@0x/contracts-test-utils": "^5.3.4",
|
||||
"@0x/contracts-utils": "^4.5.1",
|
||||
"@0x/dev-utils": "^3.3.0",
|
||||
"@0x/sol-compiler": "^4.1.1",
|
||||
"@0x/tslint-config": "^4.1.0",
|
||||
"@0x/web3-wrapper": "^7.2.0",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
"chai": "^4.0.1",
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"shx": "^0.2.2",
|
||||
"solhint": "^1.4.1",
|
||||
"truffle": "^5.0.32",
|
||||
"tslint": "5.11.0",
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.2.3",
|
||||
"@0x/types": "^3.2.0",
|
||||
"@0x/typescript-typings": "^5.1.1",
|
||||
"@0x/utils": "^5.5.1",
|
||||
"ethereum-types": "^3.2.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './wrappers';
|
||||
export * from './artifacts';
|
@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Use this file to configure your truffle project. It's seeded with some
|
||||
* common settings for different networks and features like migrations,
|
||||
* compilation and testing. Uncomment the ones you need or modify
|
||||
* them to suit your project as necessary.
|
||||
*
|
||||
* More information about configuration can be found at:
|
||||
*
|
||||
* truffleframework.com/docs/advanced/configuration
|
||||
*
|
||||
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
|
||||
* to sign your transactions before they're sent to a remote public node. Infura accounts
|
||||
* are available for free at: infura.io/register.
|
||||
*
|
||||
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
|
||||
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
|
||||
* phrase from a file you've .gitignored so it doesn't accidentally become public.
|
||||
*
|
||||
*/
|
||||
|
||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
|
||||
// const infuraKey = "fj4jll3k.....";
|
||||
//
|
||||
// const fs = require('fs');
|
||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Networks define how you connect to your ethereum client and let you set the
|
||||
* defaults web3 uses to send transactions. If you don't specify one truffle
|
||||
* will spin up a development blockchain for you on port 9545 when you
|
||||
* run `develop` or `test`. You can ask a truffle command to use a specific
|
||||
* network from the command line, e.g
|
||||
*
|
||||
* $ truffle test --network <network-name>
|
||||
*/
|
||||
|
||||
networks: {
|
||||
// Useful for testing. The `development` name is special - truffle uses it by default
|
||||
// if it's defined here and no other network is specified at the command line.
|
||||
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
|
||||
// tab if you use this network and you must also set the `host`, `port` and `network_id`
|
||||
// options below to some value.
|
||||
//
|
||||
// development: {
|
||||
// host: "127.0.0.1", // Localhost (default: none)
|
||||
// port: 8545, // Standard Ethereum port (default: none)
|
||||
// network_id: "*", // Any network (default: none)
|
||||
// },
|
||||
// Another network with more advanced options...
|
||||
// advanced: {
|
||||
// port: 8777, // Custom port
|
||||
// network_id: 1342, // Custom network
|
||||
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
|
||||
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
|
||||
// from: <address>, // Account to send txs from (default: accounts[0])
|
||||
// websockets: true // Enable EventEmitter interface for web3 (default: false)
|
||||
// },
|
||||
// Useful for deploying to a public network.
|
||||
// NB: It's important to wrap the provider as a function.
|
||||
// ropsten: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
|
||||
// network_id: 3, // Ropsten's id
|
||||
// gas: 5500000, // Ropsten has a lower block limit than mainnet
|
||||
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
|
||||
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
|
||||
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
|
||||
// },
|
||||
// Useful for private networks
|
||||
// private: {
|
||||
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
|
||||
// network_id: 2111, // This network is yours, in the cloud.
|
||||
// production: true // Treats this network as if it was a public net. (default: false)
|
||||
// }
|
||||
},
|
||||
|
||||
// Set default mocha options here, use special reporters etc.
|
||||
mocha: {
|
||||
// timeout: 100000
|
||||
},
|
||||
|
||||
// Configure your compilers
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/DummyLiquidityProvider.json",
|
||||
"generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"generated-artifacts/ERC20BridgeSampler.json",
|
||||
"generated-artifacts/ILiquidityProvider.json",
|
||||
"generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ApproximateBuys.json",
|
||||
"test/generated-artifacts/CurveSampler.json",
|
||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/Eth2DaiSampler.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IDevUtils.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberHintHandler.json",
|
||||
"test/generated-artifacts/IKyberNetwork.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
"test/generated-artifacts/IKyberStorage.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/IMultiBridge.json",
|
||||
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
||||
"test/generated-artifacts/IUniswapV2Router01.json",
|
||||
"test/generated-artifacts/KyberSampler.json",
|
||||
"test/generated-artifacts/LiquidityProviderSampler.json",
|
||||
"test/generated-artifacts/MultiBridgeSampler.json",
|
||||
"test/generated-artifacts/NativeOrderSampler.json",
|
||||
"test/generated-artifacts/SamplerUtils.json",
|
||||
"test/generated-artifacts/TestERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/UniswapSampler.json",
|
||||
"test/generated-artifacts/UniswapV2Sampler.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"custom-no-magic-numbers": false,
|
||||
"max-file-line-count": false
|
||||
},
|
||||
"linterOptions": {
|
||||
"exclude": ["src/artifacts.ts", "test/artifacts.ts"]
|
||||
}
|
||||
}
|
@ -57,7 +57,6 @@
|
||||
"@0x/contracts-broker": "^1.1.6",
|
||||
"@0x/contracts-coordinator": "^3.1.7",
|
||||
"@0x/contracts-dev-utils": "^1.3.5",
|
||||
"@0x/contracts-erc20-bridge-sampler": "^1.7.0",
|
||||
"@0x/contracts-exchange-forwarder": "^4.2.7",
|
||||
"@0x/contracts-exchange-libs": "^4.3.7",
|
||||
"@0x/contracts-extensions": "^6.2.1",
|
||||
|
@ -50,90 +50,98 @@ contract DeploymentConstants {
|
||||
address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
|
||||
/// @dev Mainnet address of the GST Collector
|
||||
address constant private GST_COLLECTOR_ADDRESS = 0x000000D3b08566BE75A6DB803C03C85C0c1c5B96;
|
||||
/// @dev Mainnet address of the mStable mUSD contract.
|
||||
address constant private MUSD_ADDRESS = 0xe2f2a5C287993345a840Db3B0845fbC70f5935a5;
|
||||
|
||||
/* // Ropsten addresses ///////////////////////////////////////////////////////
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
|
||||
/// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||
address constant private KYBER_NETWORK_PROXY_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
||||
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `UniswapV2Router01` contract.
|
||||
address constant private UNISWAP_V2_ROUTER_01_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
|
||||
address constant private ETH2DAI_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `ERC20BridgeProxy` contract
|
||||
address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xb344afeD348de15eb4a9e180205A2B0739628339;
|
||||
///@dev Mainnet address of the `Dai` (multi-collateral) contract
|
||||
address constant private DAI_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `Chai` contract
|
||||
address constant private CHAI_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the 0x DevUtils contract.
|
||||
address constant private DEV_UTILS_ADDRESS = 0xC812AF3f3fBC62F76ea4262576EC0f49dB8B7f1c;
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev Mainnet address of the dYdX contract.
|
||||
address constant private DYDX_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the GST2 contract
|
||||
address constant private GST_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the GST Collector
|
||||
address constant private GST_COLLECTOR_ADDRESS = address(0); */
|
||||
// // Ropsten addresses ///////////////////////////////////////////////////////
|
||||
// /// @dev Mainnet address of the WETH contract.
|
||||
// address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
|
||||
// /// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||
// address constant private KYBER_NETWORK_PROXY_ADDRESS = 0xd719c34261e099Fdb33030ac8909d5788D3039C4;
|
||||
// /// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
||||
// address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0x9c83dCE8CA20E9aAF9D3efc003b2ea62aBC08351;
|
||||
// /// @dev Mainnet address of the `UniswapV2Router01` contract.
|
||||
// address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
|
||||
// /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
|
||||
// address constant private ETH2DAI_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the `ERC20BridgeProxy` contract
|
||||
// address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xb344afeD348de15eb4a9e180205A2B0739628339;
|
||||
// ///@dev Mainnet address of the `Dai` (multi-collateral) contract
|
||||
// address constant private DAI_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the `Chai` contract
|
||||
// address constant private CHAI_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the 0x DevUtils contract.
|
||||
// address constant private DEV_UTILS_ADDRESS = 0xC812AF3f3fBC62F76ea4262576EC0f49dB8B7f1c;
|
||||
// /// @dev Kyber ETH pseudo-address.
|
||||
// address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
// /// @dev Mainnet address of the dYdX contract.
|
||||
// address constant private DYDX_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the GST2 contract
|
||||
// address constant private GST_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the GST Collector
|
||||
// address constant private GST_COLLECTOR_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the mStable mUSD contract.
|
||||
// address constant private MUSD_ADDRESS = 0x4E1000616990D83e56f4b5fC6CC8602DcfD20459;
|
||||
|
||||
/* // Rinkeby addresses ///////////////////////////////////////////////////////
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
|
||||
/// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||
address constant private KYBER_NETWORK_PROXY_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
||||
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `UniswapV2Router01` contract.
|
||||
address constant private UNISWAP_V2_ROUTER_01_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
|
||||
address constant private ETH2DAI_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `ERC20BridgeProxy` contract
|
||||
address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xA2AA4bEFED748Fba27a3bE7Dfd2C4b2c6DB1F49B;
|
||||
///@dev Mainnet address of the `Dai` (multi-collateral) contract
|
||||
address constant private DAI_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the `Chai` contract
|
||||
address constant private CHAI_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the 0x DevUtils contract.
|
||||
address constant private DEV_UTILS_ADDRESS = 0x46B5BC959e8A754c0256FFF73bF34A52Ad5CdfA9;
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev Mainnet address of the dYdX contract.
|
||||
address constant private DYDX_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the GST2 contract
|
||||
address constant private GST_ADDRESS = address(0);
|
||||
/// @dev Mainnet address of the GST Collector
|
||||
address constant private GST_COLLECTOR_ADDRESS = address(0); */
|
||||
// // Rinkeby addresses ///////////////////////////////////////////////////////
|
||||
// /// @dev Mainnet address of the WETH contract.
|
||||
// address constant private WETH_ADDRESS = 0xc778417E063141139Fce010982780140Aa0cD5Ab;
|
||||
// /// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||
// address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x0d5371e5EE23dec7DF251A8957279629aa79E9C5;
|
||||
// /// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
||||
// address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36;
|
||||
// /// @dev Mainnet address of the `UniswapV2Router01` contract.
|
||||
// address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
|
||||
// /// @dev Mainnet address of the Eth2Dai `MatchingMarket` contract.
|
||||
// address constant private ETH2DAI_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the `ERC20BridgeProxy` contract
|
||||
// address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0xA2AA4bEFED748Fba27a3bE7Dfd2C4b2c6DB1F49B;
|
||||
// ///@dev Mainnet address of the `Dai` (multi-collateral) contract
|
||||
// address constant private DAI_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the `Chai` contract
|
||||
// address constant private CHAI_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the 0x DevUtils contract.
|
||||
// address constant private DEV_UTILS_ADDRESS = 0x46B5BC959e8A754c0256FFF73bF34A52Ad5CdfA9;
|
||||
// /// @dev Kyber ETH pseudo-address.
|
||||
// address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
// /// @dev Mainnet address of the dYdX contract.
|
||||
// address constant private DYDX_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the GST2 contract
|
||||
// address constant private GST_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the GST Collector
|
||||
// address constant private GST_COLLECTOR_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the mStable mUSD contract.
|
||||
// address constant private MUSD_ADDRESS = address(0);
|
||||
|
||||
/* // Kovan addresses /////////////////////////////////////////////////////////
|
||||
/// @dev Kovan address of the WETH contract.
|
||||
address constant private WETH_ADDRESS = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
|
||||
/// @dev Kovan address of the KyberNetworkProxy contract.
|
||||
address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D;
|
||||
/// @dev Kovan address of the `UniswapExchangeFactory` contract.
|
||||
address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30;
|
||||
/// @dev Kovan address of the `UniswapV2Router01` contract.
|
||||
address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
|
||||
/// @dev Kovan address of the Eth2Dai `MatchingMarket` contract.
|
||||
address constant private ETH2DAI_ADDRESS = 0xe325acB9765b02b8b418199bf9650972299235F4;
|
||||
/// @dev Kovan address of the `ERC20BridgeProxy` contract
|
||||
address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x3577552C1Fb7A44aD76BeEB7aB53251668A21F8D;
|
||||
/// @dev Kovan address of the `Chai` contract
|
||||
address constant private CHAI_ADDRESS = address(0);
|
||||
/// @dev Kovan address of the `Dai` (multi-collateral) contract
|
||||
address constant private DAI_ADDRESS = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;
|
||||
/// @dev Kovan address of the 0x DevUtils contract.
|
||||
address constant private DEV_UTILS_ADDRESS = 0x9402639A828BdF4E9e4103ac3B69E1a6E522eB59;
|
||||
/// @dev Kyber ETH pseudo-address.
|
||||
address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev Kovan address of the dYdX contract.
|
||||
address constant private DYDX_ADDRESS = address(0);
|
||||
/// @dev Kovan address of the GST2 contract
|
||||
address constant private GST_ADDRESS = address(0);
|
||||
/// @dev Kovan address of the GST Collector
|
||||
address constant private GST_COLLECTOR_ADDRESS = address(0); */
|
||||
// // Kovan addresses /////////////////////////////////////////////////////////
|
||||
// /// @dev Kovan address of the WETH contract.
|
||||
// address constant private WETH_ADDRESS = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
|
||||
// /// @dev Kovan address of the KyberNetworkProxy contract.
|
||||
// address constant private KYBER_NETWORK_PROXY_ADDRESS = 0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D;
|
||||
// /// @dev Kovan address of the `UniswapExchangeFactory` contract.
|
||||
// address constant private UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30;
|
||||
// /// @dev Kovan address of the `UniswapV2Router01` contract.
|
||||
// address constant private UNISWAP_V2_ROUTER_01_ADDRESS = 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a;
|
||||
// /// @dev Kovan address of the Eth2Dai `MatchingMarket` contract.
|
||||
// address constant private ETH2DAI_ADDRESS = 0xe325acB9765b02b8b418199bf9650972299235F4;
|
||||
// /// @dev Kovan address of the `ERC20BridgeProxy` contract
|
||||
// address constant private ERC20_BRIDGE_PROXY_ADDRESS = 0x3577552C1Fb7A44aD76BeEB7aB53251668A21F8D;
|
||||
// /// @dev Kovan address of the `Chai` contract
|
||||
// address constant private CHAI_ADDRESS = address(0);
|
||||
// /// @dev Kovan address of the `Dai` (multi-collateral) contract
|
||||
// address constant private DAI_ADDRESS = 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa;
|
||||
// /// @dev Kovan address of the 0x DevUtils contract.
|
||||
// address constant private DEV_UTILS_ADDRESS = 0x9402639A828BdF4E9e4103ac3B69E1a6E522eB59;
|
||||
// /// @dev Kyber ETH pseudo-address.
|
||||
// address constant internal KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
// /// @dev Kovan address of the dYdX contract.
|
||||
// address constant private DYDX_ADDRESS = address(0);
|
||||
// /// @dev Kovan address of the GST2 contract
|
||||
// address constant private GST_ADDRESS = address(0);
|
||||
// /// @dev Kovan address of the GST Collector
|
||||
// address constant private GST_COLLECTOR_ADDRESS = address(0);
|
||||
// /// @dev Mainnet address of the mStable mUSD contract.
|
||||
// address constant private MUSD_ADDRESS = address(0);
|
||||
|
||||
/// @dev Overridable way to get the `KyberNetworkProxy` address.
|
||||
/// @return kyberAddress The `IKyberNetworkProxy` address.
|
||||
@ -254,4 +262,14 @@ contract DeploymentConstants {
|
||||
{
|
||||
return GST_COLLECTOR_ADDRESS;
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the mStable mUSD address.
|
||||
/// @return musd The mStable mUSD address.
|
||||
function _getMUsdAddress()
|
||||
internal
|
||||
view
|
||||
returns (address musd)
|
||||
{
|
||||
return MUSD_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
172
contracts/zero-ex/contracts/src/bridges/BridgeAdapter.sol
Normal file
172
contracts/zero-ex/contracts/src/bridges/BridgeAdapter.sol
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./mixins/MixinAdapterAddresses.sol";
|
||||
import "./mixins/MixinBalancer.sol";
|
||||
import "./mixins/MixinCurve.sol";
|
||||
import "./mixins/MixinKyber.sol";
|
||||
import "./mixins/MixinMStable.sol";
|
||||
import "./mixins/MixinOasis.sol";
|
||||
import "./mixins/MixinUniswap.sol";
|
||||
import "./mixins/MixinUniswapV2.sol";
|
||||
import "./mixins/MixinZeroExBridge.sol";
|
||||
|
||||
contract BridgeAdapter is
|
||||
MixinAdapterAddresses,
|
||||
MixinBalancer,
|
||||
MixinCurve,
|
||||
MixinKyber,
|
||||
MixinMStable,
|
||||
MixinOasis,
|
||||
MixinUniswap,
|
||||
MixinUniswapV2,
|
||||
MixinZeroExBridge
|
||||
{
|
||||
|
||||
address private immutable BALANCER_BRIDGE_ADDRESS;
|
||||
address private immutable CURVE_BRIDGE_ADDRESS;
|
||||
address private immutable KYBER_BRIDGE_ADDRESS;
|
||||
address private immutable MSTABLE_BRIDGE_ADDRESS;
|
||||
address private immutable OASIS_BRIDGE_ADDRESS;
|
||||
address private immutable UNISWAP_BRIDGE_ADDRESS;
|
||||
address private immutable UNISWAP_V2_BRIDGE_ADDRESS;
|
||||
|
||||
/// @dev Emitted when a trade occurs.
|
||||
/// @param inputToken The token the bridge is converting from.
|
||||
/// @param outputToken The token the bridge is converting to.
|
||||
/// @param inputTokenAmount Amount of input token.
|
||||
/// @param outputTokenAmount Amount of output token.
|
||||
/// @param from The bridge address, indicating the underlying source of the fill.
|
||||
/// @param to The `to` address, currrently `address(this)`
|
||||
event ERC20BridgeTransfer(
|
||||
address inputToken,
|
||||
address outputToken,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount,
|
||||
address from,
|
||||
address to
|
||||
);
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
MixinBalancer()
|
||||
MixinCurve()
|
||||
MixinKyber(addresses)
|
||||
MixinMStable(addresses)
|
||||
MixinOasis(addresses)
|
||||
MixinUniswap(addresses)
|
||||
MixinUniswapV2(addresses)
|
||||
MixinZeroExBridge()
|
||||
{
|
||||
BALANCER_BRIDGE_ADDRESS = addresses.balancerBridge;
|
||||
CURVE_BRIDGE_ADDRESS = addresses.curveBridge;
|
||||
KYBER_BRIDGE_ADDRESS = addresses.kyberBridge;
|
||||
MSTABLE_BRIDGE_ADDRESS = addresses.mStableBridge;
|
||||
OASIS_BRIDGE_ADDRESS = addresses.oasisBridge;
|
||||
UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge;
|
||||
UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge;
|
||||
}
|
||||
|
||||
function trade(
|
||||
bytes calldata makerAssetData,
|
||||
address fromTokenAddress,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
(
|
||||
address toTokenAddress,
|
||||
address bridgeAddress,
|
||||
bytes memory bridgeData
|
||||
) = abi.decode(
|
||||
makerAssetData[4:],
|
||||
(address, address, bytes)
|
||||
);
|
||||
require(
|
||||
bridgeAddress != address(this) && bridgeAddress != address(0),
|
||||
"BridgeAdapter/INVALID_BRIDGE_ADDRESS"
|
||||
);
|
||||
|
||||
if (bridgeAddress == CURVE_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeCurve(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == UNISWAP_V2_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeUniswapV2(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == UNISWAP_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeUniswap(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == BALANCER_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeBalancer(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == KYBER_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeKyber(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == MSTABLE_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeMStable(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == OASIS_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeOasis(
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
bridgeAddress,
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
boughtAmount,
|
||||
bridgeAddress,
|
||||
address(this)
|
||||
);
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
30
contracts/zero-ex/contracts/src/bridges/IBridgeAdapter.sol
Normal file
30
contracts/zero-ex/contracts/src/bridges/IBridgeAdapter.sol
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
interface IBridgeAdapter {
|
||||
|
||||
function trade(
|
||||
bytes calldata makerAssetData,
|
||||
address fromTokenAddress,
|
||||
uint256 sellAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 boughtAmount);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
contract MixinAdapterAddresses
|
||||
{
|
||||
|
||||
struct AdapterAddresses {
|
||||
// Bridges
|
||||
address balancerBridge;
|
||||
address curveBridge;
|
||||
address kyberBridge;
|
||||
address mStableBridge;
|
||||
address oasisBridge;
|
||||
address uniswapBridge;
|
||||
address uniswapV2Bridge;
|
||||
// Exchanges
|
||||
address kyberNetworkProxy;
|
||||
address oasis;
|
||||
address uniswapV2Router;
|
||||
address uniswapExchangeFactory;
|
||||
address mStable;
|
||||
// Other
|
||||
address weth;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
|
||||
interface IBalancerPool {
|
||||
/// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`.
|
||||
/// @param tokenIn The token being sold
|
||||
/// @param tokenAmountIn The amount of `tokenIn` to sell.
|
||||
/// @param tokenOut The token being bought.
|
||||
/// @param minAmountOut The minimum amount of `tokenOut` to buy.
|
||||
/// @param maxPrice The maximum value for `spotPriceAfter`.
|
||||
/// @return tokenAmountOut The amount of `tokenOut` bought.
|
||||
/// @return spotPriceAfter The new marginal spot price of the given
|
||||
/// token pair for this pool.
|
||||
function swapExactAmountIn(
|
||||
address tokenIn,
|
||||
uint tokenAmountIn,
|
||||
address tokenOut,
|
||||
uint minAmountOut,
|
||||
uint maxPrice
|
||||
) external returns (uint tokenAmountOut, uint spotPriceAfter);
|
||||
}
|
||||
|
||||
contract MixinBalancer {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
function _tradeBalancer(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data.
|
||||
(address fromTokenAddress, address poolAddress) = abi.decode(
|
||||
bridgeData,
|
||||
(address, address)
|
||||
);
|
||||
IERC20TokenV06(fromTokenAddress).approveIfBelow(
|
||||
poolAddress,
|
||||
sellAmount
|
||||
);
|
||||
// Sell all of this contract's `fromTokenAddress` token balance.
|
||||
(boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
|
||||
fromTokenAddress, // tokenIn
|
||||
sellAmount, // tokenAmountIn
|
||||
toTokenAddress, // tokenOut
|
||||
1, // minAmountOut
|
||||
uint256(-1) // maxPrice
|
||||
);
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
|
||||
contract MixinCurve {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
using LibRichErrorsV06 for bytes;
|
||||
|
||||
|
||||
struct CurveBridgeData {
|
||||
address curveAddress;
|
||||
bytes4 exchangeFunctionSelector;
|
||||
address fromTokenAddress;
|
||||
int128 fromCoinIdx;
|
||||
int128 toCoinIdx;
|
||||
}
|
||||
|
||||
function _tradeCurve(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the Curve metadata.
|
||||
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
|
||||
IERC20TokenV06(data.fromTokenAddress).approveIfBelow(data.curveAddress, sellAmount);
|
||||
uint256 beforeBalance = IERC20TokenV06(toTokenAddress).balanceOf(address(this));
|
||||
(bool success, bytes memory resultData) =
|
||||
data.curveAddress.call(abi.encodeWithSelector(
|
||||
data.exchangeFunctionSelector,
|
||||
data.fromCoinIdx,
|
||||
data.toCoinIdx,
|
||||
// dx
|
||||
sellAmount,
|
||||
// min dy
|
||||
1
|
||||
));
|
||||
if (!success) {
|
||||
resultData.rrevert();
|
||||
}
|
||||
|
||||
return IERC20TokenV06(toTokenAddress).balanceOf(address(this)).safeSub(beforeBalance);
|
||||
}
|
||||
}
|
123
contracts/zero-ex/contracts/src/bridges/mixins/MixinKyber.sol
Normal file
123
contracts/zero-ex/contracts/src/bridges/mixins/MixinKyber.sol
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
interface IKyberNetworkProxy {
|
||||
|
||||
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens.
|
||||
/// @param sellTokenAddress Token to sell.
|
||||
/// @param sellAmount Amount of tokens to sell.
|
||||
/// @param buyTokenAddress Token to buy.
|
||||
/// @param recipientAddress Address to send bought tokens to.
|
||||
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
|
||||
/// @param minConversionRate The minimal conversion rate. If actual rate
|
||||
/// is lower, trade is canceled.
|
||||
/// @param walletId The wallet ID to send part of the fees
|
||||
/// @return boughtAmount Amount of tokens bought.
|
||||
function trade(
|
||||
address sellTokenAddress,
|
||||
uint256 sellAmount,
|
||||
address buyTokenAddress,
|
||||
address payable recipientAddress,
|
||||
uint256 maxBuyTokenAmount,
|
||||
uint256 minConversionRate,
|
||||
address walletId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns(uint256 boughtAmount);
|
||||
}
|
||||
|
||||
contract MixinKyber is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Address indicating the trade is using ETH
|
||||
address private immutable KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
/// @dev Mainnet address of the KyberNetworkProxy contract.
|
||||
IKyberNetworkProxy private immutable KYBER_NETWORK_PROXY;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
WETH = IEtherTokenV06(addresses.weth);
|
||||
KYBER_NETWORK_PROXY = IKyberNetworkProxy(addresses.kyberNetworkProxy);
|
||||
}
|
||||
|
||||
function _tradeKyber(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
address fromTokenAddress = abi.decode(bridgeData, (address));
|
||||
uint256 payableAmount;
|
||||
|
||||
if (fromTokenAddress != address(WETH)) {
|
||||
// If the input token is not WETH, grant an allowance to the exchange
|
||||
// to spend them.
|
||||
IERC20TokenV06(fromTokenAddress).approveIfBelow(
|
||||
address(KYBER_NETWORK_PROXY),
|
||||
sellAmount
|
||||
);
|
||||
} else {
|
||||
// If the input token is WETH, unwrap it and attach it to the call.
|
||||
fromTokenAddress = KYBER_ETH_ADDRESS;
|
||||
payableAmount = sellAmount;
|
||||
WETH.withdraw(payableAmount);
|
||||
}
|
||||
bool isToTokenWeth = toTokenAddress == address(WETH);
|
||||
|
||||
// Try to sell all of this contract's input token balance through
|
||||
// `KyberNetworkProxy.trade()`.
|
||||
boughtAmount = KYBER_NETWORK_PROXY.trade{ value: payableAmount }(
|
||||
// Input token.
|
||||
fromTokenAddress,
|
||||
// Sell amount.
|
||||
sellAmount,
|
||||
// Output token.
|
||||
isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress,
|
||||
// Transfer to this contract
|
||||
address(uint160(address(this))),
|
||||
// Buy as much as possible.
|
||||
uint256(-1),
|
||||
// Lowest minimum conversion rate
|
||||
1,
|
||||
// No affiliate address.
|
||||
address(0)
|
||||
);
|
||||
if (isToTokenWeth) {
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
}
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
|
||||
interface IMStable {
|
||||
|
||||
function swap(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _quantity,
|
||||
address _recipient
|
||||
)
|
||||
external
|
||||
returns (uint256 output);
|
||||
}
|
||||
|
||||
contract MixinMStable is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the mStable mUSD contract.
|
||||
IMStable private immutable MSTABLE;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
MSTABLE = IMStable(addresses.mStable);
|
||||
}
|
||||
|
||||
function _tradeMStable(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
IERC20TokenV06(fromTokenAddress).approveIfBelow(address(MSTABLE), sellAmount);
|
||||
|
||||
boughtAmount = MSTABLE.swap(
|
||||
fromTokenAddress,
|
||||
toTokenAddress,
|
||||
sellAmount,
|
||||
address(this)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
interface IOasis {
|
||||
|
||||
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
|
||||
/// @param fromToken The token being sold.
|
||||
/// @param sellAmount The amount of `fromToken` token being sold.
|
||||
/// @param toToken The token being bought.
|
||||
/// @param minFillAmount Minimum amount of `toToken` token to buy.
|
||||
/// @return fillAmount Amount of `toToken` bought.
|
||||
function sellAllAmount(
|
||||
address fromToken,
|
||||
uint256 sellAmount,
|
||||
address toToken,
|
||||
uint256 minFillAmount
|
||||
)
|
||||
external
|
||||
returns (uint256 fillAmount);
|
||||
}
|
||||
|
||||
contract MixinOasis is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the Oasis `MatchingMarket` contract.
|
||||
IOasis private immutable OASIS;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
OASIS = IOasis(addresses.oasis);
|
||||
}
|
||||
|
||||
function _tradeOasis(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
|
||||
IERC20TokenV06(fromTokenAddress).approveIfBelow(
|
||||
address(OASIS),
|
||||
sellAmount
|
||||
);
|
||||
// Try to sell all of this contract's `fromTokenAddress` token balance.
|
||||
boughtAmount = OASIS.sellAllAmount(
|
||||
fromTokenAddress,
|
||||
sellAmount,
|
||||
toTokenAddress,
|
||||
// min fill amount
|
||||
1
|
||||
);
|
||||
return boughtAmount;
|
||||
}
|
||||
}
|
220
contracts/zero-ex/contracts/src/bridges/mixins/MixinUniswap.sol
Normal file
220
contracts/zero-ex/contracts/src/bridges/mixins/MixinUniswap.sol
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
interface IUniswapExchangeFactory {
|
||||
|
||||
/// @dev Get the exchange for a token.
|
||||
/// @param tokenAddress The address of the token contract.
|
||||
function getExchange(address tokenAddress)
|
||||
external
|
||||
view
|
||||
returns (address);
|
||||
}
|
||||
|
||||
interface IUniswapExchange {
|
||||
|
||||
/// @dev Buys at least `minTokensBought` tokens with ETH and transfer them
|
||||
/// to `recipient`.
|
||||
/// @param minTokensBought The minimum number of tokens to buy.
|
||||
/// @param deadline Time when this order expires.
|
||||
/// @param recipient Who to transfer the tokens to.
|
||||
/// @return tokensBought Amount of tokens bought.
|
||||
function ethToTokenTransferInput(
|
||||
uint256 minTokensBought,
|
||||
uint256 deadline,
|
||||
address recipient
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (uint256 tokensBought);
|
||||
|
||||
/// @dev Buys at least `minEthBought` ETH with tokens.
|
||||
/// @param tokensSold Amount of tokens to sell.
|
||||
/// @param minEthBought The minimum amount of ETH to buy.
|
||||
/// @param deadline Time when this order expires.
|
||||
/// @return ethBought Amount of tokens bought.
|
||||
function tokenToEthSwapInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline
|
||||
)
|
||||
external
|
||||
returns (uint256 ethBought);
|
||||
|
||||
/// @dev Buys at least `minTokensBought` tokens with the exchange token
|
||||
/// and transfer them to `recipient`.
|
||||
/// @param tokensSold Amount of tokens to sell.
|
||||
/// @param minTokensBought The minimum number of tokens to buy.
|
||||
/// @param minEthBought The minimum amount of intermediate ETH to buy.
|
||||
/// @param deadline Time when this order expires.
|
||||
/// @param recipient Who to transfer the tokens to.
|
||||
/// @param toTokenAddress The token being bought.
|
||||
/// @return tokensBought Amount of tokens bought.
|
||||
function tokenToTokenTransferInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address recipient,
|
||||
address toTokenAddress
|
||||
)
|
||||
external
|
||||
returns (uint256 tokensBought);
|
||||
|
||||
/// @dev Buys at least `minTokensBought` tokens with the exchange token.
|
||||
/// @param tokensSold Amount of tokens to sell.
|
||||
/// @param minTokensBought The minimum number of tokens to buy.
|
||||
/// @param minEthBought The minimum amount of intermediate ETH to buy.
|
||||
/// @param deadline Time when this order expires.
|
||||
/// @param toTokenAddress The token being bought.
|
||||
/// @return tokensBought Amount of tokens bought.
|
||||
function tokenToTokenSwapInput(
|
||||
uint256 tokensSold,
|
||||
uint256 minTokensBought,
|
||||
uint256 minEthBought,
|
||||
uint256 deadline,
|
||||
address toTokenAddress
|
||||
)
|
||||
external
|
||||
returns (uint256 tokensBought);
|
||||
}
|
||||
|
||||
contract MixinUniswap is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the WETH contract.
|
||||
IEtherTokenV06 private immutable WETH;
|
||||
/// @dev Mainnet address of the `UniswapExchangeFactory` contract.
|
||||
IUniswapExchangeFactory private immutable UNISWAP_EXCHANGE_FACTORY;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
WETH = IEtherTokenV06(addresses.weth);
|
||||
UNISWAP_EXCHANGE_FACTORY = IUniswapExchangeFactory(addresses.uniswapExchangeFactory);
|
||||
}
|
||||
|
||||
function _tradeUniswap(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(address fromTokenAddress) = abi.decode(bridgeData, (address));
|
||||
|
||||
// Get the exchange for the token pair.
|
||||
IUniswapExchange exchange = _getUniswapExchangeForTokenPair(
|
||||
fromTokenAddress,
|
||||
toTokenAddress
|
||||
);
|
||||
|
||||
// Convert from WETH to a token.
|
||||
if (fromTokenAddress == address(WETH)) {
|
||||
// Unwrap the WETH.
|
||||
WETH.withdraw(sellAmount);
|
||||
// Buy as much of `toTokenAddress` token with ETH as possible
|
||||
boughtAmount = exchange.ethToTokenTransferInput{ value: sellAmount }(
|
||||
// Minimum buy amount.
|
||||
1,
|
||||
// Expires after this block.
|
||||
block.timestamp,
|
||||
// Recipient is `this`.
|
||||
address(this)
|
||||
);
|
||||
|
||||
// Convert from a token to WETH.
|
||||
} else if (toTokenAddress == address(WETH)) {
|
||||
// Grant the exchange an allowance.
|
||||
IERC20TokenV06(fromTokenAddress).approveIfBelow(
|
||||
address(exchange),
|
||||
sellAmount
|
||||
);
|
||||
// Buy as much ETH with `fromTokenAddress` token as possible.
|
||||
boughtAmount = exchange.tokenToEthSwapInput(
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
1,
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
// Wrap the ETH.
|
||||
WETH.deposit{ value: boughtAmount }();
|
||||
// Convert from one token to another.
|
||||
} else {
|
||||
// Grant the exchange an allowance.
|
||||
IERC20TokenV06(fromTokenAddress).approveIfBelow(
|
||||
address(exchange),
|
||||
sellAmount
|
||||
);
|
||||
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
|
||||
boughtAmount = exchange.tokenToTokenSwapInput(
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
1,
|
||||
// Must buy at least 1 intermediate wei of ETH.
|
||||
1,
|
||||
// Expires after this block.
|
||||
block.timestamp,
|
||||
// Convert to `toTokenAddress`.
|
||||
toTokenAddress
|
||||
);
|
||||
}
|
||||
|
||||
return boughtAmount;
|
||||
}
|
||||
|
||||
/// @dev Retrieves the uniswap exchange for a given token pair.
|
||||
/// In the case of a WETH-token exchange, this will be the non-WETH token.
|
||||
/// In th ecase of a token-token exchange, this will be the first token.
|
||||
/// @param fromTokenAddress The address of the token we are converting from.
|
||||
/// @param toTokenAddress The address of the token we are converting to.
|
||||
/// @return exchange The uniswap exchange.
|
||||
function _getUniswapExchangeForTokenPair(
|
||||
address fromTokenAddress,
|
||||
address toTokenAddress
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (IUniswapExchange exchange)
|
||||
{
|
||||
address exchangeTokenAddress = fromTokenAddress;
|
||||
// Whichever isn't WETH is the exchange token.
|
||||
if (fromTokenAddress == address(WETH)) {
|
||||
exchangeTokenAddress = toTokenAddress;
|
||||
}
|
||||
exchange = IUniswapExchange(UNISWAP_EXCHANGE_FACTORY.getExchange(exchangeTokenAddress));
|
||||
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
|
||||
return exchange;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "./MixinAdapterAddresses.sol";
|
||||
|
||||
/*
|
||||
UniswapV2
|
||||
*/
|
||||
interface IUniswapV2Router02 {
|
||||
|
||||
/// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
|
||||
/// The first element of path is the input token, the last is the output token, and any intermediate elements represent
|
||||
/// intermediate pairs to trade through (if, for example, a direct pair does not exist).
|
||||
/// @param amountIn The amount of input tokens to send.
|
||||
/// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
|
||||
/// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
|
||||
/// @param to Recipient of the output tokens.
|
||||
/// @param deadline Unix timestamp after which the transaction will revert.
|
||||
/// @return amounts The input token amount and all subsequent output token amounts.
|
||||
function swapExactTokensForTokens(
|
||||
uint amountIn,
|
||||
uint amountOutMin,
|
||||
address[] calldata path,
|
||||
address to,
|
||||
uint deadline
|
||||
) external returns (uint[] memory amounts);
|
||||
}
|
||||
|
||||
contract MixinUniswapV2 is
|
||||
MixinAdapterAddresses
|
||||
{
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
|
||||
/// @dev Mainnet address of the `UniswapV2Router02` contract.
|
||||
IUniswapV2Router02 private immutable UNISWAP_V2_ROUTER;
|
||||
|
||||
constructor(AdapterAddresses memory addresses)
|
||||
public
|
||||
{
|
||||
UNISWAP_V2_ROUTER = IUniswapV2Router02(addresses.uniswapV2Router);
|
||||
}
|
||||
|
||||
function _tradeUniswapV2(
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256)
|
||||
{
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
// solhint-disable indent
|
||||
address[] memory path = abi.decode(bridgeData, (address[]));
|
||||
// solhint-enable indent
|
||||
|
||||
require(path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
|
||||
require(path[path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
|
||||
// Grant the Uniswap router an allowance.
|
||||
IERC20TokenV06(path[0]).approveIfBelow(
|
||||
address(UNISWAP_V2_ROUTER),
|
||||
sellAmount
|
||||
);
|
||||
|
||||
uint[] memory amounts = UNISWAP_V2_ROUTER.swapExactTokensForTokens(
|
||||
// Sell all tokens we hold.
|
||||
sellAmount,
|
||||
// Minimum buy amount.
|
||||
1,
|
||||
// Convert `fromTokenAddress` to `toTokenAddress`.
|
||||
path,
|
||||
// Recipient is `this`.
|
||||
address(this),
|
||||
// Expires after this block.
|
||||
block.timestamp
|
||||
);
|
||||
return amounts[amounts.length-1];
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
|
||||
interface IERC20Bridge {
|
||||
|
||||
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
|
||||
/// @param tokenAddress The address of the ERC20 token to transfer.
|
||||
/// @param from Address to transfer asset from.
|
||||
/// @param to Address to transfer asset to.
|
||||
/// @param amount Amount of asset to transfer.
|
||||
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
|
||||
/// @return success The magic bytes `0xdc1600f3` if successful.
|
||||
function bridgeTransferFrom(
|
||||
address tokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success);
|
||||
}
|
||||
|
||||
contract MixinZeroExBridge {
|
||||
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibSafeMathV06 for uint256;
|
||||
|
||||
function _tradeZeroExBridge(
|
||||
address bridgeAddress,
|
||||
address fromTokenAddress,
|
||||
address toTokenAddress,
|
||||
uint256 sellAmount,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
internal
|
||||
returns (uint256 boughtAmount)
|
||||
{
|
||||
uint256 balanceBefore = IERC20TokenV06(toTokenAddress).balanceOf(address(this));
|
||||
// Trade the good old fashioned way
|
||||
IERC20TokenV06(fromTokenAddress).compatTransfer(
|
||||
bridgeAddress,
|
||||
sellAmount
|
||||
);
|
||||
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
|
||||
toTokenAddress,
|
||||
bridgeAddress,
|
||||
address(this),
|
||||
1, // amount to transfer back from the bridge
|
||||
bridgeData
|
||||
);
|
||||
|
||||
boughtAmount = IERC20TokenV06(toTokenAddress).balanceOf(address(this)).safeSub(balanceBefore);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2020 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.6.5;
|
||||
|
||||
import "../vendor/v3/IGasToken.sol";
|
||||
|
||||
contract FixinGasToken
|
||||
{
|
||||
/// @dev Mainnet address of the GST2 contract
|
||||
address constant private GST_ADDRESS = 0x0000000000b3F879cb30FE243b4Dfee438691c04;
|
||||
/// @dev Mainnet address of the GST Collector
|
||||
address constant private GST_COLLECTOR_ADDRESS = 0x000000D3b08566BE75A6DB803C03C85C0c1c5B96;
|
||||
|
||||
/// @dev Frees gas tokens using the balance of `from`. Amount freed is based
|
||||
/// on the gas consumed in the function
|
||||
modifier freesGasTokensFromCollector() {
|
||||
uint256 gasBefore = gasleft();
|
||||
_;
|
||||
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
|
||||
// 14154 24000 6870
|
||||
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
|
||||
GST_ADDRESS.call(
|
||||
abi.encodeWithSelector(
|
||||
IGasToken(address(0)).freeFromUpTo.selector,
|
||||
GST_COLLECTOR_ADDRESS,
|
||||
value
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -27,17 +27,14 @@ import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
|
||||
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
|
||||
import "../errors/LibTransformERC20RichErrors.sol";
|
||||
import "../vendor/v3/IExchange.sol";
|
||||
import "../vendor/v3/IERC20Bridge.sol";
|
||||
import "../bridges/IBridgeAdapter.sol";
|
||||
import "./Transformer.sol";
|
||||
import "./LibERC20Transformer.sol";
|
||||
import "../fixins/FixinGasToken.sol";
|
||||
|
||||
|
||||
/// @dev A transformer that fills an ERC20 market sell/buy quote.
|
||||
/// This transformer shortcuts bridge orders and fills them directly
|
||||
contract FillQuoteTransformer is
|
||||
Transformer,
|
||||
FixinGasToken
|
||||
Transformer
|
||||
{
|
||||
using LibERC20TokenV06 for IERC20TokenV06;
|
||||
using LibERC20Transformer for IERC20TokenV06;
|
||||
@ -116,15 +113,18 @@ contract FillQuoteTransformer is
|
||||
IExchange public immutable exchange;
|
||||
/// @dev The ERC20Proxy address.
|
||||
address public immutable erc20Proxy;
|
||||
/// @dev The BridgeAdapter address
|
||||
IBridgeAdapter public immutable bridgeAdapter;
|
||||
|
||||
/// @dev Create this contract.
|
||||
/// @param exchange_ The Exchange V3 instance.
|
||||
constructor(IExchange exchange_)
|
||||
constructor(IExchange exchange_, IBridgeAdapter bridgeAdapter_)
|
||||
public
|
||||
Transformer()
|
||||
{
|
||||
exchange = exchange_;
|
||||
erc20Proxy = exchange_.getAssetProxy(ERC20_ASSET_PROXY_ID);
|
||||
bridgeAdapter = bridgeAdapter_;
|
||||
}
|
||||
|
||||
/// @dev Sell this contract's entire balance of of `sellToken` in exchange
|
||||
@ -139,7 +139,6 @@ contract FillQuoteTransformer is
|
||||
)
|
||||
external
|
||||
override
|
||||
freesGasTokensFromCollector
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TransformData memory data = abi.decode(data_, (TransformData));
|
||||
@ -308,7 +307,6 @@ contract FillQuoteTransformer is
|
||||
signature,
|
||||
takerTokenFillAmount,
|
||||
state,
|
||||
makerToken,
|
||||
takerFeeToken == takerToken
|
||||
);
|
||||
}
|
||||
@ -372,7 +370,6 @@ contract FillQuoteTransformer is
|
||||
signature,
|
||||
takerTokenFillAmount,
|
||||
state,
|
||||
makerToken,
|
||||
takerFeeToken == takerToken
|
||||
);
|
||||
}
|
||||
@ -383,7 +380,6 @@ contract FillQuoteTransformer is
|
||||
/// @param signature The order signature.
|
||||
/// @param takerAssetFillAmount How much taker asset to fill.
|
||||
/// @param state Intermediate state variables to get around stack limits.
|
||||
/// @param makerToken The maker token.
|
||||
/// @param isTakerFeeInTakerToken Whether the taker fee token is the same as the
|
||||
/// taker token.
|
||||
function _fillOrder(
|
||||
@ -391,7 +387,6 @@ contract FillQuoteTransformer is
|
||||
bytes memory signature,
|
||||
uint256 takerAssetFillAmount,
|
||||
FillState memory state,
|
||||
IERC20TokenV06 makerToken,
|
||||
bool isTakerFeeInTakerToken
|
||||
)
|
||||
private
|
||||
@ -402,37 +397,23 @@ contract FillQuoteTransformer is
|
||||
takerAssetFillAmount.min256(order.takerAssetAmount);
|
||||
availableTakerAssetFillAmount =
|
||||
availableTakerAssetFillAmount.min256(state.takerTokenBalanceRemaining);
|
||||
// If it is a Bridge order we fill this directly
|
||||
// rather than filling via 0x Exchange
|
||||
|
||||
// If it is a Bridge order we fill this directly through the BridgeAdapter
|
||||
if (order.makerAssetData.readBytes4(0) == ERC20_BRIDGE_PROXY_ID) {
|
||||
// Calculate the amount (in maker token) we expect to receive
|
||||
// from the bridge
|
||||
uint256 outputTokenAmount = LibMathV06.getPartialAmountFloor(
|
||||
availableTakerAssetFillAmount,
|
||||
order.takerAssetAmount,
|
||||
order.makerAssetAmount
|
||||
);
|
||||
(bool success, bytes memory data) = address(_implementation).delegatecall(
|
||||
(bool success, bytes memory resultData) = address(bridgeAdapter).delegatecall(
|
||||
abi.encodeWithSelector(
|
||||
this.fillBridgeOrder.selector,
|
||||
order.makerAddress,
|
||||
IBridgeAdapter.trade.selector,
|
||||
order.makerAssetData,
|
||||
order.takerAssetData,
|
||||
availableTakerAssetFillAmount,
|
||||
outputTokenAmount
|
||||
address(_getTokenFromERC20AssetData(order.takerAssetData)),
|
||||
availableTakerAssetFillAmount
|
||||
)
|
||||
);
|
||||
// Swallow failures, leaving all results as zero.
|
||||
// TransformERC20 asserts the overall price is as expected. It is possible
|
||||
// a subsequent fill can net out at the expected price so we do not assert
|
||||
// the trade balance
|
||||
if (success) {
|
||||
results.makerTokenBoughtAmount = makerToken
|
||||
.balanceOf(address(this))
|
||||
.safeSub(state.boughtAmount);
|
||||
results.makerTokenBoughtAmount = abi.decode(resultData, (uint256));
|
||||
results.takerTokenSoldAmount = availableTakerAssetFillAmount;
|
||||
// protocol fee paid remains 0
|
||||
}
|
||||
return results;
|
||||
} else {
|
||||
// Emit an event if we do not have sufficient ETH to cover the protocol fee.
|
||||
if (state.ethRemaining < state.protocolFee) {
|
||||
@ -460,46 +441,6 @@ contract FillQuoteTransformer is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Attempt to fill an ERC20 Bridge order. If the fill reverts,
|
||||
/// or the amount filled was not sufficient this reverts.
|
||||
/// @param makerAddress The address of the maker.
|
||||
/// @param makerAssetData The encoded ERC20BridgeProxy asset data.
|
||||
/// @param takerAssetData The encoded ERC20 asset data.
|
||||
/// @param inputTokenAmount How much taker asset to fill clamped to the available balance.
|
||||
/// @param outputTokenAmount How much maker asset to receive.
|
||||
function fillBridgeOrder(
|
||||
address makerAddress,
|
||||
bytes calldata makerAssetData,
|
||||
bytes calldata takerAssetData,
|
||||
uint256 inputTokenAmount,
|
||||
uint256 outputTokenAmount
|
||||
)
|
||||
external
|
||||
{
|
||||
// Track changes in the maker token balance.
|
||||
(
|
||||
address tokenAddress,
|
||||
address bridgeAddress,
|
||||
bytes memory bridgeData
|
||||
) = abi.decode(
|
||||
makerAssetData.sliceDestructive(4, makerAssetData.length),
|
||||
(address, address, bytes)
|
||||
);
|
||||
require(bridgeAddress != address(this), "INVALID_BRIDGE_ADDRESS");
|
||||
// Transfer the tokens to the bridge to perform the work
|
||||
_getTokenFromERC20AssetData(takerAssetData).compatTransfer(
|
||||
bridgeAddress,
|
||||
inputTokenAmount
|
||||
);
|
||||
IERC20Bridge(bridgeAddress).bridgeTransferFrom(
|
||||
tokenAddress,
|
||||
makerAddress,
|
||||
address(this),
|
||||
outputTokenAmount, // amount to transfer back from the bridge
|
||||
bridgeData
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Extract the token from plain ERC20 asset data.
|
||||
/// If the asset-data is empty, a zero token address will be returned.
|
||||
/// @param assetData The order asset data.
|
||||
|
@ -29,6 +29,7 @@ contract TestFillQuoteTransformerBridge {
|
||||
struct FillBehavior {
|
||||
// Scaling for maker assets minted, in 1e18.
|
||||
uint256 makerAssetMintRatio;
|
||||
uint256 amount;
|
||||
}
|
||||
|
||||
bytes4 private constant ERC20_BRIDGE_PROXY_ID = 0xdc1600f3;
|
||||
@ -49,7 +50,7 @@ contract TestFillQuoteTransformerBridge {
|
||||
LibMathV06.getPartialAmountFloor(
|
||||
behavior.makerAssetMintRatio,
|
||||
1e18,
|
||||
amount
|
||||
behavior.amount
|
||||
)
|
||||
);
|
||||
return ERC20_BRIDGE_PROXY_ID;
|
||||
|
@ -39,9 +39,9 @@
|
||||
"publish:private": "yarn build && gitpkg publish"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20,FillQuoteTransformer,PayTakerTransformer,WethTransformer,Ownable,SimpleFunctionRegistry,TransformERC20,TokenSpender,AffiliateFeeTransformer,SignatureValidator,MetaTransactions",
|
||||
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20,FillQuoteTransformer,PayTakerTransformer,WethTransformer,Ownable,SimpleFunctionRegistry,TransformERC20,TokenSpender,AffiliateFeeTransformer,SignatureValidator,MetaTransactions,BridgeAdapter",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|Bootstrap|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinGasToken|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|IMetaTransactions|IOwnable|ISignatureValidator|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|MetaTransactions|Ownable|PayTakerTransformer|SignatureValidator|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|TransformerDeployer|WethTransformer|ZeroEx).json"
|
||||
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|AllowanceTarget|Bootstrap|BridgeAdapter|FillQuoteTransformer|FixinCommon|FixinEIP712|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IExchange|IFeature|IFlashWallet|IGasToken|IMetaTransactions|IOwnable|ISignatureValidator|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSignatureRichErrors|LibSignedCallData|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|MetaTransactions|MixinAdapterAddresses|MixinBalancer|MixinCurve|MixinKyber|MixinMStable|MixinOasis|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|Ownable|PayTakerTransformer|SignatureValidator|SimpleFunctionRegistry|TestCallTarget|TestDelegateCaller|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFullMigration|TestInitialMigration|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TokenSpender|TransformERC20|Transformer|TransformerDeployer|WethTransformer|ZeroEx).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as AffiliateFeeTransformer from '../generated-artifacts/AffiliateFeeTransformer.json';
|
||||
import * as BridgeAdapter from '../generated-artifacts/BridgeAdapter.json';
|
||||
import * as FillQuoteTransformer from '../generated-artifacts/FillQuoteTransformer.json';
|
||||
import * as FullMigration from '../generated-artifacts/FullMigration.json';
|
||||
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
|
||||
@ -48,4 +49,5 @@ export const artifacts = {
|
||||
AffiliateFeeTransformer: AffiliateFeeTransformer as ContractArtifact,
|
||||
SignatureValidator: SignatureValidator as ContractArtifact,
|
||||
MetaTransactions: MetaTransactions as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||
};
|
||||
|
@ -1,6 +1,40 @@
|
||||
export { ZeroExRevertErrors } from '@0x/utils';
|
||||
export {
|
||||
AbiDefinition,
|
||||
CompilerOpts,
|
||||
CompilerSettings,
|
||||
CompilerSettingsMetadata,
|
||||
ConstructorAbi,
|
||||
ConstructorStateMutability,
|
||||
ContractAbi,
|
||||
ContractArtifact,
|
||||
ContractChainData,
|
||||
ContractChains,
|
||||
DataItem,
|
||||
DevdocOutput,
|
||||
EventAbi,
|
||||
EventParameter,
|
||||
EvmBytecodeOutput,
|
||||
EvmBytecodeOutputLinkReferences,
|
||||
EvmOutput,
|
||||
FallbackAbi,
|
||||
FunctionAbi,
|
||||
MethodAbi,
|
||||
OptimizerSettings,
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
RevertErrorAbi,
|
||||
StandardContractOutput,
|
||||
StateMutability,
|
||||
TupleDataItem,
|
||||
} from 'ethereum-types';
|
||||
export { artifacts } from './artifacts';
|
||||
export * from './migration';
|
||||
export * from './nonce_utils';
|
||||
export * from './signed_call_data';
|
||||
export {
|
||||
AffiliateFeeTransformerContract,
|
||||
BridgeAdapterContract,
|
||||
FillQuoteTransformerContract,
|
||||
IOwnableContract,
|
||||
IOwnableEvents,
|
||||
@ -13,37 +47,3 @@ export {
|
||||
WethTransformerContract,
|
||||
ZeroExContract,
|
||||
} from './wrappers';
|
||||
export { ZeroExRevertErrors } from '@0x/utils';
|
||||
export {
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
CompilerOpts,
|
||||
StandardContractOutput,
|
||||
CompilerSettings,
|
||||
ContractChainData,
|
||||
ContractAbi,
|
||||
DevdocOutput,
|
||||
EvmOutput,
|
||||
CompilerSettingsMetadata,
|
||||
OptimizerSettings,
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
EvmBytecodeOutput,
|
||||
EvmBytecodeOutputLinkReferences,
|
||||
AbiDefinition,
|
||||
FunctionAbi,
|
||||
EventAbi,
|
||||
RevertErrorAbi,
|
||||
EventParameter,
|
||||
DataItem,
|
||||
MethodAbi,
|
||||
ConstructorAbi,
|
||||
FallbackAbi,
|
||||
ConstructorStateMutability,
|
||||
TupleDataItem,
|
||||
StateMutability,
|
||||
} from 'ethereum-types';
|
||||
|
||||
export * from './nonce_utils';
|
||||
export * from './migration';
|
||||
export * from './signed_call_data';
|
||||
|
@ -4,6 +4,7 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/affiliate_fee_transformer';
|
||||
export * from '../generated-wrappers/bridge_adapter';
|
||||
export * from '../generated-wrappers/fill_quote_transformer';
|
||||
export * from '../generated-wrappers/full_migration';
|
||||
export * from '../generated-wrappers/i_allowance_target';
|
||||
|
@ -8,14 +8,15 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
import * as AffiliateFeeTransformer from '../test/generated-artifacts/AffiliateFeeTransformer.json';
|
||||
import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.json';
|
||||
import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json';
|
||||
import * as BridgeAdapter from '../test/generated-artifacts/BridgeAdapter.json';
|
||||
import * as FillQuoteTransformer from '../test/generated-artifacts/FillQuoteTransformer.json';
|
||||
import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json';
|
||||
import * as FixinEIP712 from '../test/generated-artifacts/FixinEIP712.json';
|
||||
import * as FixinGasToken from '../test/generated-artifacts/FixinGasToken.json';
|
||||
import * as FlashWallet from '../test/generated-artifacts/FlashWallet.json';
|
||||
import * as FullMigration from '../test/generated-artifacts/FullMigration.json';
|
||||
import * as IAllowanceTarget from '../test/generated-artifacts/IAllowanceTarget.json';
|
||||
import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json';
|
||||
import * as IBridgeAdapter from '../test/generated-artifacts/IBridgeAdapter.json';
|
||||
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
|
||||
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
|
||||
import * as IExchange from '../test/generated-artifacts/IExchange.json';
|
||||
@ -52,6 +53,15 @@ import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTra
|
||||
import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json';
|
||||
import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json';
|
||||
import * as MetaTransactions from '../test/generated-artifacts/MetaTransactions.json';
|
||||
import * as MixinAdapterAddresses from '../test/generated-artifacts/MixinAdapterAddresses.json';
|
||||
import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json';
|
||||
import * as MixinCurve from '../test/generated-artifacts/MixinCurve.json';
|
||||
import * as MixinKyber from '../test/generated-artifacts/MixinKyber.json';
|
||||
import * as MixinMStable from '../test/generated-artifacts/MixinMStable.json';
|
||||
import * as MixinOasis from '../test/generated-artifacts/MixinOasis.json';
|
||||
import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json';
|
||||
import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json';
|
||||
import * as MixinZeroExBridge from '../test/generated-artifacts/MixinZeroExBridge.json';
|
||||
import * as Ownable from '../test/generated-artifacts/Ownable.json';
|
||||
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
|
||||
import * as SignatureValidator from '../test/generated-artifacts/SignatureValidator.json';
|
||||
@ -87,6 +97,17 @@ import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json';
|
||||
export const artifacts = {
|
||||
IZeroEx: IZeroEx as ContractArtifact,
|
||||
ZeroEx: ZeroEx as ContractArtifact,
|
||||
BridgeAdapter: BridgeAdapter as ContractArtifact,
|
||||
IBridgeAdapter: IBridgeAdapter as ContractArtifact,
|
||||
MixinAdapterAddresses: MixinAdapterAddresses as ContractArtifact,
|
||||
MixinBalancer: MixinBalancer as ContractArtifact,
|
||||
MixinCurve: MixinCurve as ContractArtifact,
|
||||
MixinKyber: MixinKyber as ContractArtifact,
|
||||
MixinMStable: MixinMStable as ContractArtifact,
|
||||
MixinOasis: MixinOasis as ContractArtifact,
|
||||
MixinUniswap: MixinUniswap as ContractArtifact,
|
||||
MixinUniswapV2: MixinUniswapV2 as ContractArtifact,
|
||||
MixinZeroExBridge: MixinZeroExBridge as ContractArtifact,
|
||||
LibCommonRichErrors: LibCommonRichErrors as ContractArtifact,
|
||||
LibMetaTransactionsRichErrors: LibMetaTransactionsRichErrors as ContractArtifact,
|
||||
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
|
||||
@ -119,7 +140,6 @@ export const artifacts = {
|
||||
LibSignedCallData: LibSignedCallData as ContractArtifact,
|
||||
FixinCommon: FixinCommon as ContractArtifact,
|
||||
FixinEIP712: FixinEIP712 as ContractArtifact,
|
||||
FixinGasToken: FixinGasToken as ContractArtifact,
|
||||
FullMigration: FullMigration as ContractArtifact,
|
||||
InitialMigration: InitialMigration as ContractArtifact,
|
||||
LibBootstrap: LibBootstrap as ContractArtifact,
|
||||
|
@ -20,6 +20,7 @@ import * as _ from 'lodash';
|
||||
import { artifacts } from '../artifacts';
|
||||
import { TestFillQuoteTransformerBridgeContract } from '../generated-wrappers/test_fill_quote_transformer_bridge';
|
||||
import {
|
||||
BridgeAdapterContract,
|
||||
FillQuoteTransformerContract,
|
||||
TestFillQuoteTransformerExchangeContract,
|
||||
TestFillQuoteTransformerHostContract,
|
||||
@ -50,12 +51,34 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const bridgeAdapter = await BridgeAdapterContract.deployFrom0xArtifactAsync(
|
||||
artifacts.BridgeAdapter,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
{
|
||||
balancerBridge: NULL_ADDRESS,
|
||||
curveBridge: NULL_ADDRESS,
|
||||
kyberBridge: NULL_ADDRESS,
|
||||
mStableBridge: NULL_ADDRESS,
|
||||
oasisBridge: NULL_ADDRESS,
|
||||
uniswapBridge: NULL_ADDRESS,
|
||||
uniswapV2Bridge: NULL_ADDRESS,
|
||||
kyberNetworkProxy: NULL_ADDRESS,
|
||||
oasis: NULL_ADDRESS,
|
||||
uniswapV2Router: NULL_ADDRESS,
|
||||
uniswapExchangeFactory: NULL_ADDRESS,
|
||||
mStable: NULL_ADDRESS,
|
||||
weth: NULL_ADDRESS,
|
||||
},
|
||||
);
|
||||
transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.FillQuoteTransformer,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
exchange.address,
|
||||
bridgeAdapter.address,
|
||||
);
|
||||
host = await TestFillQuoteTransformerHostContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestFillQuoteTransformerHost,
|
||||
@ -110,8 +133,9 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
};
|
||||
}
|
||||
|
||||
function createBridgeOrder(fields: Partial<Order> = {}, bridgeData: string = encodeBridgeBehavior()): FilledOrder {
|
||||
function createBridgeOrder(fields: Partial<Order> = {}, fillRatio: Numberish = 1.0): FilledOrder {
|
||||
const order = createOrder(fields);
|
||||
const bridgeData = encodeBridgeBehavior(order.makerAssetAmount, fillRatio);
|
||||
return {
|
||||
...order,
|
||||
makerAddress: bridge.address,
|
||||
@ -265,11 +289,12 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
);
|
||||
}
|
||||
|
||||
function encodeBridgeBehavior(makerAssetMintRatio: Numberish = 1.0): string {
|
||||
function encodeBridgeBehavior(amount: BigNumber, makerAssetMintRatio: Numberish = 1.0): string {
|
||||
return hexUtils.slice(
|
||||
bridge
|
||||
.encodeBehaviorData({
|
||||
makerAssetMintRatio: new BigNumber(makerAssetMintRatio).times('1e18').integerValue(),
|
||||
amount,
|
||||
})
|
||||
.getABIEncodedTransactionData(),
|
||||
4,
|
||||
@ -865,7 +890,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('bridge orders', () => {
|
||||
describe('bridge orders fall through', () => {
|
||||
it('can fully sell to a single bridge order quote', async () => {
|
||||
const orders = _.times(1, () => createBridgeOrder());
|
||||
const signatures = orders.map(() => NULL_BYTES);
|
||||
|
@ -6,14 +6,15 @@
|
||||
export * from '../test/generated-wrappers/affiliate_fee_transformer';
|
||||
export * from '../test/generated-wrappers/allowance_target';
|
||||
export * from '../test/generated-wrappers/bootstrap';
|
||||
export * from '../test/generated-wrappers/bridge_adapter';
|
||||
export * from '../test/generated-wrappers/fill_quote_transformer';
|
||||
export * from '../test/generated-wrappers/fixin_common';
|
||||
export * from '../test/generated-wrappers/fixin_e_i_p712';
|
||||
export * from '../test/generated-wrappers/fixin_gas_token';
|
||||
export * from '../test/generated-wrappers/flash_wallet';
|
||||
export * from '../test/generated-wrappers/full_migration';
|
||||
export * from '../test/generated-wrappers/i_allowance_target';
|
||||
export * from '../test/generated-wrappers/i_bootstrap';
|
||||
export * from '../test/generated-wrappers/i_bridge_adapter';
|
||||
export * from '../test/generated-wrappers/i_erc20_bridge';
|
||||
export * from '../test/generated-wrappers/i_erc20_transformer';
|
||||
export * from '../test/generated-wrappers/i_exchange';
|
||||
@ -50,6 +51,15 @@ export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors';
|
||||
export * from '../test/generated-wrappers/lib_transform_erc20_storage';
|
||||
export * from '../test/generated-wrappers/lib_wallet_rich_errors';
|
||||
export * from '../test/generated-wrappers/meta_transactions';
|
||||
export * from '../test/generated-wrappers/mixin_adapter_addresses';
|
||||
export * from '../test/generated-wrappers/mixin_balancer';
|
||||
export * from '../test/generated-wrappers/mixin_curve';
|
||||
export * from '../test/generated-wrappers/mixin_kyber';
|
||||
export * from '../test/generated-wrappers/mixin_m_stable';
|
||||
export * from '../test/generated-wrappers/mixin_oasis';
|
||||
export * from '../test/generated-wrappers/mixin_uniswap';
|
||||
export * from '../test/generated-wrappers/mixin_uniswap_v2';
|
||||
export * from '../test/generated-wrappers/mixin_zero_ex_bridge';
|
||||
export * from '../test/generated-wrappers/ownable';
|
||||
export * from '../test/generated-wrappers/pay_taker_transformer';
|
||||
export * from '../test/generated-wrappers/signature_validator';
|
||||
|
@ -4,6 +4,7 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/AffiliateFeeTransformer.json",
|
||||
"generated-artifacts/BridgeAdapter.json",
|
||||
"generated-artifacts/FillQuoteTransformer.json",
|
||||
"generated-artifacts/FullMigration.json",
|
||||
"generated-artifacts/IAllowanceTarget.json",
|
||||
@ -27,14 +28,15 @@
|
||||
"test/generated-artifacts/AffiliateFeeTransformer.json",
|
||||
"test/generated-artifacts/AllowanceTarget.json",
|
||||
"test/generated-artifacts/Bootstrap.json",
|
||||
"test/generated-artifacts/BridgeAdapter.json",
|
||||
"test/generated-artifacts/FillQuoteTransformer.json",
|
||||
"test/generated-artifacts/FixinCommon.json",
|
||||
"test/generated-artifacts/FixinEIP712.json",
|
||||
"test/generated-artifacts/FixinGasToken.json",
|
||||
"test/generated-artifacts/FlashWallet.json",
|
||||
"test/generated-artifacts/FullMigration.json",
|
||||
"test/generated-artifacts/IAllowanceTarget.json",
|
||||
"test/generated-artifacts/IBootstrap.json",
|
||||
"test/generated-artifacts/IBridgeAdapter.json",
|
||||
"test/generated-artifacts/IERC20Bridge.json",
|
||||
"test/generated-artifacts/IERC20Transformer.json",
|
||||
"test/generated-artifacts/IExchange.json",
|
||||
@ -71,6 +73,15 @@
|
||||
"test/generated-artifacts/LibTransformERC20Storage.json",
|
||||
"test/generated-artifacts/LibWalletRichErrors.json",
|
||||
"test/generated-artifacts/MetaTransactions.json",
|
||||
"test/generated-artifacts/MixinAdapterAddresses.json",
|
||||
"test/generated-artifacts/MixinBalancer.json",
|
||||
"test/generated-artifacts/MixinCurve.json",
|
||||
"test/generated-artifacts/MixinKyber.json",
|
||||
"test/generated-artifacts/MixinMStable.json",
|
||||
"test/generated-artifacts/MixinOasis.json",
|
||||
"test/generated-artifacts/MixinUniswap.json",
|
||||
"test/generated-artifacts/MixinUniswapV2.json",
|
||||
"test/generated-artifacts/MixinZeroExBridge.json",
|
||||
"test/generated-artifacts/Ownable.json",
|
||||
"test/generated-artifacts/PayTakerTransformer.json",
|
||||
"test/generated-artifacts/SignatureValidator.json",
|
||||
|
@ -51,7 +51,7 @@
|
||||
"lint:contracts": "wsrun lint -p ${npm_package_config_contractsPackages} -c --fast-exit --stages --exclude-missing"
|
||||
},
|
||||
"config": {
|
||||
"contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc20-bridge-sampler @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler @0x/contracts-broker @0x/contracts-zero-ex",
|
||||
"contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator @0x/contracts-broker @0x/contracts-zero-ex",
|
||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic",
|
||||
"packagesWithDocPages": "0x.js @0x/contract-wrappers @0x/connect @0x/json-schemas @0x/subproviders @0x/web3-wrapper @0x/order-utils @0x/sol-compiler @0x/sol-coverage @0x/sol-profiler @0x/sol-trace @0x/dev-utils @0x/asset-swapper @0x/migrations @0x/orderbook @0x/contracts-asset-proxy @0x/contracts-coordinator @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-extensions @0x/contracts-staking @0x/contracts-zero-ex",
|
||||
"ignoreDependencyVersions": "@types/styled-components @types/node",
|
||||
|
2
packages/asset-swapper/.gitignore
vendored
Normal file
2
packages/asset-swapper/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
**/generated-artifacts
|
||||
**/generated-wrappers
|
@ -3,6 +3,8 @@
|
||||
*
|
||||
# Whitelist lib
|
||||
!lib/**/*
|
||||
# Whitelist Solidity contracts
|
||||
!contracts/src/**/*
|
||||
# Blacklist tests and publish scripts
|
||||
/lib/test/*
|
||||
/lib/monorepo_scripts/
|
||||
|
21
packages/asset-swapper/.solhint.json
Normal file
21
packages/asset-swapper/.solhint.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"extends": "default",
|
||||
"rules": {
|
||||
"avoid-low-level-calls": false,
|
||||
"avoid-tx-origin": "warn",
|
||||
"bracket-align": false,
|
||||
"code-complexity": false,
|
||||
"compiler-fixed": false,
|
||||
"const-name-snakecase": "error",
|
||||
"expression-indent": "error",
|
||||
"function-max-lines": false,
|
||||
"func-order": "error",
|
||||
"indent": ["error", 4],
|
||||
"max-line-length": ["warn", 160],
|
||||
"no-inline-assembly": false,
|
||||
"quotes": ["error", "double"],
|
||||
"separate-by-one-line-in-contract": "error",
|
||||
"space-after-comma": "error",
|
||||
"statement-indent": "error"
|
||||
}
|
||||
}
|
@ -45,6 +45,14 @@
|
||||
{
|
||||
"note": "Adjust fill by ethToInputRate when ethToOutputRate is 0",
|
||||
"pr": 2660
|
||||
},
|
||||
{
|
||||
"note": "Added `mStable`",
|
||||
"pr": 2662
|
||||
},
|
||||
{
|
||||
"note": "Merge `erc20-bridge-sampler` into this package",
|
||||
"pr": 2664
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -24,20 +24,22 @@ import "./Eth2DaiSampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
import "./MultiBridgeSampler.sol";
|
||||
import "./MStableSampler.sol";
|
||||
import "./NativeOrderSampler.sol";
|
||||
import "./UniswapSampler.sol";
|
||||
import "./UniswapV2Sampler.sol";
|
||||
|
||||
|
||||
contract ERC20BridgeSampler is
|
||||
Eth2DaiSampler,
|
||||
UniswapSampler,
|
||||
KyberSampler,
|
||||
CurveSampler,
|
||||
Eth2DaiSampler,
|
||||
KyberSampler,
|
||||
LiquidityProviderSampler,
|
||||
UniswapV2Sampler,
|
||||
MStableSampler,
|
||||
MultiBridgeSampler,
|
||||
NativeOrderSampler
|
||||
NativeOrderSampler,
|
||||
UniswapSampler,
|
||||
UniswapV2Sampler
|
||||
{
|
||||
/// @dev Call multiple public functions on this contract in a single transaction.
|
||||
/// @param callDatas ABI-encoded call data for each function call.
|
||||
@ -49,6 +51,9 @@ contract ERC20BridgeSampler is
|
||||
{
|
||||
callResults = new bytes[](callDatas.length);
|
||||
for (uint256 i = 0; i != callDatas.length; ++i) {
|
||||
if (callDatas[i].length == 0) {
|
||||
continue;
|
||||
}
|
||||
(bool didSucceed, bytes memory resultData) = address(this).staticcall(callDatas[i]);
|
||||
if (!didSucceed) {
|
||||
assembly { revert(add(resultData, 0x20), mload(resultData)) }
|
32
packages/asset-swapper/contracts/src/IMStable.sol
Normal file
32
packages/asset-swapper/contracts/src/IMStable.sol
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
interface IMStable {
|
||||
|
||||
function getSwapOutput(
|
||||
address _input,
|
||||
address _output,
|
||||
uint256 _quantity
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bool, string memory, uint256 output);
|
||||
}
|
@ -127,6 +127,9 @@ contract LiquidityProviderSampler is
|
||||
view
|
||||
returns (address providerAddress)
|
||||
{
|
||||
if (registryAddress == address(0)) {
|
||||
return address(0);
|
||||
}
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
ILiquidityProviderRegistry(0).getLiquidityProviderForMarket.selector,
|
||||
takerToken,
|
126
packages/asset-swapper/contracts/src/MStableSampler.sol
Normal file
126
packages/asset-swapper/contracts/src/MStableSampler.sol
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "./IMStable.sol";
|
||||
import "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
contract MStableSampler is
|
||||
DeploymentConstants,
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
/// @dev Default gas limit for mStable calls.
|
||||
uint256 constant private DEFAULT_CALL_GAS = 800e3; // 800k
|
||||
|
||||
/// @dev Sample sell quotes from the mStable mUSD contract
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||
/// amount.
|
||||
function sampleSellsFromMStable(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
// Initialize array of maker token amounts.
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
address(_getMUsdAddress()).staticcall.gas(DEFAULT_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IMStable(0).getSwapOutput.selector,
|
||||
takerToken,
|
||||
makerToken,
|
||||
takerTokenAmounts[i]
|
||||
));
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
(, , buyAmount) = abi.decode(resultData, (bool, string, uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from MStable mUSD contract
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromMStable(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
return _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken),
|
||||
takerTokenData: abi.encode(takerToken),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromMStable
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromMStable(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory makerTokenData,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 buyAmount)
|
||||
{
|
||||
(address takerToken) =
|
||||
abi.decode(takerTokenData, (address));
|
||||
(address makerToken) =
|
||||
abi.decode(makerTokenData, (address));
|
||||
(bool success, bytes memory resultData) =
|
||||
address(this).staticcall(abi.encodeWithSelector(
|
||||
this.sampleSellsFromMStable.selector,
|
||||
takerToken,
|
||||
makerToken,
|
||||
_toSingleValueArray(sellAmount)
|
||||
));
|
||||
if (!success) {
|
||||
return 0;
|
||||
}
|
||||
// solhint-disable-next-line indent
|
||||
return abi.decode(resultData, (uint256[]))[0];
|
||||
}
|
||||
}
|
205
packages/asset-swapper/contracts/src/NativeOrderSampler.sol
Normal file
205
packages/asset-swapper/contracts/src/NativeOrderSampler.sol
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
|
||||
|
||||
contract NativeOrderSampler {
|
||||
using LibSafeMath for uint256;
|
||||
using LibBytes for bytes;
|
||||
|
||||
/// @dev The Exchange ERC20Proxy ID.
|
||||
bytes4 private constant ERC20_ASSET_PROXY_ID = 0xf47261b0;
|
||||
/// @dev Gas limit for calls to `getOrderFillableTakerAmount()`.
|
||||
uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// maker/taker asset amounts (returning 0).
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param exchange The V3 exchange.
|
||||
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableTakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
IExchange exchange
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableTakerAssetAmounts)
|
||||
{
|
||||
orderFillableTakerAssetAmounts = new uint256[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// solhint-disable indent
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
address(this)
|
||||
.staticcall
|
||||
.gas(DEFAULT_CALL_GAS)
|
||||
(abi.encodeWithSelector(
|
||||
this.getOrderFillableTakerAmount.selector,
|
||||
orders[i],
|
||||
orderSignatures[i],
|
||||
exchange
|
||||
));
|
||||
// solhint-enable indent
|
||||
orderFillableTakerAssetAmounts[i] = didSucceed
|
||||
? abi.decode(resultData, (uint256))
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Queries the fillable taker asset amounts of native orders.
|
||||
/// Effectively ignores orders that have empty signatures or
|
||||
/// @param orders Native orders to query.
|
||||
/// @param orderSignatures Signatures for each respective order in `orders`.
|
||||
/// @param exchange The V3 exchange.
|
||||
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
|
||||
/// by each order in `orders`.
|
||||
function getOrderFillableMakerAssetAmounts(
|
||||
LibOrder.Order[] memory orders,
|
||||
bytes[] memory orderSignatures,
|
||||
IExchange exchange
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory orderFillableMakerAssetAmounts)
|
||||
{
|
||||
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
|
||||
orders,
|
||||
orderSignatures,
|
||||
exchange
|
||||
);
|
||||
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
|
||||
// convert them to maker asset amounts.
|
||||
for (uint256 i = 0; i < orders.length; ++i) {
|
||||
if (orderFillableMakerAssetAmounts[i] != 0) {
|
||||
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
|
||||
orderFillableMakerAssetAmounts[i],
|
||||
orders[i].takerAssetAmount,
|
||||
orders[i].makerAssetAmount
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Get the fillable taker amount of an order, taking into account
|
||||
/// order state, maker fees, and maker balances.
|
||||
function getOrderFillableTakerAmount(
|
||||
LibOrder.Order memory order,
|
||||
bytes memory signature,
|
||||
IExchange exchange
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (uint256 fillableTakerAmount)
|
||||
{
|
||||
if (signature.length == 0 ||
|
||||
order.makerAssetAmount == 0 ||
|
||||
order.takerAssetAmount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LibOrder.OrderInfo memory orderInfo = exchange.getOrderInfo(order);
|
||||
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
|
||||
return 0;
|
||||
}
|
||||
if (!exchange.isValidHashSignature(orderInfo.orderHash, order.makerAddress, signature)) {
|
||||
return 0;
|
||||
}
|
||||
address spender = exchange.getAssetProxy(ERC20_ASSET_PROXY_ID);
|
||||
IERC20Token makerToken = _getTokenFromERC20AssetData(order.makerAssetData);
|
||||
if (makerToken == IERC20Token(0)) {
|
||||
return 0;
|
||||
}
|
||||
IERC20Token makerFeeToken = order.makerFee > 0
|
||||
? _getTokenFromERC20AssetData(order.makerFeeAssetData)
|
||||
: IERC20Token(0);
|
||||
uint256 remainingTakerAmount = order.takerAssetAmount
|
||||
.safeSub(orderInfo.orderTakerAssetFilledAmount);
|
||||
fillableTakerAmount = remainingTakerAmount;
|
||||
// The total fillable maker amount is the remaining fillable maker amount
|
||||
// PLUS maker fees, if maker fees are denominated in the maker token.
|
||||
uint256 totalFillableMakerAmount = LibMath.safeGetPartialAmountFloor(
|
||||
remainingTakerAmount,
|
||||
order.takerAssetAmount,
|
||||
makerFeeToken == makerToken
|
||||
? order.makerAssetAmount.safeAdd(order.makerFee)
|
||||
: order.makerAssetAmount
|
||||
);
|
||||
// The spendable amount of maker tokens (by the maker) is the lesser of
|
||||
// the maker's balance and the allowance they've granted to the ERC20Proxy.
|
||||
uint256 spendableMakerAmount = LibSafeMath.min256(
|
||||
makerToken.balanceOf(order.makerAddress),
|
||||
makerToken.allowance(order.makerAddress, spender)
|
||||
);
|
||||
// Scale the fillable taker amount by the ratio of the maker's
|
||||
// spendable maker amount over the total fillable maker amount.
|
||||
if (spendableMakerAmount < totalFillableMakerAmount) {
|
||||
fillableTakerAmount = LibMath.getPartialAmountCeil(
|
||||
spendableMakerAmount,
|
||||
totalFillableMakerAmount,
|
||||
remainingTakerAmount
|
||||
);
|
||||
}
|
||||
// If the maker fee is denominated in another token, constrain
|
||||
// the fillable taker amount by how much the maker can pay of that token.
|
||||
if (makerFeeToken != makerToken && makerFeeToken != IERC20Token(0)) {
|
||||
uint256 spendableExtraMakerFeeAmount = LibSafeMath.min256(
|
||||
makerFeeToken.balanceOf(order.makerAddress),
|
||||
makerFeeToken.allowance(order.makerAddress, spender)
|
||||
);
|
||||
if (spendableExtraMakerFeeAmount < order.makerFee) {
|
||||
fillableTakerAmount = LibSafeMath.min256(
|
||||
fillableTakerAmount,
|
||||
LibMath.getPartialAmountCeil(
|
||||
spendableExtraMakerFeeAmount,
|
||||
order.makerFee,
|
||||
remainingTakerAmount
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _getTokenFromERC20AssetData(bytes memory assetData)
|
||||
private
|
||||
pure
|
||||
returns (IERC20Token token)
|
||||
{
|
||||
if (assetData.length == 0) {
|
||||
return IERC20Token(address(0));
|
||||
}
|
||||
if (assetData.length != 36 ||
|
||||
assetData.readBytes4(0) != ERC20_ASSET_PROXY_ID)
|
||||
{
|
||||
return IERC20Token(address(0));
|
||||
}
|
||||
return IERC20Token(assetData.readAddress(16));
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "../src/ERC20BridgeSampler.sol";
|
||||
import "../src/IEth2Dai.sol";
|
||||
import "../src/IDevUtils.sol";
|
||||
import "../src/IKyberNetworkProxy.sol";
|
||||
import "../src/IUniswapV2Router01.sol";
|
||||
|
||||
@ -477,33 +476,17 @@ contract TestERC20BridgeSampler is
|
||||
uniswap.createTokenExchanges(tokenAddresses);
|
||||
}
|
||||
|
||||
// `IDevUtils.getOrderRelevantState()`, overridden to return deterministic
|
||||
// states.
|
||||
function getOrderRelevantState(
|
||||
// Overridden to return deterministic states.
|
||||
function getOrderFillableTakerAmount(
|
||||
LibOrder.Order memory order,
|
||||
bytes memory
|
||||
bytes memory,
|
||||
IExchange
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
LibOrder.OrderInfo memory orderInfo,
|
||||
uint256 fillableTakerAssetAmount,
|
||||
bool isValidSignature
|
||||
)
|
||||
view
|
||||
returns (uint256 fillableTakerAmount)
|
||||
{
|
||||
// The order hash is just the hash of the salt.
|
||||
bytes32 orderHash = keccak256(abi.encode(order.salt));
|
||||
// Everything else is derived from the hash.
|
||||
orderInfo.orderHash = orderHash;
|
||||
if (uint256(orderHash) % 100 > 90) {
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
|
||||
} else {
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
|
||||
}
|
||||
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
|
||||
fillableTakerAssetAmount =
|
||||
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
|
||||
isValidSignature = uint256(orderHash) % 2 == 1;
|
||||
return uint256(keccak256(abi.encode(order.salt))) % order.takerAssetAmount;
|
||||
}
|
||||
|
||||
// Overriden to return deterministic decimals.
|
109
packages/asset-swapper/contracts/test/TestNativeOrderSampler.sol
Normal file
109
packages/asset-swapper/contracts/test/TestNativeOrderSampler.sol
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
import "../src/NativeOrderSampler.sol";
|
||||
|
||||
|
||||
contract TestNativeOrderSamplerToken {
|
||||
mapping (address => uint256) public balanceOf;
|
||||
mapping (address => mapping(address => uint256)) public allowance;
|
||||
|
||||
function setBalanceAndAllowance(
|
||||
address owner,
|
||||
address spender,
|
||||
uint256 balance,
|
||||
uint256 allowance_
|
||||
)
|
||||
external
|
||||
{
|
||||
balanceOf[owner] = balance;
|
||||
allowance[owner][spender] = allowance_;
|
||||
}
|
||||
}
|
||||
|
||||
contract TestNativeOrderSampler is
|
||||
NativeOrderSampler
|
||||
{
|
||||
uint8 private constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED) + 1;
|
||||
bytes32 private constant VALID_SIGNATURE_HASH = keccak256(hex"01");
|
||||
|
||||
function createTokens(uint256 count)
|
||||
external
|
||||
returns (TestNativeOrderSamplerToken[] memory tokens)
|
||||
{
|
||||
tokens = new TestNativeOrderSamplerToken[](count);
|
||||
for (uint256 i = 0; i < count; ++i) {
|
||||
tokens[i] = new TestNativeOrderSamplerToken();
|
||||
}
|
||||
}
|
||||
|
||||
function setTokenBalanceAndAllowance(
|
||||
TestNativeOrderSamplerToken token,
|
||||
address owner,
|
||||
address spender,
|
||||
uint256 balance,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
{
|
||||
token.setBalanceAndAllowance(owner, spender, balance, allowance);
|
||||
}
|
||||
|
||||
// IExchange.getAssetProxy()
|
||||
function getAssetProxy(bytes4 proxyId)
|
||||
public
|
||||
pure
|
||||
returns (address)
|
||||
{
|
||||
return address(uint160(uint256(keccak256(abi.encode(proxyId)))));
|
||||
}
|
||||
|
||||
// IExchange.getOrderInfo()
|
||||
function getOrderInfo(LibOrder.Order calldata order)
|
||||
external
|
||||
pure
|
||||
returns (LibOrder.OrderInfo memory orderInfo)
|
||||
{
|
||||
// The order salt determines everything.
|
||||
orderInfo.orderHash = keccak256(abi.encode(order.salt));
|
||||
if (uint8(order.salt) == 0xFF) {
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
|
||||
} else {
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
|
||||
}
|
||||
// The expiration time is the filled taker asset amount.
|
||||
orderInfo.orderTakerAssetFilledAmount = order.expirationTimeSeconds;
|
||||
}
|
||||
|
||||
// IExchange.isValidSignature()
|
||||
function isValidHashSignature(
|
||||
bytes32,
|
||||
address,
|
||||
bytes calldata signature
|
||||
)
|
||||
external
|
||||
pure
|
||||
returns (bool isValid)
|
||||
{
|
||||
return keccak256(signature) == VALID_SIGNATURE_HASH;
|
||||
}
|
||||
}
|
@ -8,26 +8,35 @@
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "yarn tsc -b",
|
||||
"build": "yarn pre_build && tsc -b",
|
||||
"watch": "tsc -w -p tsconfig.json",
|
||||
"build:ci": "yarn build",
|
||||
"lint": "tslint --format stylish --project . && yarn prettier --check",
|
||||
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
|
||||
"compile": "sol-compiler",
|
||||
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"lint-contracts": "#solhint -c .solhint.json contracts/**/**/**/**/*.sol",
|
||||
"prettier": "prettier '**/*.{ts,tsx,json,md}' --config ../../.prettierrc --ignore-path ../../.prettierignore",
|
||||
"fix": "tslint --fix --format stylish --project . && yarn prettier --write",
|
||||
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
|
||||
"test": "yarn run_mocha",
|
||||
"rebuild_and_test": "run-s clean build test",
|
||||
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
|
||||
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
|
||||
"test:circleci": "yarn test:coverage",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 30000 --bail --exit",
|
||||
"clean": "shx rm -rf lib test_temp generated_docs",
|
||||
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*_test.js' lib/test/global_hooks.js --timeout 30000 --bail --exit",
|
||||
"clean": "shx rm -rf lib test_temp generated_docs test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
|
||||
"diff_docs": "git diff --exit-code ./docs",
|
||||
"s3:sync_md_docs": "aws s3 sync ./docs s3://docs-markdown/${npm_package_name}/v${npm_package_version} --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES",
|
||||
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
|
||||
"contracts:gen": "contracts-gen generate",
|
||||
"contracts:copy": "contracts-gen copy",
|
||||
"publish:private": "yarn build && gitpkg publish"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "ERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|ICurve|IEth2Dai|IKyberHintHandler|IKyberNetwork|IKyberNetworkProxy|IKyberStorage|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMultiBridge|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|TestERC20BridgeSampler|TestNativeOrderSampler|UniswapSampler|UniswapV2Sampler).json",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
@ -47,34 +56,43 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.9",
|
||||
"@0x/base-contract": "^6.2.3",
|
||||
"@0x/contract-addresses": "^4.11.0",
|
||||
"@0x/contract-artifacts": "^3.7.1",
|
||||
"@0x/contract-wrappers": "^13.8.0",
|
||||
"@0x/json-schemas": "^5.1.0",
|
||||
"@0x/order-utils": "^10.3.0",
|
||||
"@0x/orderbook": "^2.2.7",
|
||||
"@0x/quote-server": "^2.0.2",
|
||||
"@0x/types": "^3.2.0",
|
||||
"@0x/typescript-typings": "^5.1.1",
|
||||
"@0x/utils": "^5.5.1",
|
||||
"@0x/web3-wrapper": "^7.2.0",
|
||||
"@balancer-labs/sor": "0.3.2",
|
||||
"axios": "^0.19.2",
|
||||
"axios-mock-adapter": "^1.18.1",
|
||||
"decimal.js": "^10.2.0",
|
||||
"ethereum-types": "^3.2.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"heartbeats": "^5.0.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0x/base-contract": "^6.2.3",
|
||||
"@0x/contracts-asset-proxy": "^3.4.0",
|
||||
"@0x/contracts-erc20": "^3.2.1",
|
||||
"@0x/contracts-exchange": "^3.2.7",
|
||||
"@0x/contracts-exchange-libs": "^4.3.7",
|
||||
"@0x/contracts-gen": "^2.0.10",
|
||||
"@0x/contracts-test-utils": "^5.3.4",
|
||||
"@0x/contracts-utils": "^4.5.1",
|
||||
"@0x/dev-utils": "^3.3.0",
|
||||
"@0x/mesh-rpc-client": "^7.0.4-beta-0xv3",
|
||||
"@0x/migrations": "^6.4.0",
|
||||
"@0x/sol-compiler": "^4.1.1",
|
||||
"@0x/subproviders": "^6.1.1",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.1.0",
|
||||
"@0x/types": "^3.2.0",
|
||||
"@0x/typescript-typings": "^5.1.1",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@ -82,7 +100,6 @@
|
||||
"chai-as-promised": "^7.1.0",
|
||||
"chai-bignumber": "^3.0.0",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"ethereum-types": "^3.2.0",
|
||||
"gitpkg": "https://github.com/0xProject/gitpkg.git",
|
||||
"make-promises-safe": "^1.1.0",
|
||||
"mocha": "^6.2.0",
|
||||
|
@ -13,21 +13,57 @@ export {
|
||||
SRAWebsocketOrderProviderOpts,
|
||||
} from '@0x/orderbook';
|
||||
export { RFQTFirmQuote, RFQTIndicativeQuote } from '@0x/quote-server';
|
||||
export { APIOrder, Asset, AssetPairsItem, SignedOrder } from '@0x/types';
|
||||
export { BigNumber } from '@0x/utils';
|
||||
export {
|
||||
APIOrder,
|
||||
Asset,
|
||||
AssetPairsItem,
|
||||
DecodedLogEvent,
|
||||
EventCallback,
|
||||
IndexedFilterValues,
|
||||
SignedOrder,
|
||||
} from '@0x/types';
|
||||
export { BigNumber } from '@0x/utils';
|
||||
export { AxiosInstance } from 'axios';
|
||||
export {
|
||||
AbiDefinition,
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
CompilerOpts,
|
||||
CompilerSettings,
|
||||
CompilerSettingsMetadata,
|
||||
ConstructorAbi,
|
||||
ConstructorStateMutability,
|
||||
ContractAbi,
|
||||
ContractArtifact,
|
||||
ContractChainData,
|
||||
ContractChains,
|
||||
ContractEventArg,
|
||||
DataItem,
|
||||
DecodedLogArgs,
|
||||
DevdocOutput,
|
||||
EIP1193Event,
|
||||
EIP1193Provider,
|
||||
EventAbi,
|
||||
EventParameter,
|
||||
EvmBytecodeOutput,
|
||||
EvmBytecodeOutputLinkReferences,
|
||||
EvmOutput,
|
||||
FallbackAbi,
|
||||
FunctionAbi,
|
||||
GanacheProvider,
|
||||
GethCallOverrides,
|
||||
JSONRPCErrorCallback,
|
||||
JSONRPCRequestPayload,
|
||||
JSONRPCResponseError,
|
||||
JSONRPCResponsePayload,
|
||||
LogWithDecodedArgs,
|
||||
MethodAbi,
|
||||
OptimizerSettings,
|
||||
OutputField,
|
||||
ParamDescription,
|
||||
RevertErrorAbi,
|
||||
StandardContractOutput,
|
||||
StateMutability,
|
||||
SupportedProvider,
|
||||
TupleDataItem,
|
||||
Web3JsProvider,
|
||||
@ -36,6 +72,7 @@ export {
|
||||
Web3JsV3Provider,
|
||||
ZeroExProvider,
|
||||
} from 'ethereum-types';
|
||||
export { artifacts } from './artifacts';
|
||||
export { InsufficientAssetLiquidityError } from './errors';
|
||||
export { SwapQuoteConsumer } from './quote_consumers/swap_quote_consumer';
|
||||
export { SwapQuoter } from './swap_quoter';
|
||||
@ -99,7 +136,6 @@ export {
|
||||
} from './utils/quote_report_generator';
|
||||
export { QuoteRequestor } from './utils/quote_requestor';
|
||||
export { rfqtMocker } from './utils/rfqt_mocker';
|
||||
export { ERC20BridgeSamplerContract } from './wrappers';
|
||||
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
|
||||
export type Native = ERC20BridgeSource.Native;
|
||||
|
||||
export { AxiosInstance } from 'axios';
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
|
||||
import { ERC20BridgeSampler } from '@0x/contract-artifacts';
|
||||
import { DevUtilsContract, ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
|
||||
import { DevUtilsContract } from '@0x/contract-wrappers';
|
||||
import { schemas } from '@0x/json-schemas';
|
||||
import { assetDataUtils, SignedOrder } from '@0x/order-utils';
|
||||
import { MeshOrderProviderOpts, Orderbook, SRAPollingOrderProviderOpts } from '@0x/orderbook';
|
||||
@ -8,6 +7,7 @@ import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { BlockParamLiteral, SupportedProvider, ZeroExProvider } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { constants } from './constants';
|
||||
import {
|
||||
CalculateSwapQuoteOpts,
|
||||
@ -39,6 +39,7 @@ import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
|
||||
import { QuoteRequestor } from './utils/quote_requestor';
|
||||
import { sortingUtils } from './utils/sorting_utils';
|
||||
import { SwapQuoteCalculator } from './utils/swap_quote_calculator';
|
||||
import { ERC20BridgeSamplerContract } from './wrappers';
|
||||
|
||||
export class SwapQuoter {
|
||||
public readonly provider: ZeroExProvider;
|
||||
@ -183,7 +184,7 @@ export class SwapQuoter {
|
||||
);
|
||||
this._orderStateUtils = new OrderStateUtils(this._devUtilsContract);
|
||||
// Allow the sampler bytecode to be overwritten using geths override functionality
|
||||
const samplerBytecode = _.get(ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
|
||||
const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object');
|
||||
const defaultCodeOverrides = samplerBytecode
|
||||
? {
|
||||
[this._contractAddresses.erc20BridgeSampler]: { code: samplerBytecode },
|
||||
|
@ -14,6 +14,7 @@ export const SELL_SOURCES = [
|
||||
ERC20BridgeSource.Kyber,
|
||||
ERC20BridgeSource.Curve,
|
||||
ERC20BridgeSource.Balancer,
|
||||
ERC20BridgeSource.MStable,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -26,6 +27,7 @@ export const BUY_SOURCES = [
|
||||
ERC20BridgeSource.Kyber,
|
||||
ERC20BridgeSource.Curve,
|
||||
ERC20BridgeSource.Balancer,
|
||||
ERC20BridgeSource.MStable,
|
||||
];
|
||||
|
||||
export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
|
||||
|
@ -97,7 +97,7 @@ export class MarketOperationUtils {
|
||||
// Call the sampler contract.
|
||||
const samplerPromise = this._sampler.executeAsync(
|
||||
// Get native order fillable amounts.
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.devUtils),
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
||||
// Get the custom liquidity provider from registry.
|
||||
DexOrderSampler.ops.getLiquidityProviderFromRegistry(
|
||||
this._liquidityProviderRegistry,
|
||||
@ -213,7 +213,7 @@ export class MarketOperationUtils {
|
||||
// Call the sampler contract.
|
||||
const samplerPromise = this._sampler.executeAsync(
|
||||
// Get native order fillable amounts.
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.devUtils),
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders, this.contractAddresses.exchange),
|
||||
// Get the custom liquidity provider from registry.
|
||||
DexOrderSampler.ops.getLiquidityProviderFromRegistry(
|
||||
this._liquidityProviderRegistry,
|
||||
@ -381,7 +381,7 @@ export class MarketOperationUtils {
|
||||
const sources = difference(BUY_SOURCES, _opts.excludedSources);
|
||||
const ops = [
|
||||
...batchNativeOrders.map(orders =>
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(orders, this.contractAddresses.devUtils),
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(orders, this.contractAddresses.exchange),
|
||||
),
|
||||
...(await Promise.all(
|
||||
batchNativeOrders.map(async orders =>
|
||||
|
@ -196,6 +196,8 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
|
||||
return (fill.fillData as LiquidityProviderFillData).poolAddress;
|
||||
case ERC20BridgeSource.MultiBridge:
|
||||
return (fill.fillData as MultiBridgeFillData).poolAddress;
|
||||
case ERC20BridgeSource.MStable:
|
||||
return opts.contractAddresses.mStableBridge;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
|
||||
import { SamplerOverrides } from '../../types';
|
||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
|
||||
import { BalancerPoolsCache } from './balancer_utils';
|
||||
import { samplerOperations } from './sampler_operations';
|
||||
@ -144,18 +144,23 @@ export class DexOrderSampler {
|
||||
const { overrides, block } = this._samplerOverrides
|
||||
? this._samplerOverrides
|
||||
: { overrides: undefined, block: undefined };
|
||||
|
||||
// All operations are NOOPs
|
||||
if (callDatas.every(cd => cd === NULL_BYTES)) {
|
||||
return Promise.all(
|
||||
callDatas.map(async (_callData, i) => ops[i].handleCallResultsAsync(this._samplerContract, NULL_BYTES)),
|
||||
);
|
||||
}
|
||||
// Execute all non-empty calldatas.
|
||||
const rawCallResults = await this._samplerContract
|
||||
.batchCall(callDatas.filter(cd => cd !== '0x'))
|
||||
.batchCall(callDatas.filter(cd => cd !== NULL_BYTES))
|
||||
.callAsync({ overrides }, block);
|
||||
// Return the parsed results.
|
||||
let rawCallResultsIdx = 0;
|
||||
return Promise.all(
|
||||
callDatas.map(async (callData, i) => {
|
||||
if (callData !== '0x') {
|
||||
return ops[i].handleCallResultsAsync(this._samplerContract, rawCallResults[rawCallResultsIdx++]);
|
||||
}
|
||||
return ops[i].handleCallResultsAsync(this._samplerContract, '0x');
|
||||
const result = callData !== NULL_BYTES ? rawCallResults[rawCallResultsIdx++] : NULL_BYTES;
|
||||
return ops[i].handleCallResultsAsync(this._samplerContract, result);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import * as _ from 'lodash';
|
||||
import { BigNumber, ERC20BridgeSource, SignedOrder } from '../..';
|
||||
|
||||
import { BalancerPool, BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
|
||||
import { NULL_BYTES, ZERO_AMOUNT } from './constants';
|
||||
import { getCurveInfosForPair } from './curve_utils';
|
||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||
import {
|
||||
@ -20,11 +21,11 @@ import {
|
||||
* for use with `DexOrderSampler.executeAsync()`.
|
||||
*/
|
||||
export const samplerOperations = {
|
||||
getOrderFillableTakerAmounts(orders: SignedOrder[], devUtilsAddress: string): BatchedOperation<BigNumber[]> {
|
||||
getOrderFillableTakerAmounts(orders: SignedOrder[], exchangeAddress: string): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature), devUtilsAddress)
|
||||
.getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature), exchangeAddress)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
@ -32,11 +33,11 @@ export const samplerOperations = {
|
||||
},
|
||||
};
|
||||
},
|
||||
getOrderFillableMakerAmounts(orders: SignedOrder[], devUtilsAddress: string): BatchedOperation<BigNumber[]> {
|
||||
getOrderFillableMakerAmounts(orders: SignedOrder[], exchangeAddress: string): BatchedOperation<BigNumber[]> {
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature), devUtilsAddress)
|
||||
.getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature), exchangeAddress)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
@ -301,6 +302,32 @@ export const samplerOperations = {
|
||||
...samplerOperations.constant(makerFillAmounts.map(amount => computeBalancerBuyQuote(pool, amount))),
|
||||
};
|
||||
},
|
||||
getMStableSellQuotes(makerToken: string, takerToken: string, takerFillAmounts: BigNumber[]): SourceQuoteOperation {
|
||||
return {
|
||||
source: ERC20BridgeSource.MStable,
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleSellsFromMStable(makerToken, takerToken, takerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromMStable', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getMStableBuyQuotes(makerToken: string, takerToken: string, makerFillAmounts: BigNumber[]): SourceQuoteOperation {
|
||||
return {
|
||||
source: ERC20BridgeSource.MStable,
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleBuysFromMStable(makerToken, takerToken, makerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
return contract.getABIDecodedReturnData<BigNumber[]>('sampleBuysFromMStable', callResults);
|
||||
},
|
||||
};
|
||||
},
|
||||
getMedianSellRateAsync: async (
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
@ -326,21 +353,29 @@ export const samplerOperations = {
|
||||
);
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
const encodedCall = getSellQuotes.encodeCall(contract);
|
||||
// All soures were excluded
|
||||
if (encodedCall === NULL_BYTES) {
|
||||
return NULL_BYTES;
|
||||
}
|
||||
const subCalls = [getSellQuotes.encodeCall(contract)];
|
||||
return contract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
if (callResults === NULL_BYTES) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
|
||||
const samples = await getSellQuotes.handleCallResultsAsync(contract, rawSubCallResults[0]);
|
||||
if (samples.length === 0) {
|
||||
return new BigNumber(0);
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const flatSortedSamples = samples
|
||||
.reduce((acc, v) => acc.concat(...v))
|
||||
.filter(v => !v.output.isZero())
|
||||
.sort((a, b) => a.output.comparedTo(b.output));
|
||||
if (flatSortedSamples.length === 0) {
|
||||
return new BigNumber(0);
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)];
|
||||
return medianSample.output.div(medianSample.input);
|
||||
@ -350,7 +385,7 @@ export const samplerOperations = {
|
||||
constant<T>(result: T): BatchedOperation<T> {
|
||||
return {
|
||||
encodeCall: _contract => {
|
||||
return '0x';
|
||||
return NULL_BYTES;
|
||||
},
|
||||
handleCallResultsAsync: async (_contract, _callResults) => {
|
||||
return result;
|
||||
@ -456,6 +491,8 @@ export const samplerOperations = {
|
||||
return pools.map(pool =>
|
||||
samplerOperations.getBalancerSellQuotes(pool, takerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.MStable:
|
||||
return samplerOperations.getMStableSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
default:
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
@ -467,17 +504,27 @@ export const samplerOperations = {
|
||||
const nonSamplerOps = subOps.filter(op => op.source === ERC20BridgeSource.Balancer);
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
// All operations are NOOPs
|
||||
if (samplerOps.length === 0) {
|
||||
return NULL_BYTES;
|
||||
}
|
||||
const subCalls = samplerOps.map(op => op.encodeCall(contract));
|
||||
return contract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
let samples: BigNumber[][];
|
||||
// If all operations were NOOPs then just call the handle result callback
|
||||
if (callResults === NULL_BYTES && samplerOps.length === 0) {
|
||||
samples = await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, '')));
|
||||
} else {
|
||||
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
|
||||
let samples = await Promise.all(
|
||||
samples = await Promise.all(
|
||||
samplerOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
|
||||
);
|
||||
samples = samples.concat(
|
||||
await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))),
|
||||
);
|
||||
}
|
||||
return [...samplerOps, ...nonSamplerOps].map((op, i) => {
|
||||
return samples[i].map((output, j) => ({
|
||||
source: op.source,
|
||||
@ -553,6 +600,8 @@ export const samplerOperations = {
|
||||
return pools.map(pool =>
|
||||
samplerOperations.getBalancerBuyQuotes(pool, makerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.MStable:
|
||||
return samplerOperations.getMStableBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
default:
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
@ -564,17 +613,26 @@ export const samplerOperations = {
|
||||
const nonSamplerOps = subOps.filter(op => op.source === ERC20BridgeSource.Balancer);
|
||||
return {
|
||||
encodeCall: contract => {
|
||||
// All operations are NOOPs
|
||||
if (samplerOps.length === 0) {
|
||||
return NULL_BYTES;
|
||||
}
|
||||
const subCalls = samplerOps.map(op => op.encodeCall(contract));
|
||||
return contract.batchCall(subCalls).getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
let samples: BigNumber[][];
|
||||
if (callResults === NULL_BYTES && samplerOps.length === 0) {
|
||||
samples = await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, '')));
|
||||
} else {
|
||||
const rawSubCallResults = contract.getABIDecodedReturnData<string[]>('batchCall', callResults);
|
||||
let samples = await Promise.all(
|
||||
samples = await Promise.all(
|
||||
samplerOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])),
|
||||
);
|
||||
samples = samples.concat(
|
||||
await Promise.all(nonSamplerOps.map(async op => op.handleCallResultsAsync(contract, ''))),
|
||||
);
|
||||
}
|
||||
return [...samplerOps, ...nonSamplerOps].map((op, i) => {
|
||||
return samples[i].map((output, j) => ({
|
||||
source: op.source,
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
|
||||
import { RFQTIndicativeQuote } from '@0x/quote-server';
|
||||
import { MarketOperation, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { RfqtRequestOpts, SignedOrderWithFillableAmounts } from '../../types';
|
||||
import { QuoteRequestor } from '../../utils/quote_requestor';
|
||||
import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
import { QuoteReport } from '../quote_report_generator';
|
||||
|
||||
/**
|
||||
@ -38,6 +38,7 @@ export enum ERC20BridgeSource {
|
||||
LiquidityProvider = 'LiquidityProvider',
|
||||
MultiBridge = 'MultiBridge',
|
||||
Balancer = 'Balancer',
|
||||
MStable = 'mStable',
|
||||
}
|
||||
|
||||
// tslint:disable: enum-naming
|
||||
|
@ -12,7 +12,6 @@ import * as DummyLiquidityProviderRegistry from '../test/generated-artifacts/Dum
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
import * as Eth2DaiSampler from '../test/generated-artifacts/Eth2DaiSampler.json';
|
||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
|
||||
import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
|
||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
|
||||
import * as IKyberHintHandler from '../test/generated-artifacts/IKyberHintHandler.json';
|
||||
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
|
||||
@ -20,15 +19,18 @@ import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkPr
|
||||
import * as IKyberStorage from '../test/generated-artifacts/IKyberStorage.json';
|
||||
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
|
||||
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
|
||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
|
||||
import * as IMultiBridge from '../test/generated-artifacts/IMultiBridge.json';
|
||||
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
|
||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
|
||||
import * as KyberSampler from '../test/generated-artifacts/KyberSampler.json';
|
||||
import * as LiquidityProviderSampler from '../test/generated-artifacts/LiquidityProviderSampler.json';
|
||||
import * as MStableSampler from '../test/generated-artifacts/MStableSampler.json';
|
||||
import * as MultiBridgeSampler from '../test/generated-artifacts/MultiBridgeSampler.json';
|
||||
import * as NativeOrderSampler from '../test/generated-artifacts/NativeOrderSampler.json';
|
||||
import * as SamplerUtils from '../test/generated-artifacts/SamplerUtils.json';
|
||||
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
|
||||
import * as TestNativeOrderSampler from '../test/generated-artifacts/TestNativeOrderSampler.json';
|
||||
import * as UniswapSampler from '../test/generated-artifacts/UniswapSampler.json';
|
||||
import * as UniswapV2Sampler from '../test/generated-artifacts/UniswapV2Sampler.json';
|
||||
export const artifacts = {
|
||||
@ -39,7 +41,6 @@ export const artifacts = {
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
|
||||
ICurve: ICurve as ContractArtifact,
|
||||
IDevUtils: IDevUtils as ContractArtifact,
|
||||
IEth2Dai: IEth2Dai as ContractArtifact,
|
||||
IKyberHintHandler: IKyberHintHandler as ContractArtifact,
|
||||
IKyberNetwork: IKyberNetwork as ContractArtifact,
|
||||
@ -47,15 +48,18 @@ export const artifacts = {
|
||||
IKyberStorage: IKyberStorage as ContractArtifact,
|
||||
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
|
||||
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
|
||||
IMStable: IMStable as ContractArtifact,
|
||||
IMultiBridge: IMultiBridge as ContractArtifact,
|
||||
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
|
||||
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
|
||||
KyberSampler: KyberSampler as ContractArtifact,
|
||||
LiquidityProviderSampler: LiquidityProviderSampler as ContractArtifact,
|
||||
MStableSampler: MStableSampler as ContractArtifact,
|
||||
MultiBridgeSampler: MultiBridgeSampler as ContractArtifact,
|
||||
NativeOrderSampler: NativeOrderSampler as ContractArtifact,
|
||||
SamplerUtils: SamplerUtils as ContractArtifact,
|
||||
UniswapSampler: UniswapSampler as ContractArtifact,
|
||||
UniswapV2Sampler: UniswapV2Sampler as ContractArtifact,
|
||||
TestERC20BridgeSampler: TestERC20BridgeSampler as ContractArtifact,
|
||||
TestNativeOrderSampler: TestNativeOrderSampler as ContractArtifact,
|
||||
};
|
@ -1,10 +1,14 @@
|
||||
import { artifacts, ERC20BridgeSamplerContract } from '@0x/contracts-erc20-bridge-sampler';
|
||||
import { blockchainTests, describe, expect, toBaseUnitAmount, Web3ProviderEngine } from '@0x/contracts-test-utils';
|
||||
import { RPCSubprovider } from '@0x/subproviders';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { ERC20BridgeSamplerContract } from '../wrappers';
|
||||
|
||||
export const VB = '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b';
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
blockchainTests.skip('Mainnet Sampler Tests', env => {
|
||||
let testContract: ERC20BridgeSamplerContract;
|
||||
const fakeSamplerAddress = '0x1111111111111111111111111111111111111111';
|
@ -10,12 +10,16 @@ import { Order } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { artifacts } from '../artifacts';
|
||||
import {
|
||||
DummyLiquidityProviderContract,
|
||||
DummyLiquidityProviderRegistryContract,
|
||||
TestERC20BridgeSamplerContract,
|
||||
} from './wrappers';
|
||||
} from '../wrappers';
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
const { NULL_ADDRESS } = constants;
|
||||
|
||||
blockchainTests('erc20-bridge-sampler', env => {
|
||||
let testContract: TestERC20BridgeSamplerContract;
|
||||
@ -33,7 +37,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
let devUtilsAddress: string;
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
|
||||
@ -42,8 +45,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
// TestERC20BridgeSampler stubs DevUtils
|
||||
devUtilsAddress = testContract.address;
|
||||
});
|
||||
|
||||
function getPackedHash(...args: string[]): string {
|
||||
@ -209,12 +210,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
|
||||
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
||||
const hash = getPackedHash(hexUtils.leftPad(order.salt));
|
||||
const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
|
||||
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
|
||||
if (orderStatus !== 3 || !isValidSignature) {
|
||||
return constants.ZERO_AMOUNT;
|
||||
}
|
||||
return order.takerAssetAmount.minus(new BigNumber(hash).mod(order.takerAssetAmount));
|
||||
return new BigNumber(hash).mod(order.takerAssetAmount);
|
||||
}
|
||||
|
||||
function getDeterministicFillableMakerAssetAmount(order: Order): BigNumber {
|
||||
@ -272,44 +268,15 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, NULL_ADDRESS)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq(expected);
|
||||
});
|
||||
|
||||
it('returns empty for no orders', async () => {
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts([], [], devUtilsAddress).callAsync();
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts([], [], NULL_ADDRESS).callAsync();
|
||||
expect(actual).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with an empty signature', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOrderFillableMakerAssetAmounts()', () => {
|
||||
@ -318,44 +285,15 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
|
||||
const actual = await testContract
|
||||
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.getOrderFillableMakerAssetAmounts(orders, signatures, NULL_ADDRESS)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq(expected);
|
||||
});
|
||||
|
||||
it('returns empty for no orders', async () => {
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts([], [], devUtilsAddress).callAsync();
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts([], [], NULL_ADDRESS).callAsync();
|
||||
expect(actual).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract
|
||||
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract
|
||||
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
|
||||
it('returns zero for an order with an empty signature', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
|
||||
const actual = await testContract
|
||||
.getOrderFillableMakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
});
|
||||
|
||||
blockchainTests.resets('sampleSellsFromKyberNetwork()', () => {
|
||||
@ -1036,7 +974,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||
const calls = [
|
||||
testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, NULL_ADDRESS)
|
||||
.getABIEncodedTransactionData(),
|
||||
];
|
||||
const r = await testContract.batchCall(calls).callAsync();
|
||||
@ -1055,10 +993,10 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
];
|
||||
const calls = [
|
||||
testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders[0], signatures, devUtilsAddress)
|
||||
.getOrderFillableTakerAssetAmounts(orders[0], signatures, NULL_ADDRESS)
|
||||
.getABIEncodedTransactionData(),
|
||||
testContract
|
||||
.getOrderFillableMakerAssetAmounts(orders[1], signatures, devUtilsAddress)
|
||||
.getOrderFillableMakerAssetAmounts(orders[1], signatures, NULL_ADDRESS)
|
||||
.getABIEncodedTransactionData(),
|
||||
];
|
||||
const r = await testContract.batchCall(calls).callAsync();
|
||||
@ -1081,7 +1019,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
testContract
|
||||
.batchCall([
|
||||
testContract
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, devUtilsAddress)
|
||||
.getOrderFillableTakerAssetAmounts(orders, signatures, NULL_ADDRESS)
|
||||
.getABIEncodedTransactionData(),
|
||||
])
|
||||
.getABIEncodedTransactionData(),
|
@ -0,0 +1,313 @@
|
||||
import {
|
||||
assertIntegerRoughlyEquals,
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { Order } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
import { TestNativeOrderSamplerContract } from '../wrappers';
|
||||
|
||||
const { NULL_BYTES, ZERO_AMOUNT } = constants;
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
blockchainTests.resets('NativeOrderSampler contract', env => {
|
||||
let testContract: TestNativeOrderSamplerContract;
|
||||
let makerToken: string;
|
||||
let takerToken: string;
|
||||
let feeToken: string;
|
||||
let erc20Proxy: string;
|
||||
const ERC20_PROXY_ID = '0xf47261b0';
|
||||
const VALID_SIGNATURE = '0x01';
|
||||
const INVALID_SIGNATURE = '0x00';
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestNativeOrderSamplerContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestNativeOrderSampler,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
erc20Proxy = await testContract.getAssetProxy(ERC20_PROXY_ID).callAsync();
|
||||
const NUM_TOKENS = new BigNumber(3);
|
||||
[makerToken, takerToken, feeToken] = await testContract.createTokens(NUM_TOKENS).callAsync();
|
||||
await testContract.createTokens(NUM_TOKENS).awaitTransactionSuccessAsync();
|
||||
});
|
||||
|
||||
function getPackedHash(...args: string[]): string {
|
||||
return hexUtils.hash(hexUtils.concat(...args.map(a => hexUtils.toHex(a))));
|
||||
}
|
||||
|
||||
interface OrderInfo {
|
||||
orderHash: string;
|
||||
orderStatus: number;
|
||||
orderTakerAssetFilledAmount: BigNumber;
|
||||
}
|
||||
|
||||
function getOrderInfo(order: Order): OrderInfo {
|
||||
const hash = getPackedHash(hexUtils.leftPad(order.salt));
|
||||
const orderStatus = order.salt.mod(255).eq(0) ? 3 : 5;
|
||||
const filledAmount = order.expirationTimeSeconds;
|
||||
return {
|
||||
orderStatus,
|
||||
orderHash: hash,
|
||||
orderTakerAssetFilledAmount: filledAmount,
|
||||
};
|
||||
}
|
||||
|
||||
function createFillableOrderSalt(): BigNumber {
|
||||
return new BigNumber(hexUtils.concat(hexUtils.slice(hexUtils.random(), 0, -1), '0x01'));
|
||||
}
|
||||
|
||||
function createUnfillableOrderSalt(): BigNumber {
|
||||
return new BigNumber(hexUtils.concat(hexUtils.slice(hexUtils.random(), 0, -1), '0xff'));
|
||||
}
|
||||
|
||||
function getOrderFillableTakerAmount(order: Order): BigNumber {
|
||||
return order.takerAssetAmount.minus(getOrderInfo(order).orderTakerAssetFilledAmount);
|
||||
}
|
||||
|
||||
function getERC20AssetData(tokenAddress: string): string {
|
||||
return hexUtils.concat(ERC20_PROXY_ID, hexUtils.leftPad(tokenAddress));
|
||||
}
|
||||
|
||||
function createOrder(fields: Partial<Order> = {}, filledTakerAssetAmount: BigNumber = ZERO_AMOUNT): Order {
|
||||
return {
|
||||
chainId: 1337,
|
||||
exchangeAddress: randomAddress(),
|
||||
makerAddress: randomAddress(),
|
||||
takerAddress: randomAddress(),
|
||||
senderAddress: randomAddress(),
|
||||
feeRecipientAddress: randomAddress(),
|
||||
makerAssetAmount: getRandomInteger(1e18, 10e18),
|
||||
takerAssetAmount: getRandomInteger(1e18, 10e18),
|
||||
makerFee: getRandomInteger(1e18, 10e18),
|
||||
takerFee: getRandomInteger(1e18, 10e18),
|
||||
makerAssetData: getERC20AssetData(makerToken),
|
||||
takerAssetData: getERC20AssetData(takerToken),
|
||||
makerFeeAssetData: getERC20AssetData(feeToken),
|
||||
takerFeeAssetData: getERC20AssetData(randomAddress()),
|
||||
salt: createFillableOrderSalt(),
|
||||
// Expiration time will be used to determine filled amount.
|
||||
expirationTimeSeconds: filledTakerAssetAmount,
|
||||
...fields,
|
||||
};
|
||||
}
|
||||
|
||||
async function fundMakerAsync(
|
||||
order: Order,
|
||||
assetData: string,
|
||||
balanceScaling: number = 1,
|
||||
allowanceScaling: number = 1,
|
||||
): Promise<void> {
|
||||
let token;
|
||||
let amount;
|
||||
if (assetData === order.makerAssetData) {
|
||||
token = makerToken;
|
||||
amount =
|
||||
order.makerAssetData === order.makerFeeAssetData
|
||||
? order.makerAssetAmount.plus(order.makerFee)
|
||||
: order.makerAssetAmount;
|
||||
} else {
|
||||
token = feeToken;
|
||||
amount = order.makerFee;
|
||||
}
|
||||
amount = amount.times(getOrderFillableTakerAmount(order).div(BigNumber.max(1, order.takerAssetAmount)));
|
||||
await testContract
|
||||
.setTokenBalanceAndAllowance(
|
||||
token,
|
||||
order.makerAddress,
|
||||
erc20Proxy,
|
||||
amount.times(balanceScaling).integerValue(),
|
||||
amount.times(allowanceScaling).integerValue(),
|
||||
)
|
||||
.awaitTransactionSuccessAsync();
|
||||
}
|
||||
|
||||
describe('getOrderFillableTakerAmount()', () => {
|
||||
it('returns the full amount for a fully funded order', async () => {
|
||||
const order = createOrder();
|
||||
const expected = getOrderFillableTakerAmount(order);
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(actual).to.bignumber.eq(expected);
|
||||
});
|
||||
|
||||
it('returns the full amount for a fully funded order without maker fees', async () => {
|
||||
const order = createOrder({ makerFee: ZERO_AMOUNT });
|
||||
const expected = getOrderFillableTakerAmount(order);
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(actual).to.bignumber.eq(expected);
|
||||
});
|
||||
|
||||
it('returns the full amount for a fully funded order without maker fee asset data', async () => {
|
||||
const order = createOrder({ makerFeeAssetData: NULL_BYTES });
|
||||
const expected = getOrderFillableTakerAmount(order);
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(actual).to.bignumber.eq(expected);
|
||||
});
|
||||
|
||||
it('returns the full amount for a fully funded order with maker fees denominated in the maker asset', async () => {
|
||||
const order = createOrder({ makerFeeAssetData: getERC20AssetData(makerToken) });
|
||||
const expected = getOrderFillableTakerAmount(order);
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(actual).to.bignumber.eq(expected);
|
||||
});
|
||||
|
||||
it('returns partial amount with insufficient maker asset balance', async () => {
|
||||
const order = createOrder();
|
||||
const expected = getOrderFillableTakerAmount(order)
|
||||
.times(0.5)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
await fundMakerAsync(order, order.makerAssetData, 0.5);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
assertIntegerRoughlyEquals(actual, expected, 100);
|
||||
});
|
||||
|
||||
it('returns partial amount with insufficient maker asset allowance', async () => {
|
||||
const order = createOrder();
|
||||
const expected = getOrderFillableTakerAmount(order)
|
||||
.times(0.5)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
await fundMakerAsync(order, order.makerAssetData, 1, 0.5);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
assertIntegerRoughlyEquals(actual, expected, 100);
|
||||
});
|
||||
|
||||
it('returns partial amount with insufficient maker fee asset balance', async () => {
|
||||
const order = createOrder();
|
||||
const expected = getOrderFillableTakerAmount(order)
|
||||
.times(0.5)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData, 0.5);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
assertIntegerRoughlyEquals(actual, expected, 100);
|
||||
});
|
||||
|
||||
it('returns partial amount with insufficient maker fee asset allowance', async () => {
|
||||
const order = createOrder();
|
||||
const expected = getOrderFillableTakerAmount(order)
|
||||
.times(0.5)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData, 1, 0.5);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
assertIntegerRoughlyEquals(actual, expected, 100);
|
||||
});
|
||||
|
||||
it('returns partial amount with insufficient maker asset balance (maker asset fees)', async () => {
|
||||
const order = createOrder({ makerFeeAssetData: getERC20AssetData(makerToken) });
|
||||
const expected = getOrderFillableTakerAmount(order)
|
||||
.times(0.5)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
await fundMakerAsync(order, order.makerAssetData, 0.5);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
assertIntegerRoughlyEquals(actual, expected, 100);
|
||||
});
|
||||
|
||||
it('returns partial amount with insufficient maker asset allowance (maker asset fees)', async () => {
|
||||
const order = createOrder({ makerFeeAssetData: getERC20AssetData(makerToken) });
|
||||
const expected = getOrderFillableTakerAmount(order)
|
||||
.times(0.5)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
await fundMakerAsync(order, order.makerAssetData, 1, 0.5);
|
||||
const actual = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
assertIntegerRoughlyEquals(actual, expected, 100);
|
||||
});
|
||||
|
||||
it('returns zero for an that is not fillable', async () => {
|
||||
const order = {
|
||||
...createOrder(),
|
||||
salt: createUnfillableOrderSalt(),
|
||||
};
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const fillableTakerAmount = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const order = {
|
||||
...createOrder(),
|
||||
makerAssetAmount: ZERO_AMOUNT,
|
||||
};
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const fillableTakerAmount = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const order = {
|
||||
...createOrder(),
|
||||
takerAssetAmount: ZERO_AMOUNT,
|
||||
};
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const fillableTakerAmount = await testContract
|
||||
.getOrderFillableTakerAmount(order, VALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('returns zero for an order with an empty signature', async () => {
|
||||
const order = createOrder();
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const fillableTakerAmount = await testContract
|
||||
.getOrderFillableTakerAmount(order, NULL_BYTES, testContract.address)
|
||||
.callAsync();
|
||||
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
|
||||
});
|
||||
|
||||
it('returns zero for an order with an invalid signature', async () => {
|
||||
const order = createOrder();
|
||||
await fundMakerAsync(order, order.makerAssetData);
|
||||
await fundMakerAsync(order, order.makerFeeAssetData);
|
||||
const fillableTakerAmount = await testContract
|
||||
.getOrderFillableTakerAmount(order, INVALID_SIGNATURE, testContract.address)
|
||||
.callAsync();
|
||||
expect(fillableTakerAmount).to.bignumber.eq(ZERO_AMOUNT);
|
||||
});
|
||||
});
|
||||
});
|
@ -32,7 +32,7 @@ describe('DexSampler tests', () => {
|
||||
const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
|
||||
|
||||
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
|
||||
const devUtilsAddress = getContractAddressesForChainOrThrow(CHAIN_ID).devUtils;
|
||||
const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange;
|
||||
|
||||
describe('getSampleAmounts()', () => {
|
||||
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
||||
@ -106,7 +106,7 @@ describe('DexSampler tests', () => {
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, devUtilsAddress),
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, exchangeAddress),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
@ -122,7 +122,7 @@ describe('DexSampler tests', () => {
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, devUtilsAddress),
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, exchangeAddress),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
@ -632,8 +632,8 @@ describe('DexSampler tests', () => {
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||
const [fillableMakerAmounts, fillableTakerAmounts] = await dexOrderSampler.executeAsync(
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, devUtilsAddress),
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, devUtilsAddress),
|
||||
DexOrderSampler.ops.getOrderFillableMakerAmounts(ORDERS, exchangeAddress),
|
||||
DexOrderSampler.ops.getOrderFillableTakerAmounts(ORDERS, exchangeAddress),
|
||||
);
|
||||
expect(fillableMakerAmounts).to.deep.eq(expectedFillableMakerAmounts);
|
||||
expect(fillableTakerAmounts).to.deep.eq(expectedFillableTakerAmounts);
|
||||
|
@ -31,11 +31,6 @@ const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
|
||||
describe('MarketOperationUtils tests', () => {
|
||||
const CHAIN_ID = 1;
|
||||
const contractAddresses = { ...getContractAddressesForChainOrThrow(CHAIN_ID), multiBridge: NULL_ADDRESS };
|
||||
const ETH2DAI_BRIDGE_ADDRESS = contractAddresses.eth2DaiBridge;
|
||||
const KYBER_BRIDGE_ADDRESS = contractAddresses.kyberBridge;
|
||||
const UNISWAP_BRIDGE_ADDRESS = contractAddresses.uniswapBridge;
|
||||
const UNISWAP_V2_BRIDGE_ADDRESS = contractAddresses.uniswapV2Bridge;
|
||||
const CURVE_BRIDGE_ADDRESS = contractAddresses.curveBridge;
|
||||
let originalSamplerOperations: any;
|
||||
|
||||
before(() => {
|
||||
@ -79,16 +74,18 @@ describe('MarketOperationUtils tests', () => {
|
||||
}
|
||||
const { bridgeAddress } = bridgeData;
|
||||
switch (bridgeAddress) {
|
||||
case KYBER_BRIDGE_ADDRESS.toLowerCase():
|
||||
case contractAddresses.kyberBridge.toLowerCase():
|
||||
return ERC20BridgeSource.Kyber;
|
||||
case ETH2DAI_BRIDGE_ADDRESS.toLowerCase():
|
||||
case contractAddresses.eth2DaiBridge.toLowerCase():
|
||||
return ERC20BridgeSource.Eth2Dai;
|
||||
case UNISWAP_BRIDGE_ADDRESS.toLowerCase():
|
||||
case contractAddresses.uniswapBridge.toLowerCase():
|
||||
return ERC20BridgeSource.Uniswap;
|
||||
case UNISWAP_V2_BRIDGE_ADDRESS.toLowerCase():
|
||||
case contractAddresses.uniswapV2Bridge.toLowerCase():
|
||||
return ERC20BridgeSource.UniswapV2;
|
||||
case CURVE_BRIDGE_ADDRESS.toLowerCase():
|
||||
case contractAddresses.curveBridge.toLowerCase():
|
||||
return ERC20BridgeSource.Curve;
|
||||
case contractAddresses.mStableBridge.toLowerCase():
|
||||
return ERC20BridgeSource.MStable;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -294,6 +291,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Curve]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MultiBridge]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MStable]: _.times(NUM_SAMPLES, () => 0),
|
||||
};
|
||||
|
||||
interface FillDataBySource {
|
||||
@ -425,7 +423,12 @@ describe('MarketOperationUtils tests', () => {
|
||||
sampleDistributionBase: 1,
|
||||
bridgeSlippage: 0,
|
||||
maxFallbackSlippage: 100,
|
||||
excludedSources: [ERC20BridgeSource.UniswapV2, ERC20BridgeSource.Curve, ERC20BridgeSource.Balancer],
|
||||
excludedSources: [
|
||||
ERC20BridgeSource.UniswapV2,
|
||||
ERC20BridgeSource.Curve,
|
||||
ERC20BridgeSource.Balancer,
|
||||
ERC20BridgeSource.MStable,
|
||||
],
|
||||
allowFallback: false,
|
||||
shouldBatchBridgeOrders: false,
|
||||
};
|
||||
@ -462,7 +465,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
excludedSources: [],
|
||||
});
|
||||
expect(sourcesPolled.sort()).to.deep.eq(SELL_SOURCES.slice().sort());
|
||||
expect(sourcesPolled.sort()).to.deep.equals(SELL_SOURCES.slice().sort());
|
||||
});
|
||||
|
||||
it('polls the liquidity provider when the registry is provided in the arguments', async () => {
|
||||
@ -484,7 +487,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
excludedSources: [],
|
||||
});
|
||||
expect(args.sources.sort()).to.deep.eq(
|
||||
expect(args.sources.sort()).to.deep.equals(
|
||||
SELL_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(),
|
||||
);
|
||||
expect(args.liquidityProviderAddress).to.eql(registryAddress);
|
||||
@ -503,7 +506,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
excludedSources,
|
||||
});
|
||||
expect(sourcesPolled.sort()).to.deep.eq(_.without(SELL_SOURCES, ...excludedSources).sort());
|
||||
expect(sourcesPolled.sort()).to.deep.equals(_.without(SELL_SOURCES, ...excludedSources).sort());
|
||||
});
|
||||
|
||||
it('generates bridge orders with correct asset data', async () => {
|
||||
@ -836,6 +839,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
ERC20BridgeSource.UniswapV2,
|
||||
ERC20BridgeSource.Curve,
|
||||
ERC20BridgeSource.Balancer,
|
||||
ERC20BridgeSource.MStable,
|
||||
],
|
||||
allowFallback: false,
|
||||
shouldBatchBridgeOrders: false,
|
||||
@ -873,7 +877,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
excludedSources: [],
|
||||
});
|
||||
expect(sourcesPolled).to.deep.eq(BUY_SOURCES);
|
||||
expect(sourcesPolled.sort()).to.deep.equals(BUY_SOURCES.sort());
|
||||
});
|
||||
|
||||
it('polls the liquidity provider when the registry is provided in the arguments', async () => {
|
||||
@ -914,7 +918,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
...DEFAULT_OPTS,
|
||||
excludedSources,
|
||||
});
|
||||
expect(sourcesPolled).to.deep.eq(_.without(BUY_SOURCES, ...excludedSources));
|
||||
expect(sourcesPolled.sort()).to.deep.eq(_.without(BUY_SOURCES, ...excludedSources).sort());
|
||||
});
|
||||
|
||||
it('generates bridge orders with correct asset data', async () => {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { ContractFunctionObj } from '@0x/base-contract';
|
||||
import { ERC20BridgeSamplerContract } from '@0x/contract-wrappers';
|
||||
import { constants } from '@0x/contracts-test-utils';
|
||||
import { Order } from '@0x/types';
|
||||
import { BigNumber, hexUtils } from '@0x/utils';
|
||||
|
||||
import { ERC20BridgeSamplerContract } from '../../src/wrappers';
|
||||
|
||||
export type GetOrderFillableAssetAmountResult = BigNumber[];
|
||||
export type GetOrderFillableAssetAmountHandler = (
|
||||
orders: Order[],
|
||||
@ -59,6 +60,8 @@ interface Handlers {
|
||||
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||
}
|
||||
|
||||
// tslint:disable: no-unbound-method
|
||||
|
||||
export class MockSamplerContract extends ERC20BridgeSamplerContract {
|
||||
private readonly _handlers: Partial<Handlers> = {};
|
||||
|
||||
|
@ -10,7 +10,6 @@ export * from '../test/generated-wrappers/dummy_liquidity_provider_registry';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/eth2_dai_sampler';
|
||||
export * from '../test/generated-wrappers/i_curve';
|
||||
export * from '../test/generated-wrappers/i_dev_utils';
|
||||
export * from '../test/generated-wrappers/i_eth2_dai';
|
||||
export * from '../test/generated-wrappers/i_kyber_hint_handler';
|
||||
export * from '../test/generated-wrappers/i_kyber_network';
|
||||
@ -18,14 +17,17 @@ export * from '../test/generated-wrappers/i_kyber_network_proxy';
|
||||
export * from '../test/generated-wrappers/i_kyber_storage';
|
||||
export * from '../test/generated-wrappers/i_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
|
||||
export * from '../test/generated-wrappers/i_m_stable';
|
||||
export * from '../test/generated-wrappers/i_multi_bridge';
|
||||
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
|
||||
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
|
||||
export * from '../test/generated-wrappers/kyber_sampler';
|
||||
export * from '../test/generated-wrappers/liquidity_provider_sampler';
|
||||
export * from '../test/generated-wrappers/m_stable_sampler';
|
||||
export * from '../test/generated-wrappers/multi_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/native_order_sampler';
|
||||
export * from '../test/generated-wrappers/sampler_utils';
|
||||
export * from '../test/generated-wrappers/test_erc20_bridge_sampler';
|
||||
export * from '../test/generated-wrappers/test_native_order_sampler';
|
||||
export * from '../test/generated-wrappers/uniswap_sampler';
|
||||
export * from '../test/generated-wrappers/uniswap_v2_sampler';
|
@ -1,8 +1,40 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./src/**/*", "./test/**/*"]
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/DummyLiquidityProvider.json",
|
||||
"generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"generated-artifacts/ERC20BridgeSampler.json",
|
||||
"generated-artifacts/ILiquidityProvider.json",
|
||||
"generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ApproximateBuys.json",
|
||||
"test/generated-artifacts/CurveSampler.json",
|
||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/Eth2DaiSampler.json",
|
||||
"test/generated-artifacts/ICurve.json",
|
||||
"test/generated-artifacts/IEth2Dai.json",
|
||||
"test/generated-artifacts/IKyberHintHandler.json",
|
||||
"test/generated-artifacts/IKyberNetwork.json",
|
||||
"test/generated-artifacts/IKyberNetworkProxy.json",
|
||||
"test/generated-artifacts/IKyberStorage.json",
|
||||
"test/generated-artifacts/ILiquidityProvider.json",
|
||||
"test/generated-artifacts/ILiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/IMStable.json",
|
||||
"test/generated-artifacts/IMultiBridge.json",
|
||||
"test/generated-artifacts/IUniswapExchangeQuotes.json",
|
||||
"test/generated-artifacts/IUniswapV2Router01.json",
|
||||
"test/generated-artifacts/KyberSampler.json",
|
||||
"test/generated-artifacts/LiquidityProviderSampler.json",
|
||||
"test/generated-artifacts/MStableSampler.json",
|
||||
"test/generated-artifacts/MultiBridgeSampler.json",
|
||||
"test/generated-artifacts/NativeOrderSampler.json",
|
||||
"test/generated-artifacts/SamplerUtils.json",
|
||||
"test/generated-artifacts/TestERC20BridgeSampler.json",
|
||||
"test/generated-artifacts/TestNativeOrderSampler.json",
|
||||
"test/generated-artifacts/UniswapSampler.json",
|
||||
"test/generated-artifacts/UniswapV2Sampler.json"
|
||||
]
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user