merged into development to grab dodo

This commit is contained in:
Alex Kroeger 2020-10-13 23:23:05 -07:00
commit eb27e260e0
26 changed files with 477 additions and 11 deletions

View File

@ -33,6 +33,10 @@
{
"note": "Added `ShellBridge`",
"pr": 2722
},
{
"note": "Added `DODOBridge`",
"pr": 2701
}
]
},

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

View File

@ -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|CreamBridge|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|CreamBridge|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": {

View File

@ -11,6 +11,7 @@ import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
import * as CreamBridge from '../generated-artifacts/CreamBridge.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';
@ -75,6 +76,7 @@ export const artifacts = {
ChaiBridge: ChaiBridge as ContractArtifact,
CreamBridge: CreamBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DODOBridge: DODOBridge as ContractArtifact,
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,

View File

@ -8,6 +8,7 @@ export * from '../generated-wrappers/bancor_bridge';
export * from '../generated-wrappers/chai_bridge';
export * from '../generated-wrappers/cream_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';

View File

@ -11,6 +11,7 @@ import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
import * as CreamBridge from '../test/generated-artifacts/CreamBridge.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';
@ -75,6 +76,7 @@ export const artifacts = {
ChaiBridge: ChaiBridge as ContractArtifact,
CreamBridge: CreamBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DODOBridge: DODOBridge as ContractArtifact,
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,

View File

@ -8,6 +8,7 @@ export * from '../test/generated-wrappers/bancor_bridge';
export * from '../test/generated-wrappers/chai_bridge';
export * from '../test/generated-wrappers/cream_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';

View File

@ -8,6 +8,7 @@
"generated-artifacts/ChaiBridge.json",
"generated-artifacts/CreamBridge.json",
"generated-artifacts/CurveBridge.json",
"generated-artifacts/DODOBridge.json",
"generated-artifacts/DexForwarderBridge.json",
"generated-artifacts/DydxBridge.json",
"generated-artifacts/ERC1155Proxy.json",
@ -63,6 +64,7 @@
"test/generated-artifacts/ChaiBridge.json",
"test/generated-artifacts/CreamBridge.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",

View File

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

View File

@ -149,6 +149,10 @@
{
"note": "Remove 0x-API swap/v0-specifc code from asset-swapper",
"pr": 2725
},
{
"note": "Added `DODO`",
"pr": 2701
}
]
},

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

View File

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

View File

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

View File

@ -133,6 +133,7 @@ export {
CurveFunctionSelectors,
CurveInfo,
DexSample,
DODOFillData,
ERC20BridgeSource,
ExchangeProxyOverhead,
FeeSchedule,

View File

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

View File

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

View File

@ -23,6 +23,7 @@ import {
CurveFillData,
CurveInfo,
DexSample,
DODOFillData,
ERC20BridgeSource,
HopInfo,
KyberFillData,
@ -585,7 +586,7 @@ export class SamplerOperations {
makerToken: string,
takerToken: string,
takerFillAmounts: BigNumber[],
): SourceQuoteOperation {
): SourceQuoteOperation<MooniswapFillData> {
return new SamplerContractOperation({
source: ERC20BridgeSource.Mooniswap,
contract: this._samplerContract,
@ -606,7 +607,7 @@ export class SamplerOperations {
makerToken: string,
takerToken: string,
makerFillAmounts: BigNumber[],
): SourceQuoteOperation {
): SourceQuoteOperation<MooniswapFillData> {
return new SamplerContractOperation({
source: ERC20BridgeSource.Mooniswap,
contract: this._samplerContract,
@ -825,6 +826,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,
@ -1070,6 +1113,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}`);
}
@ -1165,6 +1210,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}`);
}

View File

@ -45,6 +45,7 @@ export enum ERC20BridgeSource {
Shell = 'Shell',
Swerve = 'Swerve',
SushiSwap = 'SushiSwap',
Dodo = 'DODO',
}
// tslint:disable: enum-naming
@ -138,6 +139,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;

View File

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

View File

@ -29,13 +29,7 @@ import { CreamPoolsCache } from '../src/utils/market_operation_utils/cream_utils
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();
@ -53,6 +47,7 @@ const DEFAULT_EXCLUDED = [
ERC20BridgeSource.MultiHop,
ERC20BridgeSource.Shell,
ERC20BridgeSource.Cream,
ERC20BridgeSource.Dodo,
];
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
@ -113,6 +108,8 @@ describe('MarketOperationUtils tests', () => {
return ERC20BridgeSource.SushiSwap;
case contractAddresses.shellBridge.toLowerCase():
return ERC20BridgeSource.Shell;
case contractAddresses.dodoBridge.toLowerCase():
return ERC20BridgeSource.Dodo;
default:
break;
}
@ -291,6 +288,7 @@ describe('MarketOperationUtils tests', () => {
[ERC20BridgeSource.MultiHop]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.Dodo]: _.times(NUM_SAMPLES, () => 0),
};
const DEFAULT_RATES: RatesBySource = {
@ -338,6 +336,7 @@ describe('MarketOperationUtils tests', () => {
[ERC20BridgeSource.MultiHop]: {},
[ERC20BridgeSource.Shell]: {},
[ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
[ERC20BridgeSource.Dodo]: {},
};
const DEFAULT_OPS = {

View File

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

View File

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

View File

@ -53,6 +53,10 @@
{
"note": "Deploy `ShellBridge` on Mainnet",
"pr": 2722
},
{
"note": "Deploy `DodoBridge` on Mainnet",
"pr": 2701
}
]
},

View File

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

View File

@ -45,6 +45,7 @@ export interface ContractAddresses {
mooniswapBridge: string;
sushiswapBridge: string;
shellBridge: string;
dodoBridge: string;
transformers: {
wethTransformer: string;
payTakerTransformer: string;

View File

@ -405,6 +405,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,