Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Commit

Permalink
Address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
dekz committed May 5, 2020
1 parent 1bb44af commit 3bc3690
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import "./IDevUtils.sol";
import "./IERC20BridgeSampler.sol";
import "./IEth2Dai.sol";
import "./IKyberNetwork.sol";
import "./IKyberNetworkContract.sol";
import "./IKyberNetworkProxy.sol";
import "./IUniswapExchangeQuotes.sol";
import "./ICurve.sol";
import "./ILiquidityProvider.sol";
Expand All @@ -53,6 +53,10 @@ contract ERC20BridgeSampler is
uint256 constant internal CURVE_CALL_GAS = 600e3; // 600k
/// @dev Default gas limit for liquidity provider calls.
uint256 constant internal DEFAULT_CALL_GAS = 200e3; // 200k
/// @dev The Kyber Uniswap Reserve address
address constant internal KYBER_UNIWAP_RESERVE = 0x31E085Afd48a1d6e51Cc193153d625e8f0514C7F;
/// @dev The Kyber Eth2Dai Reserve address
address constant internal KYBER_ETH2DAI_RESERVE = 0x1E158c0e93c30d24e918Ef83d1e0bE23595C3c0f;

address private _devUtilsAddress;

Expand Down Expand Up @@ -263,6 +267,31 @@ contract ERC20BridgeSampler is
}
}

/// @dev Sample sell quotes from Eth2Dai/Oasis using a hop to an intermediate token.
/// I.e WBTC/DAI via ETH or WBTC/ETH via DAI
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
/// @param intermediateToken Address of the token to hop to.
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
function sampleSellsFromEth2DaiHop(
address takerToken,
address makerToken,
address intermediateToken,
uint256[] memory takerTokenAmounts
)
public
view
returns (uint256[] memory makerTokenAmounts)
{
if (makerToken == intermediateToken || takerToken == intermediateToken) {
return makerTokenAmounts;
}
uint256[] memory intermediateAmounts = sampleSellsFromEth2Dai(takerToken, intermediateToken, takerTokenAmounts);
makerTokenAmounts = sampleSellsFromEth2Dai(intermediateToken, makerToken, intermediateAmounts);
}

