feat: DODO (#2701)
* feat: DODO * DODO Bridge * export DODOFillData * Use deployed DODOHelper * Deployed Bridge. Half of buys supported * other half of buys * refactor * CHANGELOGs * Lint
This commit is contained in:
parent
2dc0bff1ea
commit
4d04b72674
@ -29,6 +29,10 @@
|
||||
{
|
||||
"note": "Added `ShellBridge`",
|
||||
"pr": 2722
|
||||
},
|
||||
{
|
||||
"note": "Added `DODOBridge`",
|
||||
"pr": 2701
|
||||
}
|
||||
]
|
||||
},
|
||||
|
147
contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
Normal file
147
contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
|
||||
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;
|
||||
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";
|
||||
|
||||
|
||||
interface IDODOHelper {
|
||||
|
||||
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
|
||||
interface IDODO {
|
||||
|
||||
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
|
||||
|
||||
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
|
||||
|
||||
}
|
||||
|
||||
|
||||
contract DODOBridge is
|
||||
IERC20Bridge,
|
||||
IWallet,
|
||||
DeploymentConstants
|
||||
{
|
||||
|
||||
struct TransferState {
|
||||
address fromTokenAddress;
|
||||
uint256 fromTokenBalance;
|
||||
address pool;
|
||||
bool isSellBase;
|
||||
}
|
||||
|
||||
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
|
||||
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
|
||||
/// token encoded in the bridge data.
|
||||
/// @param toTokenAddress The token to buy and transfer to `to`.
|
||||
/// @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 path of token addresses. Last element must be toTokenAddress
|
||||
/// @return success The magic bytes if successful.
|
||||
function bridgeTransferFrom(
|
||||
address toTokenAddress,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount,
|
||||
bytes calldata bridgeData
|
||||
)
|
||||
external
|
||||
returns (bytes4 success)
|
||||
{
|
||||
TransferState memory state;
|
||||
// Decode the bridge data to get the `fromTokenAddress`.
|
||||
(state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool));
|
||||
require(state.pool != address(0), "DODOBridge/InvalidPool");
|
||||
IDODO exchange = IDODO(state.pool);
|
||||
// Get our balance of `fromTokenAddress` token.
|
||||
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
|
||||
|
||||
// Grant the pool an allowance.
|
||||
LibERC20Token.approveIfBelow(
|
||||
state.fromTokenAddress,
|
||||
address(exchange),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
|
||||
uint256 boughtAmount;
|
||||
if (state.isSellBase) {
|
||||
boughtAmount = exchange.sellBaseToken(
|
||||
// amount to sell
|
||||
state.fromTokenBalance,
|
||||
// min receive amount
|
||||
1,
|
||||
new bytes(0)
|
||||
);
|
||||
} else {
|
||||
// Need to re-calculate the sell quote amount into buyBase
|
||||
boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken(
|
||||
address(exchange),
|
||||
state.fromTokenBalance
|
||||
);
|
||||
exchange.buyBaseToken(
|
||||
// amount to buy
|
||||
boughtAmount,
|
||||
// max pay amount
|
||||
state.fromTokenBalance,
|
||||
new bytes(0)
|
||||
);
|
||||
}
|
||||
// Transfer funds to `to`
|
||||
IERC20Token(toTokenAddress).transfer(to, boughtAmount);
|
||||
|
||||
|
||||
emit ERC20BridgeTransfer(
|
||||
// input token
|
||||
state.fromTokenAddress,
|
||||
// output token
|
||||
toTokenAddress,
|
||||
// input token amount
|
||||
state.fromTokenBalance,
|
||||
// output token amount
|
||||
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 Success bytes, always.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes calldata
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
@ -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|BancorBridge|ChaiBridge|CurveBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|StaticCallProxy|SushiSwapBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
|
||||
"abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|StaticCallProxy|SushiSwapBridge|TestBancorBridge|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": {
|
||||
|
@ -10,6 +10,7 @@ import * as BancorBridge from '../generated-artifacts/BancorBridge.json';
|
||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
|
||||
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
|
||||
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
|
||||
@ -73,6 +74,7 @@ export const artifacts = {
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DODOBridge: DODOBridge as ContractArtifact,
|
||||
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
|
@ -7,6 +7,7 @@ export * from '../generated-wrappers/balancer_bridge';
|
||||
export * from '../generated-wrappers/bancor_bridge';
|
||||
export * from '../generated-wrappers/chai_bridge';
|
||||
export * from '../generated-wrappers/curve_bridge';
|
||||
export * from '../generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../generated-wrappers/dex_forwarder_bridge';
|
||||
export * from '../generated-wrappers/dydx_bridge';
|
||||
export * from '../generated-wrappers/erc1155_proxy';
|
||||
|
@ -10,6 +10,7 @@ import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json';
|
||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
|
||||
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
|
||||
import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json';
|
||||
import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json';
|
||||
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
|
||||
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
|
||||
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
|
||||
@ -73,6 +74,7 @@ export const artifacts = {
|
||||
BancorBridge: BancorBridge as ContractArtifact,
|
||||
ChaiBridge: ChaiBridge as ContractArtifact,
|
||||
CurveBridge: CurveBridge as ContractArtifact,
|
||||
DODOBridge: DODOBridge as ContractArtifact,
|
||||
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
|
||||
DydxBridge: DydxBridge as ContractArtifact,
|
||||
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
|
||||
|
@ -7,6 +7,7 @@ export * from '../test/generated-wrappers/balancer_bridge';
|
||||
export * from '../test/generated-wrappers/bancor_bridge';
|
||||
export * from '../test/generated-wrappers/chai_bridge';
|
||||
export * from '../test/generated-wrappers/curve_bridge';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_bridge';
|
||||
export * from '../test/generated-wrappers/dex_forwarder_bridge';
|
||||
export * from '../test/generated-wrappers/dydx_bridge';
|
||||
export * from '../test/generated-wrappers/erc1155_proxy';
|
||||
|
@ -7,6 +7,7 @@
|
||||
"generated-artifacts/BancorBridge.json",
|
||||
"generated-artifacts/ChaiBridge.json",
|
||||
"generated-artifacts/CurveBridge.json",
|
||||
"generated-artifacts/DODOBridge.json",
|
||||
"generated-artifacts/DexForwarderBridge.json",
|
||||
"generated-artifacts/DydxBridge.json",
|
||||
"generated-artifacts/ERC1155Proxy.json",
|
||||
@ -61,6 +62,7 @@
|
||||
"test/generated-artifacts/BancorBridge.json",
|
||||
"test/generated-artifacts/ChaiBridge.json",
|
||||
"test/generated-artifacts/CurveBridge.json",
|
||||
"test/generated-artifacts/DODOBridge.json",
|
||||
"test/generated-artifacts/DexForwarderBridge.json",
|
||||
"test/generated-artifacts/DydxBridge.json",
|
||||
"test/generated-artifacts/ERC1155Proxy.json",
|
||||
|
@ -58,6 +58,10 @@ contract DeploymentConstants {
|
||||
address constant private MOONISWAP_REGISTRY = 0x71CD6666064C3A1354a3B4dca5fA1E2D3ee7D303;
|
||||
/// @dev Mainnet address of the Shell contract
|
||||
address constant private SHELL_CONTRACT = 0x2E703D658f8dd21709a7B458967aB4081F8D3d05;
|
||||
/// @dev Mainnet address of the DODO Registry (ZOO) contract
|
||||
address constant private DODO_REGISTRY = 0x3A97247DF274a17C59A3bd12735ea3FcDFb49950;
|
||||
/// @dev Mainnet address of the DODO Helper contract
|
||||
address constant private DODO_HELPER = 0x533dA777aeDCE766CEAe696bf90f8541A4bA80Eb;
|
||||
|
||||
// // Ropsten addresses ///////////////////////////////////////////////////////
|
||||
// /// @dev Mainnet address of the WETH contract.
|
||||
@ -308,4 +312,24 @@ contract DeploymentConstants {
|
||||
{
|
||||
return SHELL_CONTRACT;
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the DODO Registry contract address.
|
||||
/// @return registry The DODO Registry contract address.
|
||||
function _getDODORegistryAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return DODO_REGISTRY;
|
||||
}
|
||||
|
||||
/// @dev An overridable way to retrieve the DODO Helper contract address.
|
||||
/// @return registry The DODO Helper contract address.
|
||||
function _getDODOHelperAddress()
|
||||
internal
|
||||
view
|
||||
returns (address)
|
||||
{
|
||||
return DODO_HELPER;
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,10 @@
|
||||
{
|
||||
"note": "Remove 0x-API swap/v0-specifc code from asset-swapper",
|
||||
"pr": 2725
|
||||
},
|
||||
{
|
||||
"note": "Added `DODO`",
|
||||
"pr": 2701
|
||||
}
|
||||
]
|
||||
},
|
||||
|
187
packages/asset-swapper/contracts/src/DODOSampler.sol
Normal file
187
packages/asset-swapper/contracts/src/DODOSampler.sol
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
|
||||
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 "./ApproximateBuys.sol";
|
||||
import "./SamplerUtils.sol";
|
||||
|
||||
|
||||
interface IDODOZoo {
|
||||
function getDODO(address baseToken, address quoteToken) external view returns (address);
|
||||
}
|
||||
|
||||
interface IDODOHelper {
|
||||
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
interface IDODO {
|
||||
function querySellBaseToken(uint256 amount) external view returns (uint256);
|
||||
}
|
||||
|
||||
contract DODOSampler is
|
||||
DeploymentConstants,
|
||||
SamplerUtils,
|
||||
ApproximateBuys
|
||||
{
|
||||
|
||||
/// @dev Gas limit for DODO calls.
|
||||
uint256 constant private DODO_CALL_GAS = 300e3; // 300k
|
||||
|
||||
/// @dev Sample sell quotes from DODO.
|
||||
/// @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 sampleSellsFromDODO(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = takerTokenAmounts.length;
|
||||
makerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
pool = IDODOZoo(_getDODORegistryAddress()).getDODO(takerToken, makerToken);
|
||||
address baseToken;
|
||||
// If pool exists we have the correct order of Base/Quote
|
||||
if (pool != address(0)) {
|
||||
baseToken = takerToken;
|
||||
sellBase = true;
|
||||
} else {
|
||||
pool = IDODOZoo(_getDODORegistryAddress()).getDODO(makerToken, takerToken);
|
||||
// No pool either direction
|
||||
if (address(pool) == address(0)) {
|
||||
return (sellBase, pool, makerTokenAmounts);
|
||||
}
|
||||
baseToken = makerToken;
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
uint256 buyAmount = _sampleSellForApproximateBuyFromDODO(
|
||||
abi.encode(takerToken, pool, baseToken), // taker token data
|
||||
abi.encode(makerToken, pool, baseToken), // maker token data
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
// Exit early if the amount is too high for the source to serve
|
||||
if (buyAmount == 0) {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Sample buy quotes from DODO.
|
||||
/// @param takerToken Address of the taker token (what to sell).
|
||||
/// @param makerToken Address of the maker token (what to buy).
|
||||
/// @param makerTokenAmounts Maker token sell amount for each sample.
|
||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||
/// amount.
|
||||
function sampleBuysFromDODO(
|
||||
address takerToken,
|
||||
address makerToken,
|
||||
uint256[] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool sellBase, address pool, uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
_assertValidPair(makerToken, takerToken);
|
||||
uint256 numSamples = makerTokenAmounts.length;
|
||||
takerTokenAmounts = new uint256[](numSamples);
|
||||
|
||||
// Pool is BASE/QUOTE
|
||||
// Look up the pool from the taker/maker combination
|
||||
pool = IDODOZoo(_getDODORegistryAddress()).getDODO(takerToken, makerToken);
|
||||
address baseToken;
|
||||
// If pool exists we have the correct order of Base/Quote
|
||||
if (pool != address(0)) {
|
||||
baseToken = takerToken;
|
||||
sellBase = true;
|
||||
} else {
|
||||
// Look up the pool from the maker/taker combination
|
||||
pool = IDODOZoo(_getDODORegistryAddress()).getDODO(makerToken, takerToken);
|
||||
// No pool either direction
|
||||
if (address(pool) == address(0)) {
|
||||
return (sellBase, pool, takerTokenAmounts);
|
||||
}
|
||||
baseToken = makerToken;
|
||||
sellBase = false;
|
||||
}
|
||||
|
||||
takerTokenAmounts = _sampleApproximateBuys(
|
||||
ApproximateBuyQuoteOpts({
|
||||
makerTokenData: abi.encode(makerToken, pool, baseToken),
|
||||
takerTokenData: abi.encode(takerToken, pool, baseToken),
|
||||
getSellQuoteCallback: _sampleSellForApproximateBuyFromDODO
|
||||
}),
|
||||
makerTokenAmounts
|
||||
);
|
||||
}
|
||||
|
||||
function _sampleSellForApproximateBuyFromDODO(
|
||||
bytes memory takerTokenData,
|
||||
bytes memory /* makerTokenData */,
|
||||
uint256 sellAmount
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
(address takerToken, address pool, address baseToken) = abi.decode(
|
||||
takerTokenData,
|
||||
(address, address, address)
|
||||
);
|
||||
|
||||
bool didSucceed;
|
||||
bytes memory resultData;
|
||||
// We will get called to sell both the taker token and also to sell the maker token
|
||||
if (takerToken == baseToken) {
|
||||
// If base token then use the original query on the pool
|
||||
(didSucceed, resultData) =
|
||||
pool.staticcall.gas(DODO_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IDODO(0).querySellBaseToken.selector,
|
||||
sellAmount
|
||||
));
|
||||
} else {
|
||||
// If quote token then use helper, this is less accurate
|
||||
(didSucceed, resultData) =
|
||||
_getDODOHelperAddress().staticcall.gas(DODO_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
IDODOHelper(0).querySellQuoteToken.selector,
|
||||
pool,
|
||||
sellAmount
|
||||
));
|
||||
}
|
||||
if (!didSucceed) {
|
||||
return 0;
|
||||
}
|
||||
// solhint-disable-next-line indent
|
||||
return abi.decode(resultData, (uint256));
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./BalancerSampler.sol";
|
||||
import "./CurveSampler.sol";
|
||||
import "./DODOSampler.sol";
|
||||
import "./Eth2DaiSampler.sol";
|
||||
import "./KyberSampler.sol";
|
||||
import "./LiquidityProviderSampler.sol";
|
||||
@ -38,6 +39,7 @@ import "./UniswapV2Sampler.sol";
|
||||
contract ERC20BridgeSampler is
|
||||
BalancerSampler,
|
||||
CurveSampler,
|
||||
DODOSampler,
|
||||
Eth2DaiSampler,
|
||||
KyberSampler,
|
||||
LiquidityProviderSampler,
|
||||
|
@ -38,7 +38,7 @@
|
||||
"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|BalancerSampler|CurveSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
||||
"abis": "./test/generated-artifacts/@(ApproximateBuys|BalancerSampler|CurveSampler|DODOSampler|DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|Eth2DaiSampler|IBalancer|ICurve|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IMStable|IMooniswap|IMultiBridge|IShell|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SushiSwapSampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler).json",
|
||||
"postpublish": {
|
||||
"assets": []
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ export {
|
||||
CurveFunctionSelectors,
|
||||
CurveInfo,
|
||||
DexSample,
|
||||
DODOFillData,
|
||||
ERC20BridgeSource,
|
||||
ExchangeProxyOverhead,
|
||||
FeeSchedule,
|
||||
|
@ -24,6 +24,7 @@ export const SELL_SOURCE_FILTER = new SourceFilters([
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -45,6 +46,7 @@ export const BUY_SOURCE_FILTER = new SourceFilters(
|
||||
ERC20BridgeSource.Swerve,
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Dodo,
|
||||
],
|
||||
[ERC20BridgeSource.MultiBridge],
|
||||
);
|
||||
|
@ -24,6 +24,7 @@ import {
|
||||
CollapsedFill,
|
||||
CurveFillData,
|
||||
DexSample,
|
||||
DODOFillData,
|
||||
ERC20BridgeSource,
|
||||
KyberFillData,
|
||||
LiquidityProviderFillData,
|
||||
@ -186,6 +187,8 @@ function getBridgeAddressFromFill(fill: CollapsedFill, opts: CreateOrderFromPath
|
||||
return opts.contractAddresses.mooniswapBridge;
|
||||
case ERC20BridgeSource.Shell:
|
||||
return opts.contractAddresses.shellBridge;
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return opts.contractAddresses.dodoBridge;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -285,6 +288,14 @@ export function createBridgeOrder(
|
||||
createMooniswapBridgeData(takerToken, mooniswapFillData.poolAddress),
|
||||
);
|
||||
break;
|
||||
case ERC20BridgeSource.Dodo:
|
||||
const dodoFillData = (fill as CollapsedFill<DODOFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
bridgeAddress,
|
||||
createDODOBridgeData(takerToken, dodoFillData.poolAddress, dodoFillData.isSellBase),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||
makerToken,
|
||||
@ -355,6 +366,15 @@ function createMooniswapBridgeData(takerToken: string, poolAddress: string): str
|
||||
return encoder.encode({ takerToken, poolAddress });
|
||||
}
|
||||
|
||||
function createDODOBridgeData(takerToken: string, poolAddress: string, isSellBase: boolean): string {
|
||||
const encoder = AbiEncoder.create([
|
||||
{ name: 'takerToken', type: 'address' },
|
||||
{ name: 'poolAddress', type: 'address' },
|
||||
{ name: 'isSellBase', type: 'bool' },
|
||||
]);
|
||||
return encoder.encode({ takerToken, poolAddress, isSellBase });
|
||||
}
|
||||
|
||||
function createCurveBridgeData(
|
||||
curveAddress: string,
|
||||
exchangeFunctionSelector: string,
|
||||
|
@ -21,6 +21,7 @@ import {
|
||||
CurveFillData,
|
||||
CurveInfo,
|
||||
DexSample,
|
||||
DODOFillData,
|
||||
ERC20BridgeSource,
|
||||
HopInfo,
|
||||
KyberFillData,
|
||||
@ -520,7 +521,7 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation {
|
||||
): SourceQuoteOperation<MooniswapFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Mooniswap,
|
||||
contract: this._samplerContract,
|
||||
@ -541,7 +542,7 @@ export class SamplerOperations {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation {
|
||||
): SourceQuoteOperation<MooniswapFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Mooniswap,
|
||||
contract: this._samplerContract,
|
||||
@ -760,6 +761,48 @@ export class SamplerOperations {
|
||||
});
|
||||
}
|
||||
|
||||
public getDODOSellQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<DODOFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Dodo,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromDODO,
|
||||
params: [takerToken, makerToken, takerFillAmounts],
|
||||
callback: (callResults: string, fillData: DODOFillData): BigNumber[] => {
|
||||
const [isSellBase, pool, samples] = this._samplerContract.getABIDecodedReturnData<
|
||||
[boolean, string, BigNumber[]]
|
||||
>('sampleSellsFromDODO', callResults);
|
||||
fillData.isSellBase = isSellBase;
|
||||
fillData.poolAddress = pool;
|
||||
return samples;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getDODOBuyQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<DODOFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Dodo,
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromDODO,
|
||||
params: [takerToken, makerToken, makerFillAmounts],
|
||||
callback: (callResults: string, fillData: DODOFillData): BigNumber[] => {
|
||||
const [isSellBase, pool, samples] = this._samplerContract.getABIDecodedReturnData<
|
||||
[boolean, string, BigNumber[]]
|
||||
>('sampleBuysFromDODO', callResults);
|
||||
fillData.isSellBase = isSellBase;
|
||||
fillData.poolAddress = pool;
|
||||
return samples;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public getMedianSellRate(
|
||||
sources: ERC20BridgeSource[],
|
||||
makerToken: string,
|
||||
@ -999,6 +1042,8 @@ export class SamplerOperations {
|
||||
);
|
||||
case ERC20BridgeSource.Shell:
|
||||
return this.getShellSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return this.getDODOSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
default:
|
||||
throw new Error(`Unsupported sell sample source: ${source}`);
|
||||
}
|
||||
@ -1088,6 +1133,8 @@ export class SamplerOperations {
|
||||
);
|
||||
case ERC20BridgeSource.Shell:
|
||||
return this.getShellBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
case ERC20BridgeSource.Dodo:
|
||||
return this.getDODOBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
default:
|
||||
throw new Error(`Unsupported buy sample source: ${source}`);
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ export enum ERC20BridgeSource {
|
||||
Shell = 'Shell',
|
||||
Swerve = 'Swerve',
|
||||
SushiSwap = 'SushiSwap',
|
||||
Dodo = 'DODO',
|
||||
}
|
||||
|
||||
// tslint:disable: enum-naming
|
||||
@ -133,6 +134,11 @@ export interface MooniswapFillData extends FillData {
|
||||
poolAddress: string;
|
||||
}
|
||||
|
||||
export interface DODOFillData extends FillData {
|
||||
poolAddress: string;
|
||||
isSellBase: boolean;
|
||||
}
|
||||
|
||||
export interface Quote<TFillData = FillData> {
|
||||
amount: BigNumber;
|
||||
fillData?: TFillData;
|
||||
|
@ -8,6 +8,7 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
import * as ApproximateBuys from '../test/generated-artifacts/ApproximateBuys.json';
|
||||
import * as BalancerSampler from '../test/generated-artifacts/BalancerSampler.json';
|
||||
import * as CurveSampler from '../test/generated-artifacts/CurveSampler.json';
|
||||
import * as DODOSampler from '../test/generated-artifacts/DODOSampler.json';
|
||||
import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json';
|
||||
import * as DummyLiquidityProviderRegistry from '../test/generated-artifacts/DummyLiquidityProviderRegistry.json';
|
||||
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
|
||||
@ -42,6 +43,7 @@ export const artifacts = {
|
||||
ApproximateBuys: ApproximateBuys as ContractArtifact,
|
||||
BalancerSampler: BalancerSampler as ContractArtifact,
|
||||
CurveSampler: CurveSampler as ContractArtifact,
|
||||
DODOSampler: DODOSampler as ContractArtifact,
|
||||
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
|
||||
Eth2DaiSampler: Eth2DaiSampler as ContractArtifact,
|
||||
IMooniswap: IMooniswap as ContractArtifact,
|
||||
|
@ -28,13 +28,7 @@ import {
|
||||
import { createFills } from '../src/utils/market_operation_utils/fills';
|
||||
import { DexOrderSampler } from '../src/utils/market_operation_utils/sampler';
|
||||
import { BATCH_SOURCE_FILTERS } from '../src/utils/market_operation_utils/sampler_operations';
|
||||
import {
|
||||
DexSample,
|
||||
ERC20BridgeSource,
|
||||
FillData,
|
||||
NativeFillData,
|
||||
OptimizedMarketOrder,
|
||||
} from '../src/utils/market_operation_utils/types';
|
||||
import { DexSample, ERC20BridgeSource, FillData, NativeFillData } from '../src/utils/market_operation_utils/types';
|
||||
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
@ -51,6 +45,7 @@ const DEFAULT_EXCLUDED = [
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.Dodo,
|
||||
];
|
||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
||||
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
||||
@ -111,6 +106,8 @@ describe('MarketOperationUtils tests', () => {
|
||||
return ERC20BridgeSource.SushiSwap;
|
||||
case contractAddresses.shellBridge.toLowerCase():
|
||||
return ERC20BridgeSource.Shell;
|
||||
case contractAddresses.dodoBridge.toLowerCase():
|
||||
return ERC20BridgeSource.Dodo;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -288,6 +285,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.SushiSwap]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MultiHop]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
|
||||
};
|
||||
|
||||
const DEFAULT_RATES: RatesBySource = {
|
||||
@ -334,6 +332,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Native]: { order: createOrder() },
|
||||
[ERC20BridgeSource.MultiHop]: {},
|
||||
[ERC20BridgeSource.Shell]: {},
|
||||
[ERC20BridgeSource.Dodo]: {},
|
||||
};
|
||||
|
||||
const DEFAULT_OPS = {
|
||||
|
@ -6,6 +6,7 @@
|
||||
export * from '../test/generated-wrappers/approximate_buys';
|
||||
export * from '../test/generated-wrappers/balancer_sampler';
|
||||
export * from '../test/generated-wrappers/curve_sampler';
|
||||
export * from '../test/generated-wrappers/d_o_d_o_sampler';
|
||||
export * from '../test/generated-wrappers/dummy_liquidity_provider';
|
||||
export * from '../test/generated-wrappers/dummy_liquidity_provider_registry';
|
||||
export * from '../test/generated-wrappers/erc20_bridge_sampler';
|
||||
|
@ -11,6 +11,7 @@
|
||||
"test/generated-artifacts/ApproximateBuys.json",
|
||||
"test/generated-artifacts/BalancerSampler.json",
|
||||
"test/generated-artifacts/CurveSampler.json",
|
||||
"test/generated-artifacts/DODOSampler.json",
|
||||
"test/generated-artifacts/DummyLiquidityProvider.json",
|
||||
"test/generated-artifacts/DummyLiquidityProviderRegistry.json",
|
||||
"test/generated-artifacts/ERC20BridgeSampler.json",
|
||||
|
@ -53,6 +53,10 @@
|
||||
{
|
||||
"note": "Deploy `ShellBridge` on Mainnet",
|
||||
"pr": 2722
|
||||
},
|
||||
{
|
||||
"note": "Deploy `DodoBridge` on Mainnet",
|
||||
"pr": 2701
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -44,6 +44,7 @@
|
||||
"mooniswapBridge": "0x02b7eca484ad960fca3f7709e0b2ac81eec3069c",
|
||||
"sushiswapBridge": "0x47ed0262a0b688dcb836d254c6a2e96b6c48a9f5",
|
||||
"shellBridge": "0x21fb3862eed7911e0f8219a077247b849846728d",
|
||||
"dodoBridge": "0xe9da66965a9344aab2167e6813c03f043cc7a6ca",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x68c0bb685099dc7cb5c5ce2b26185945b357383e",
|
||||
"payTakerTransformer": "0x49b9df2c58491764cf40cb052dd4243df63622c7",
|
||||
@ -96,6 +97,7 @@
|
||||
"mooniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"sushiswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"shellBridge": "0x0000000000000000000000000000000000000000",
|
||||
"dodoBridge": "0x0000000000000000000000000000000000000000",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
||||
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
||||
@ -148,6 +150,7 @@
|
||||
"mooniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"sushiswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"shellBridge": "0x0000000000000000000000000000000000000000",
|
||||
"dodoBridge": "0x0000000000000000000000000000000000000000",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x8d822fe2b42f60531203e288f5f357fa79474437",
|
||||
"payTakerTransformer": "0x150652244723102faeaefa4c79597d097ffa26c6",
|
||||
@ -200,6 +203,7 @@
|
||||
"mooniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"sushiswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"shellBridge": "0x0000000000000000000000000000000000000000",
|
||||
"dodoBridge": "0x0000000000000000000000000000000000000000",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x9ce35b5ee9e710535e3988e3f8731d9ca9dba17d",
|
||||
"payTakerTransformer": "0x5a53e7b02a83aa9f60ccf4e424f0442c255bc977",
|
||||
@ -252,6 +256,7 @@
|
||||
"mooniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"sushiswapBridge": "0x0000000000000000000000000000000000000000",
|
||||
"shellBridge": "0x0000000000000000000000000000000000000000",
|
||||
"dodoBridge": "0x0000000000000000000000000000000000000000",
|
||||
"transformers": {
|
||||
"wethTransformer": "0xc6b0d3c45a6b5092808196cb00df5c357d55e1d5",
|
||||
"payTakerTransformer": "0x7209185959d7227fb77274e1e88151d7c4c368d3",
|
||||
|
@ -45,6 +45,7 @@ export interface ContractAddresses {
|
||||
mooniswapBridge: string;
|
||||
sushiswapBridge: string;
|
||||
shellBridge: string;
|
||||
dodoBridge: string;
|
||||
transformers: {
|
||||
wethTransformer: string;
|
||||
payTakerTransformer: string;
|
||||
|
@ -404,6 +404,7 @@ export async function runMigrationsAsync(
|
||||
mooniswapBridge: NULL_ADDRESS,
|
||||
sushiswapBridge: NULL_ADDRESS,
|
||||
shellBridge: NULL_ADDRESS,
|
||||
dodoBridge: NULL_ADDRESS,
|
||||
exchangeProxy: exchangeProxy.address,
|
||||
exchangeProxyAllowanceTarget: exchangeProxyAllowanceTargetAddress,
|
||||
exchangeProxyTransformerDeployer: txDefaults.from,
|
||||
|
Loading…
x
Reference in New Issue
Block a user