Compare commits

...

14 Commits

Author SHA1 Message Date
Github Actions
719664c145 Publish
- @0x/contracts-integrations@2.7.57
 - @0x/asset-swapper@16.20.0
2021-07-06 21:34:44 +00:00
Github Actions
f800d6c24c Updated CHANGELOGS & MD docs 2021-07-06 21:34:39 +00:00
Romain Butteaud
a9a81bcafb feat: ShibaSwap (#276) 2021-07-06 13:53:39 -07:00
Github Actions
4280307a15 Publish
- @0x/contracts-integrations@2.7.56
 - @0x/asset-swapper@16.19.1
2021-07-06 04:03:16 +00:00
Github Actions
7b57d3ae51 Updated CHANGELOGS & MD docs 2021-07-06 04:03:11 +00:00
Romain Butteaud
8a8a5bbda0 fix: adding MultiHop for Polygon (#271) 2021-07-06 13:33:41 +10:00
Jacob Evans
76987c8db1 fix: PLP fallback (#272)
* fix: PLP fallback

* CHANGELOG
2021-07-06 13:32:34 +10:00
Github Actions
6f8971cc42 Publish
- @0x/contracts-integrations@2.7.55
 - @0x/asset-swapper@16.19.0
2021-07-02 01:48:13 +00:00
Github Actions
71ab882143 Updated CHANGELOGS & MD docs 2021-07-02 01:48:08 +00:00
Romain Butteaud
5a4961c8d9 fix: KyberDMM pick best pools, Polygon KyberDMM (#269)
* fix: KyberDMM all pools, Polygon KyberDMM

* fix: KyberDMM, remove getPoolsLength interface and revert if no pools found
2021-07-01 18:07:02 -07:00
mzhu25
4c4fb99d87 Add PLP as a source for Polygon (#270)
* Whitelist PLP as a source for Polygon

* changelog
2021-07-01 17:21:23 -07:00
Github Actions
872abf09e9 Publish
- @0x/contracts-integrations@2.7.54
 - @0x/asset-swapper@6.18.3
2021-06-29 17:20:15 +00:00
Github Actions
f10bfe7d04 Updated CHANGELOGS & MD docs 2021-06-29 17:20:11 +00:00
Romain Butteaud
a74d8deff3 feat: Balancer V2 Polygon (#267) 2021-06-29 09:46:17 -07:00
14 changed files with 235 additions and 23 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-integrations",
"version": "2.7.53",
"version": "2.7.57",
"private": true,
"engines": {
"node": ">=6.12"
@@ -93,7 +93,7 @@
"typescript": "4.2.2"
},
"dependencies": {
"@0x/asset-swapper": "^6.18.2",
"@0x/asset-swapper": "^16.20.0",
"@0x/base-contract": "^6.4.0",
"@0x/contracts-asset-proxy": "^3.7.16",
"@0x/contracts-erc1155": "^2.1.34",

View File

@@ -1,4 +1,43 @@
[
{
"version": "16.20.0",
"changes": [
{
"note": "ShibaSwap",
"pr": 276
}
],
"timestamp": 1625607277
},
{
"version": "16.19.1",
"changes": [
{
"note": "Fix LiquidityProvider fallback",
"pr": 272
}
],
"timestamp": 1625544188
},
{
"version": "16.19.0",
"changes": [
{
"note": "Add LiquidityProvider to Polygon sources",
"pr": 270
}
],
"timestamp": 1625190486
},
{
"version": "6.18.3",
"changes": [
{
"note": "Polygon Balance V2"
}
],
"timestamp": 1624987208
},
{
"timestamp": 1624562704,
"version": "6.18.2",

View File

@@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v16.20.0 - _July 6, 2021_
* ShibaSwap (#276)
## v16.19.1 - _July 6, 2021_
* Fix LiquidityProvider fallback (#272)
## v16.19.0 - _July 2, 2021_
* Add LiquidityProvider to Polygon sources (#270)
## v6.18.3 - _June 29, 2021_
* Polygon Balance V2
## v6.18.2 - _June 24, 2021_
* Dependencies updated

View File

@@ -20,12 +20,20 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
interface IKyberDmmFactory {
interface IKyberDmmPool {
function getPoolAtIndex(address token0, address token1, uint256 index)
function totalSupply()
external
view
returns (address);
returns (uint256);
}
interface IKyberDmmFactory {
function getPools(address token0, address token1)
external
view
returns (address[] memory _tokenPools);
}
interface IKyberDmmRouter {
@@ -140,17 +148,26 @@ contract KyberDmmSampler
view
returns (address[] memory pools)
{
pools = new address[](path.length - 1);
IKyberDmmFactory factory = IKyberDmmFactory(IKyberDmmRouter(router).factory());
pools = new address[](path.length - 1);
for (uint256 i = 0; i < pools.length; i++) {
// Currently only supporting the first pool found at the index
// find the best pool
address[] memory allPools;
try
factory.getPoolAtIndex
factory.getPools
{gas: KYBER_DMM_CALL_GAS}
(path[i], path[i + 1], 0)
returns (address pool)
(path[i], path[i + 1])
returns (address[] memory allPools)
{
pools[i] = pool;
uint256 maxSupply = 0;
require(allPools.length >= 1, "KyberDMMSampler/NO_POOLS_FOUND");
for (uint256 j = 0; j < allPools.length; j++) {
uint256 totalSupply = IKyberDmmPool(allPools[j]).totalSupply();
if (totalSupply > maxSupply) {
maxSupply = totalSupply;
pools[i] = allPools[j];
}
}
} catch (bytes memory) {
return new address[](0);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/asset-swapper",
"version": "6.18.2",
"version": "16.20.0",
"engines": {
"node": ">=6.12"
},

View File

@@ -32,6 +32,7 @@ import {
QUICKSWAP_ROUTER_BY_CHAIN_ID,
SADDLE_MAINNET_INFOS,
SHELL_POOLS_BY_CHAIN_ID,
SHIBASWAP_ROUTER_BY_CHAIN_ID,
SMOOTHY_BSC_INFOS,
SMOOTHY_MAINNET_INFOS,
SNOWSWAP_MAINNET_INFOS,
@@ -399,7 +400,8 @@ export function uniswapV2LikeRouterAddress(
| ERC20BridgeSource.ComethSwap
| ERC20BridgeSource.Dfyn
| ERC20BridgeSource.WaultSwap
| ERC20BridgeSource.Polydex,
| ERC20BridgeSource.Polydex
| ERC20BridgeSource.ShibaSwap,
): string {
switch (source) {
case ERC20BridgeSource.UniswapV2:
@@ -432,6 +434,8 @@ export function uniswapV2LikeRouterAddress(
return WAULTSWAP_ROUTER_BY_CHAIN_ID[chainId];
case ERC20BridgeSource.Polydex:
return POLYDEX_ROUTER_BY_CHAIN_ID[chainId];
case ERC20BridgeSource.ShibaSwap:
return SHIBASWAP_ROUTER_BY_CHAIN_ID[chainId];
default:
throw new Error(`Unknown UniswapV2 like source ${source}`);
}

View File

@@ -97,6 +97,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.XSigma,
ERC20BridgeSource.UniswapV3,
ERC20BridgeSource.CurveV2,
ERC20BridgeSource.ShibaSwap,
]),
[ChainId.Ropsten]: new SourceFilters([
ERC20BridgeSource.Kyber,
@@ -146,6 +147,10 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.Polydex,
ERC20BridgeSource.ApeSwap,
ERC20BridgeSource.FirebirdOneSwap,
ERC20BridgeSource.BalancerV2,
ERC20BridgeSource.KyberDmm,
ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.MultiHop,
]),
},
new SourceFilters([]),
@@ -188,6 +193,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.XSigma,
ERC20BridgeSource.UniswapV3,
ERC20BridgeSource.CurveV2,
ERC20BridgeSource.ShibaSwap,
]),
[ChainId.Ropsten]: new SourceFilters([
ERC20BridgeSource.Kyber,
@@ -237,6 +243,10 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>(
ERC20BridgeSource.Polydex,
ERC20BridgeSource.ApeSwap,
ERC20BridgeSource.FirebirdOneSwap,
ERC20BridgeSource.BalancerV2,
ERC20BridgeSource.KyberDmm,
ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.MultiHop,
]),
},
new SourceFilters([]),
@@ -517,10 +527,6 @@ export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>(
POLYGON_TOKENS.DAI,
POLYGON_TOKENS.USDT,
POLYGON_TOKENS.WBTC,
POLYGON_TOKENS.QUICK,
POLYGON_TOKENS.DFYN,
POLYGON_TOKENS.BANANA,
POLYGON_TOKENS.WEXPOLY,
],
},
[],
@@ -1090,6 +1096,13 @@ export const LINKSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
NULL_ADDRESS,
);
export const SHIBASWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
{
[ChainId.Mainnet]: '0x03f7724180aa6b939894b5ca4314783b0b36b329',
},
NULL_ADDRESS,
);
export const MSTABLE_POOLS_BY_CHAIN_ID = valueByChainId(
{
[ChainId.Mainnet]: {
@@ -1135,6 +1148,7 @@ export const OASIS_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
export const KYBER_DMM_ROUTER_BY_CHAIN_ID = valueByChainId<string>(
{
[ChainId.Mainnet]: '0x1c87257f5e8609940bc751a07bb085bb7f8cdbe6',
[ChainId.Polygon]: '0x546c79662e028b661dfb4767664d0273184e4dd1',
},
NULL_ADDRESS,
);
@@ -1283,6 +1297,7 @@ export const COMPONENT_POOLS_BY_CHAIN_ID = valueByChainId(
export const BALANCER_V2_VAULT_ADDRESS_BY_CHAIN = valueByChainId<string>(
{
[ChainId.Mainnet]: '0xba12222222228d8ba445958a75a0704d566bf2c8',
[ChainId.Polygon]: '0xba12222222228d8ba445958a75a0704d566bf2c8',
},
NULL_ADDRESS,
);
@@ -1303,7 +1318,13 @@ export const LIDO_INFO_BY_CHAIN = valueByChainId<LidoInfo>(
export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer';
export const BALANCER_TOP_POOLS_FETCHED = 250;
export const BALANCER_MAX_POOLS_FETCHED = 3;
export const BALANCER_V2_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2';
export const BALANCER_V2_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>(
{
[ChainId.Polygon]: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2',
},
'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2',
);
export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId(
{
@@ -1460,6 +1481,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
[ERC20BridgeSource.SushiSwap]: uniswapV2CloneGasSchedule,
[ERC20BridgeSource.CryptoCom]: uniswapV2CloneGasSchedule,
[ERC20BridgeSource.Linkswap]: uniswapV2CloneGasSchedule,
[ERC20BridgeSource.ShibaSwap]: uniswapV2CloneGasSchedule,
[ERC20BridgeSource.Balancer]: () => 120e3,
[ERC20BridgeSource.BalancerV2]: () => 100e3,
[ERC20BridgeSource.Cream]: () => 120e3,

View File

@@ -172,6 +172,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s
return encodeBridgeSourceId(BridgeProtocol.Nerve, 'FirebirdOneSwap');
case ERC20BridgeSource.Lido:
return encodeBridgeSourceId(BridgeProtocol.Lido, 'Lido');
case ERC20BridgeSource.ShibaSwap:
return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'ShibaSwap');
default:
throw new Error(AggregationError.NoBridgeForSource);
}
@@ -242,6 +244,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder
case ERC20BridgeSource.Dfyn:
case ERC20BridgeSource.WaultSwap:
case ERC20BridgeSource.Polydex:
case ERC20BridgeSource.ShibaSwap:
const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData;
bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]);
break;
@@ -427,6 +430,7 @@ export const BRIDGE_ENCODERS: {
[ERC20BridgeSource.SushiSwap]: routerAddressPathEncoder,
[ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder,
[ERC20BridgeSource.Linkswap]: routerAddressPathEncoder,
[ERC20BridgeSource.ShibaSwap]: routerAddressPathEncoder,
// BSC
[ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder,
[ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder,

View File

@@ -78,6 +78,11 @@ export class Path {
return this;
}
/**
* Add a fallback path to the current path
* Fallback must contain exclusive fills that are
* not present in this path
*/
public addFallback(fallback: Path): this {
// 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
@@ -93,7 +98,16 @@ export class Path {
// 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
const nativeFills = this.fills.filter(f => f.source === ERC20BridgeSource.Native);
this.fills = [...nativeFills.filter(f => f !== lastNativeFillIfExists), ...fallback.fills];
const otherFills = this.fills.filter(f => f.source !== ERC20BridgeSource.Native);
const otherSourcePathIds = otherFills.map(f => f.sourcePathId);
this.fills = [
// Append all of the native fills first
...nativeFills.filter(f => f !== lastNativeFillIfExists),
// Add the other fills that are not native in the optimal path
...otherFills,
// Add the fallbacks to the end that aren't already included
...fallback.fills.filter(f => !otherSourcePathIds.includes(f.sourcePathId)),
];
// Recompute the source flags
this.sourceFlags = this.fills.reduce((flags, fill) => flags | fill.flags, BigInt(0));
return this;

View File

@@ -1,3 +1,4 @@
import { ChainId } from '@0x/contract-addresses';
import { BigNumber } from '@0x/utils';
// import { parsePoolData } from '@balancer-labs'; // TODO - upgrade to v2
import { Pool } from '@balancer-labs/sor/dist/types';
@@ -5,7 +6,11 @@ import { gql, request } from 'graphql-request';
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
import { LogFunction } from '../../../types';
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED, BALANCER_V2_SUBGRAPH_URL } from '../constants';
import {
BALANCER_MAX_POOLS_FETCHED,
BALANCER_TOP_POOLS_FETCHED,
BALANCER_V2_SUBGRAPH_URL_BY_CHAIN,
} from '../constants';
import { parsePoolData } from './balancer_sor_v2';
import { CacheValue, PoolsCache } from './pools_cache';
@@ -45,7 +50,8 @@ export class BalancerV2PoolsCache extends PoolsCache {
}
constructor(
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL,
chainId: ChainId,
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId],
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,

View File

@@ -122,7 +122,7 @@ export class SamplerOperations {
this.poolsCaches = poolsCaches
? poolsCaches
: {
[ERC20BridgeSource.BalancerV2]: new BalancerV2PoolsCache(),
[ERC20BridgeSource.BalancerV2]: new BalancerV2PoolsCache(chainId),
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
};
@@ -1229,6 +1229,7 @@ export class SamplerOperations {
case ERC20BridgeSource.Dfyn:
case ERC20BridgeSource.WaultSwap:
case ERC20BridgeSource.Polydex:
case ERC20BridgeSource.ShibaSwap:
const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source);
if (!isValidAddress(uniLikeRouter)) {
return [];
@@ -1499,6 +1500,7 @@ export class SamplerOperations {
case ERC20BridgeSource.Dfyn:
case ERC20BridgeSource.WaultSwap:
case ERC20BridgeSource.Polydex:
case ERC20BridgeSource.ShibaSwap:
const uniLikeRouter = uniswapV2LikeRouterAddress(this.chainId, source);
if (!isValidAddress(uniLikeRouter)) {
return [];

View File

@@ -68,6 +68,7 @@ export enum ERC20BridgeSource {
UniswapV3 = 'Uniswap_V3',
CurveV2 = 'Curve_V2',
Lido = 'Lido',
ShibaSwap = 'ShibaSwap',
// BSC only
PancakeSwap = 'PancakeSwap',
PancakeSwapV2 = 'PancakeSwap_V2',

View File

@@ -0,0 +1,86 @@
import { expect } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import { MarketOperation } from '../src/types';
import { Path } from '../src/utils/market_operation_utils/path';
import { ERC20BridgeSource, Fill } from '../src/utils/market_operation_utils/types';
const createFill = (
source: ERC20BridgeSource,
input: BigNumber = new BigNumber(100),
output: BigNumber = new BigNumber(100),
): Fill =>
// tslint:disable-next-line: no-object-literal-type-assertion
({
source,
input,
output,
adjustedOutput: output,
flags: BigInt(0),
sourcePathId: source,
} as Fill);
describe('Path', () => {
it('Adds a fallback', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
MarketOperation.Sell,
[createFill(ERC20BridgeSource.Native), createFill(ERC20BridgeSource.Native)],
targetInput,
);
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Uniswap)], targetInput);
path.addFallback(fallback);
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([ERC20BridgeSource.Native, ERC20BridgeSource.Native, ERC20BridgeSource.Uniswap]);
});
it('Adds a fallback with LiquidityProvider', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
MarketOperation.Sell,
[createFill(ERC20BridgeSource.Native), createFill(ERC20BridgeSource.LiquidityProvider)],
targetInput,
);
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Uniswap)], targetInput);
path.addFallback(fallback);
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([
ERC20BridgeSource.Native,
ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.Uniswap,
]);
});
it('Removes partial Native orders', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
MarketOperation.Sell,
[
createFill(ERC20BridgeSource.Uniswap),
createFill(ERC20BridgeSource.LiquidityProvider),
createFill(ERC20BridgeSource.Native),
],
targetInput,
);
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Kyber)], targetInput);
path.addFallback(fallback);
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.Kyber,
]);
});
it('Handles duplicates', () => {
const targetInput = new BigNumber(100);
const path = Path.create(
MarketOperation.Sell,
[createFill(ERC20BridgeSource.Uniswap), createFill(ERC20BridgeSource.LiquidityProvider)],
targetInput,
);
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Uniswap)], targetInput);
path.addFallback(fallback);
const sources = path.fills.map(f => f.source);
expect(sources).to.deep.eq([ERC20BridgeSource.Uniswap, ERC20BridgeSource.LiquidityProvider]);
});
});

View File

@@ -1,3 +1,4 @@
import { ChainId } from '@0x/contract-addresses';
import * as chai from 'chai';
import 'mocha';
@@ -49,7 +50,7 @@ describe('Pools Caches for Balancer-based sampling', () => {
});
describe('BalancerV2PoolsCache', () => {
const cache = new BalancerV2PoolsCache();
const cache = new BalancerV2PoolsCache(ChainId.Mainnet);
it('fetches pools', async () => {
const pairs = [
[wethAddress, wbtcAddress],