/// @dev Sample buy quotes from Eth2Dai/Oasis.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
Expand Down Expand Up @@ -809,7 +838,7 @@ contract ERC20BridgeSampler is
uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
(bool didSucceed, bytes memory resultData) = _getKyberNetworkProxyAddress().staticcall.gas(DEFAULT_CALL_GAS)(
abi.encodeWithSelector(
IKyberNetwork(0).kyberNetworkContract.selector
IKyberNetworkProxy(0).kyberNetworkContract.selector
));
if (!didSucceed) {
return makerTokenAmount;
Expand All @@ -818,7 +847,7 @@ contract ERC20BridgeSampler is
(didSucceed, resultData) =
kyberNetworkContract.staticcall.gas(KYBER_CALL_GAS)(
abi.encodeWithSelector(
IKyberNetworkContract(0).searchBestRate.selector,
IKyberNetwork(0).searchBestRate.selector,
_takerToken,
_makerToken,
takerTokenAmount,
Expand All @@ -831,9 +860,7 @@ contract ERC20BridgeSampler is
} else {
return makerTokenAmount;
}
if (reserve != 0x31E085Afd48a1d6e51Cc193153d625e8f0514C7F || // Uniswap
reserve != 0x1E158c0e93c30d24e918Ef83d1e0bE23595C3c0f) // Eth2Dai
{
if (reserve != KYBER_UNIWAP_RESERVE || reserve != KYBER_ETH2DAI_RESERVE) {
makerTokenAmount =
rate *
takerTokenAmount *
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@ pragma solidity ^0.5.9;

interface IKyberNetwork {

function kyberNetworkContract() external view returns (address);

function getExpectedRate(
function searchBestRate(
address fromToken,
address toToken,
uint256 fromAmount
uint256 fromAmount,
bool usePermissionless
)
external
view
returns (uint256 expectedRate, uint256 slippageRate);
returns (address reserve, uint256 expectedRate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
pragma solidity ^0.5.9;


interface IKyberNetworkContract {
interface IKyberNetworkProxy {

function searchBestRate(
function kyberNetworkContract() external view returns (address);

function getExpectedRate(
address fromToken,
address toToken,
uint256 fromAmount,
bool usePermissionless
uint256 fromAmount
)
external
view
returns (address reserve, uint256 expectedRate);
returns (uint256 expectedRate, uint256 slippageRate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "../src/ERC20BridgeSampler.sol";
import "../src/IEth2Dai.sol";
import "../src/IDevUtils.sol";
import "../src/IKyberNetwork.sol";
import "../src/IKyberNetworkProxy.sol";


library LibDeterministicQuotes {
Expand Down Expand Up @@ -210,7 +210,7 @@ contract TestERC20BridgeSamplerKyberNetwork is
return address(this);
}

// IKyberNetworkContract not exposed via IKyberNetwork
// IKyberNetwork not exposed via IKyberNetworkProxy
function searchBestRate(
address fromToken,
address toToken,
Expand All @@ -225,7 +225,7 @@ contract TestERC20BridgeSamplerKyberNetwork is
return (address(this), expectedRate);
}

// Deterministic `IKyberNetwork.getExpectedRate()`.
// Deterministic `IKyberNetworkProxy.getExpectedRate()`.
function getExpectedRate(
address fromToken,
address toToken,
Expand Down
2 changes: 1 addition & 1 deletion contracts/erc20-bridge-sampler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IKyberNetworkContract|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
"abis": "./test/generated-artifacts/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IKyberNetworkProxy|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
},
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions contracts/erc20-bridge-sampler/test/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
import * as IKyberNetworkContract from '../test/generated-artifacts/IKyberNetworkContract.json';
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
import * as ILiquidityProvider from '../test/generated-artifacts/ILiquidityProvider.json';
import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquidityProviderRegistry.json';
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
Expand All @@ -27,7 +27,7 @@ export const artifacts = {
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetwork: IKyberNetwork as ContractArtifact,
IKyberNetworkContract: IKyberNetworkContract as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
ILiquidityProvider: ILiquidityProvider as ContractArtifact,
ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact,
IUniswapExchangeQuotes: IUniswapExchangeQuotes as ContractArtifact,
Expand Down
2 changes: 1 addition & 1 deletion contracts/erc20-bridge-sampler/test/wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export * from '../test/generated-wrappers/i_dev_utils';
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_network';
export * from '../test/generated-wrappers/i_kyber_network_contract';
export * from '../test/generated-wrappers/i_kyber_network_proxy';
export * from '../test/generated-wrappers/i_liquidity_provider';
export * from '../test/generated-wrappers/i_liquidity_provider_registry';
export * from '../test/generated-wrappers/i_uniswap_exchange_quotes';
Expand Down
2 changes: 1 addition & 1 deletion contracts/erc20-bridge-sampler/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"test/generated-artifacts/IERC20BridgeSampler.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberNetwork.json",
"test/generated-artifacts/IKyberNetworkContract.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/ILiquidityProvider.json",
"test/generated-artifacts/ILiquidityProviderRegistry.json",
"test/generated-artifacts/IUniswapExchangeQuotes.json",
Expand Down
17 changes: 8 additions & 9 deletions packages/asset-swapper/src/utils/market_operation_utils/fills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,10 @@ function dexQuotesToPaths(
const paths: Fill[][] = [];
for (let quote of dexQuotes) {
const path: Fill[] = [];
// Drop any non-zero entries. This can occur if the
// first few fills on Kyber were UniswapReserves
// Drop any non-zero entries. This can occur if the any fills on Kyber were UniswapReserves
// We need not worry about Kyber fills going to UniswapReserve as the input amount
// we fill is the same as we sampled. I.e we received [0,20,30] output from [1,2,3] input
// and we only fill [2,3] on Kyber (as 1 returns 0 output)
quote = quote.filter(q => !q.output.isZero());
for (let i = 0; i < quote.length; i++) {
const sample = quote[i];
Expand Down Expand Up @@ -159,12 +161,6 @@ function sourceToFillFlags(source: ERC20BridgeSource): number {
if (source === ERC20BridgeSource.Kyber) {
return FillFlags.Kyber;
}
if (source === ERC20BridgeSource.Eth2Dai) {
return FillFlags.ConflictsWithKyber;
}
if (source === ERC20BridgeSource.Uniswap) {
return FillFlags.ConflictsWithKyber;
}
return 0;
}

Expand Down Expand Up @@ -203,6 +199,7 @@ export function getPathAdjustedSize(path: Fill[], targetInput: BigNumber = POSIT
}

export function isValidPath(path: Fill[], skipDuplicateCheck: boolean = false): boolean {
let flags = 0;
for (let i = 0; i < path.length; ++i) {
// Fill must immediately follow its parent.
if (path[i].parent) {
Expand All @@ -218,8 +215,10 @@ export function isValidPath(path: Fill[], skipDuplicateCheck: boolean = false):
}
}
}
flags |= path[i].flags;
}
return true;
const conflictFlags = FillFlags.Kyber | FillFlags.ConflictsWithKyber;
return (flags & conflictFlags) !== conflictFlags;
}

export function clipPathToInput(path: Fill[], targetInput: BigNumber = POSITIVE_INF): Fill[] {
Expand Down
26 changes: 15 additions & 11 deletions packages/asset-swapper/src/utils/market_operation_utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,28 +343,32 @@ export class MarketOperationUtils {
// Generate a fallback path if native orders are in the optimal paath.
const nativeSubPath = optimalPath.filter(f => f.source === ERC20BridgeSource.Native);
if (opts.allowFallback && nativeSubPath.length !== 0) {
// We create a fallback path that is exclusive of Native liquidity
// This is the optimal on-chain path for the entire input amount
const nonNativePaths = paths.filter(p => p.length > 0 && p[0].source !== ERC20BridgeSource.Native);
// The fallback path is the entire input amount
const nonNativeOptimalPath = findOptimalPath(side, nonNativePaths, inputAmount, opts.runLimit) || [];
// Calculate the slippage of on-chain sources compared to the most optimal path
const fallbackSlippage = getPathAdjustedSlippage(
side,
nonNativeOptimalPath,
inputAmount,
getPathAdjustedRate(side, optimalPath, inputAmount),
);
if (fallbackSlippage <= maxFallbackSlippage) {
// If the last fill is Native and penultimate is not
// then this intention is a partial fill
// In this case we drop it as we don't want it to fail
// at the end and we don't want to fully fill it
// tslint:disable-next-line: no-unused-variable
const [last, penultimate, ..._rest] = optimalPath.reverse();
const finalNativeFillOrUndefined =
last.source === ERC20BridgeSource.Native && penultimate.source !== ERC20BridgeSource.Native
// If the last fill is Native and penultimate is not, then the intention was to partial fill
// In this case we drop it entirely as we can't handle a failure at the end and we don't
// want to fully fill when it gets prepended to the front below
const [last, penultimateIfExists] = optimalPath.slice().reverse();
const lastNativeFillIfExists =
last.source === ERC20BridgeSource.Native &&
penultimateIfExists &&
penultimateIfExists.source !== ERC20BridgeSource.Native
? last
: undefined;

optimalPath = [...nativeSubPath.filter(f => f !== finalNativeFillOrUndefined), ...nonNativeOptimalPath];
// By prepending native paths to the front they cannot split on-chain sources and incur
// an additional protocol fee. I.e [Uniswap,Native,Kyber] becomes [Native,Uniswap,Kyber]
// In the previous step we dropped any hanging Native partial fills, as to not fully fill
optimalPath = [...nativeSubPath.filter(f => f !== lastNativeFillIfExists), ...nonNativeOptimalPath];
}
}
return createOrdersFromPath(optimalPath, {
Expand Down
28 changes: 26 additions & 2 deletions packages/contract-artifacts/artifacts/ERC20BridgeSampler.json

Large diffs are not rendered by default.

0 comments on commit 3bc3690

Please sign in to comment.