Integrated CREAM into asset-swapper
This commit is contained in:
parent
c6b9ea5723
commit
c72aa653e8
@ -65,6 +65,10 @@
|
||||
{
|
||||
"note": "Added `Shell` into FQT",
|
||||
"pr": 2722
|
||||
},
|
||||
{
|
||||
"note": "Added `CREAM` into FQT",
|
||||
"pr": 2715
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -46,6 +46,7 @@ contract BridgeAdapter is
|
||||
{
|
||||
|
||||
address private immutable BALANCER_BRIDGE_ADDRESS;
|
||||
address private immutable CREAM_BRIDGE_ADDRESS;
|
||||
address private immutable CURVE_BRIDGE_ADDRESS;
|
||||
address private immutable KYBER_BRIDGE_ADDRESS;
|
||||
address private immutable MOONISWAP_BRIDGE_ADDRESS;
|
||||
@ -93,6 +94,7 @@ contract BridgeAdapter is
|
||||
SHELL_BRIDGE_ADDRESS = addresses.shellBridge;
|
||||
UNISWAP_BRIDGE_ADDRESS = addresses.uniswapBridge;
|
||||
UNISWAP_V2_BRIDGE_ADDRESS = addresses.uniswapV2Bridge;
|
||||
CREAM_BRIDGE_ADDRESS = addresses.creamBridge;
|
||||
}
|
||||
|
||||
function trade(
|
||||
@ -170,6 +172,12 @@ contract BridgeAdapter is
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else if (bridgeAddress == CREAM_BRIDGE_ADDRESS) {
|
||||
boughtAmount = _tradeBalancer(
|
||||
buyToken,
|
||||
sellAmount,
|
||||
bridgeData
|
||||
);
|
||||
} else {
|
||||
boughtAmount = _tradeZeroExBridge(
|
||||
bridgeAddress,
|
||||
|
@ -24,6 +24,7 @@ contract MixinAdapterAddresses
|
||||
struct AdapterAddresses {
|
||||
// Bridges
|
||||
address balancerBridge;
|
||||
address creamBridge;
|
||||
address curveBridge;
|
||||
address kyberBridge;
|
||||
address mooniswapBridge;
|
||||
|
@ -75,6 +75,7 @@ blockchainTests.resets('FillQuoteTransformer', env => {
|
||||
weth: NULL_ADDRESS,
|
||||
shellBridge: NULL_ADDRESS,
|
||||
shell: NULL_ADDRESS,
|
||||
creamBridge: NULL_ADDRESS,
|
||||
},
|
||||
);
|
||||
transformer = await FillQuoteTransformerContract.deployFrom0xArtifactAsync(
|
||||
|
@ -73,6 +73,7 @@
|
||||
"@bancor/sdk": "^0.2.9",
|
||||
"axios": "^0.19.2",
|
||||
"axios-mock-adapter": "^1.18.1",
|
||||
"cream-sor": "^0.3.3",
|
||||
"decimal.js": "^10.2.0",
|
||||
"ethereum-types": "^3.2.0",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
|
@ -0,0 +1,104 @@
|
||||
import { getPoolsWithTokens, parsePoolData } from 'cream-sor';
|
||||
|
||||
import { BalancerPool } from './balancer_utils';
|
||||
|
||||
// tslint:disable:boolean-naming
|
||||
|
||||
interface CacheValue {
|
||||
timestamp: number;
|
||||
pools: BalancerPool[];
|
||||
}
|
||||
|
||||
// tslint:disable:custom-no-magic-numbers
|
||||
const FIVE_SECONDS_MS = 5 * 1000;
|
||||
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
||||
const DEFAULT_TIMEOUT_MS = 1000;
|
||||
const MAX_POOLS_FETCHED = 3;
|
||||
// tslint:enable:custom-no-magic-numbers
|
||||
|
||||
export class CreamPoolsCache {
|
||||
constructor(
|
||||
private readonly _cache: { [key: string]: CacheValue } = {},
|
||||
private readonly maxPoolsFetched: number = MAX_POOLS_FETCHED,
|
||||
) {}
|
||||
|
||||
public async getPoolsForPairAsync(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
timeoutMs: number = DEFAULT_TIMEOUT_MS,
|
||||
): Promise<BalancerPool[]> {
|
||||
const timeout = new Promise<BalancerPool[]>(resolve => setTimeout(resolve, timeoutMs, []));
|
||||
return Promise.race([this._getPoolsForPairAsync(takerToken, makerToken), timeout]);
|
||||
}
|
||||
|
||||
public getCachedPoolAddressesForPair(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
cacheExpiryMs?: number,
|
||||
): string[] | undefined {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
const value = this._cache[key];
|
||||
if (cacheExpiryMs === undefined) {
|
||||
return value === undefined ? [] : value.pools.map(pool => pool.id);
|
||||
}
|
||||
const minTimestamp = Date.now() - cacheExpiryMs;
|
||||
if (value === undefined || value.timestamp < minTimestamp) {
|
||||
return undefined;
|
||||
} else {
|
||||
return value.pools.map(pool => pool.id);
|
||||
}
|
||||
}
|
||||
|
||||
public howToSampleCream(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
isAllowedSource: boolean,
|
||||
): { onChain: boolean; offChain: boolean } {
|
||||
// If Balancer is excluded as a source, do not sample.
|
||||
if (!isAllowedSource) {
|
||||
return { onChain: false, offChain: false };
|
||||
}
|
||||
const cachedCreamPools = this.getCachedPoolAddressesForPair(takerToken, makerToken, ONE_DAY_MS);
|
||||
// Sample CREAM on-chain (i.e. via the ERC20BridgeSampler contract) if:
|
||||
// - Cached values are not stale
|
||||
// - There is at least one CREAM pool for this pair
|
||||
const onChain = cachedCreamPools !== undefined && cachedCreamPools.length > 0;
|
||||
// Sample Balancer off-chain (i.e. via GraphQL query + `computeCreamBuy/SellQuote`)
|
||||
// if cached values are stale
|
||||
const offChain = cachedCreamPools === undefined;
|
||||
return { onChain, offChain };
|
||||
}
|
||||
|
||||
protected async _getPoolsForPairAsync(
|
||||
takerToken: string,
|
||||
makerToken: string,
|
||||
cacheExpiryMs: number = FIVE_SECONDS_MS,
|
||||
): Promise<BalancerPool[]> {
|
||||
const key = JSON.stringify([takerToken, makerToken]);
|
||||
const value = this._cache[key];
|
||||
const minTimestamp = Date.now() - cacheExpiryMs;
|
||||
if (value === undefined || value.timestamp < minTimestamp) {
|
||||
const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken);
|
||||
const timestamp = Date.now();
|
||||
this._cache[key] = {
|
||||
pools,
|
||||
timestamp,
|
||||
};
|
||||
}
|
||||
return this._cache[key].pools;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:prefer-function-over-method
|
||||
protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<BalancerPool[]> {
|
||||
try {
|
||||
const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools;
|
||||
// Sort by maker token balance (descending)
|
||||
const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) =>
|
||||
b.balanceOut.minus(a.balanceOut).toNumber(),
|
||||
);
|
||||
return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools;
|
||||
} catch (err) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
@ -150,6 +150,23 @@ export class MarketOperationUtils {
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.Balancer),
|
||||
);
|
||||
|
||||
const {
|
||||
onChain: sampleCreamOnChain,
|
||||
offChain: sampleCreamOffChain,
|
||||
} = this._sampler.creamPoolsCache.howToSampleCream(
|
||||
takerToken,
|
||||
makerToken,
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.Cream),
|
||||
);
|
||||
|
||||
let excludedSources: ERC20BridgeSource[] = [];
|
||||
if (!sampleCreamOnChain) {
|
||||
excludedSources = excludedSources.concat(ERC20BridgeSource.Cream);
|
||||
}
|
||||
if (!sampleBalancerOnChain) {
|
||||
excludedSources = excludedSources.concat(ERC20BridgeSource.Balancer);
|
||||
}
|
||||
|
||||
// Call the sampler contract.
|
||||
const samplerPromise = this._sampler.executeAsync(
|
||||
// Get native order fillable amounts.
|
||||
@ -176,7 +193,7 @@ export class MarketOperationUtils {
|
||||
),
|
||||
// Get sell quotes for taker -> maker.
|
||||
this._sampler.getSellQuotes(
|
||||
quoteSourceFilters.exclude(sampleBalancerOnChain ? [] : ERC20BridgeSource.Balancer).sources,
|
||||
quoteSourceFilters.exclude(excludedSources).sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
sampleAmounts,
|
||||
@ -209,6 +226,10 @@ export class MarketOperationUtils {
|
||||
? this._sampler.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const offChainCreamPromise = sampleCreamOffChain
|
||||
? this._sampler.getCreamSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const offChainBancorPromise = quoteSourceFilters.isAllowed(ERC20BridgeSource.Bancor)
|
||||
? this._sampler.getBancorSellQuotesOffChainAsync(makerToken, takerToken, [takerAmount])
|
||||
: Promise.resolve([]);
|
||||
@ -217,15 +238,16 @@ export class MarketOperationUtils {
|
||||
[orderFillableAmounts, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes, twoHopQuotes],
|
||||
rfqtIndicativeQuotes,
|
||||
offChainBalancerQuotes,
|
||||
offChainCreamQuotes,
|
||||
offChainBancorQuotes,
|
||||
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainBancorPromise]);
|
||||
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise, offChainBancorPromise]);
|
||||
|
||||
return {
|
||||
side: MarketOperation.Sell,
|
||||
inputAmount: takerAmount,
|
||||
inputToken: takerToken,
|
||||
outputToken: makerToken,
|
||||
dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, offChainBancorQuotes]),
|
||||
dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, ...offChainCreamQuotes, offChainBancorQuotes]),
|
||||
nativeOrders,
|
||||
orderFillableAmounts,
|
||||
ethToOutputRate: ethToMakerAssetRate,
|
||||
@ -266,6 +288,23 @@ export class MarketOperationUtils {
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.Balancer),
|
||||
);
|
||||
|
||||
const {
|
||||
onChain: sampleCreamOnChain,
|
||||
offChain: sampleCreamOffChain,
|
||||
} = this._sampler.creamPoolsCache.howToSampleCream(
|
||||
takerToken,
|
||||
makerToken,
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.Cream),
|
||||
);
|
||||
|
||||
let excludedSources: ERC20BridgeSource[] = [];
|
||||
if (!sampleCreamOnChain) {
|
||||
excludedSources = excludedSources.concat(ERC20BridgeSource.Cream);
|
||||
}
|
||||
if (!sampleBalancerOnChain) {
|
||||
excludedSources = excludedSources.concat(ERC20BridgeSource.Balancer);
|
||||
}
|
||||
|
||||
// Call the sampler contract.
|
||||
const samplerPromise = this._sampler.executeAsync(
|
||||
// Get native order fillable amounts.
|
||||
@ -292,7 +331,7 @@ export class MarketOperationUtils {
|
||||
),
|
||||
// Get buy quotes for taker -> maker.
|
||||
this._sampler.getBuyQuotes(
|
||||
quoteSourceFilters.exclude(sampleBalancerOnChain ? [] : ERC20BridgeSource.Balancer).sources,
|
||||
quoteSourceFilters.exclude(excludedSources).sources,
|
||||
makerToken,
|
||||
takerToken,
|
||||
sampleAmounts,
|
||||
@ -324,11 +363,16 @@ export class MarketOperationUtils {
|
||||
? this._sampler.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const offChainCreamPromise = sampleCreamOffChain
|
||||
? this._sampler.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const [
|
||||
[orderFillableAmounts, ethToMakerAssetRate, ethToTakerAssetRate, dexQuotes, twoHopQuotes],
|
||||
rfqtIndicativeQuotes,
|
||||
offChainBalancerQuotes,
|
||||
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise]);
|
||||
offChainCreamQuotes,
|
||||
] = await Promise.all([samplerPromise, rfqtPromise, offChainBalancerPromise, offChainCreamPromise]);
|
||||
// Attach the MultiBridge address to the sample fillData
|
||||
(dexQuotes.find(quotes => quotes[0] && quotes[0].source === ERC20BridgeSource.MultiBridge) || []).forEach(
|
||||
q => (q.fillData = { poolAddress: this._multiBridge }),
|
||||
@ -338,7 +382,7 @@ export class MarketOperationUtils {
|
||||
inputAmount: makerAmount,
|
||||
inputToken: makerToken,
|
||||
outputToken: takerToken,
|
||||
dexQuotes: dexQuotes.concat(offChainBalancerQuotes),
|
||||
dexQuotes: dexQuotes.concat(offChainBalancerQuotes, offChainCreamQuotes),
|
||||
nativeOrders,
|
||||
orderFillableAmounts,
|
||||
ethToOutputRate: ethToTakerAssetRate,
|
||||
|
@ -6,6 +6,7 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
|
||||
import { BalancerPoolsCache } from './balancer_utils';
|
||||
import { BancorService } from './bancor_service';
|
||||
import { CreamPoolsCache } from './cream_utils';
|
||||
import { SamplerOperations } from './sampler_operations';
|
||||
import { BatchedOperation } from './types';
|
||||
|
||||
@ -37,9 +38,10 @@ export class DexOrderSampler extends SamplerOperations {
|
||||
private readonly _samplerOverrides?: SamplerOverrides,
|
||||
provider?: SupportedProvider,
|
||||
balancerPoolsCache?: BalancerPoolsCache,
|
||||
creamPoolsCache?: CreamPoolsCache,
|
||||
getBancorServiceFn?: () => BancorService,
|
||||
) {
|
||||
super(_samplerContract, provider, balancerPoolsCache, getBancorServiceFn);
|
||||
super(_samplerContract, provider, balancerPoolsCache, creamPoolsCache, getBancorServiceFn);
|
||||
}
|
||||
|
||||
/* Type overloads for `executeAsync()`. Could skip this if we would upgrade TS. */
|
||||
|
@ -8,6 +8,7 @@ import { ERC20BridgeSamplerContract } from '../../wrappers';
|
||||
import { BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
|
||||
import { BancorService } from './bancor_service';
|
||||
import { MAINNET_SUSHI_SWAP_ROUTER, MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } from './constants';
|
||||
import { CreamPoolsCache } from './cream_utils';
|
||||
import { getCurveInfosForPair, getSwerveInfosForPair } from './curve_utils';
|
||||
import { getKyberReserveIdsForPair } from './kyber_utils';
|
||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||
@ -18,6 +19,7 @@ import {
|
||||
BalancerFillData,
|
||||
BancorFillData,
|
||||
BatchedOperation,
|
||||
CreamFillData,
|
||||
CurveFillData,
|
||||
CurveInfo,
|
||||
DexSample,
|
||||
@ -72,6 +74,7 @@ export class SamplerOperations {
|
||||
protected readonly _samplerContract: ERC20BridgeSamplerContract,
|
||||
public readonly provider?: SupportedProvider,
|
||||
public readonly balancerPoolsCache: BalancerPoolsCache = new BalancerPoolsCache(),
|
||||
public readonly creamPoolsCache: CreamPoolsCache = new CreamPoolsCache(),
|
||||
protected readonly getBancorServiceFn?: () => BancorService, // for dependency injection in tests
|
||||
) {}
|
||||
|
||||
@ -466,6 +469,68 @@ export class SamplerOperations {
|
||||
);
|
||||
}
|
||||
|
||||
public getCreamSellQuotes(
|
||||
poolAddress: string,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<CreamFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Cream,
|
||||
fillData: { poolAddress },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleSellsFromBalancer,
|
||||
params: [poolAddress, takerToken, makerToken, takerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public getCreamBuyQuotes(
|
||||
poolAddress: string,
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): SourceQuoteOperation<CreamFillData> {
|
||||
return new SamplerContractOperation({
|
||||
source: ERC20BridgeSource.Cream,
|
||||
fillData: { poolAddress },
|
||||
contract: this._samplerContract,
|
||||
function: this._samplerContract.sampleBuysFromBalancer,
|
||||
params: [poolAddress, takerToken, makerToken, makerFillAmounts],
|
||||
});
|
||||
}
|
||||
|
||||
public async getCreamSellQuotesOffChainAsync(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
): Promise<Array<Array<DexSample<CreamFillData>>>> {
|
||||
const pools = await this.creamPoolsCache.getPoolsForPairAsync(takerToken, makerToken);
|
||||
return pools.map(pool =>
|
||||
takerFillAmounts.map(amount => ({
|
||||
source: ERC20BridgeSource.Balancer,
|
||||
output: computeBalancerSellQuote(pool, amount),
|
||||
input: amount,
|
||||
fillData: { poolAddress: pool.id },
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
public async getCreamBuyQuotesOffChainAsync(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
): Promise<Array<Array<DexSample<BalancerFillData>>>> {
|
||||
const pools = await this.creamPoolsCache.getPoolsForPairAsync(takerToken, makerToken);
|
||||
return pools.map(pool =>
|
||||
makerFillAmounts.map(amount => ({
|
||||
source: ERC20BridgeSource.Balancer,
|
||||
output: computeBalancerBuyQuote(pool, amount),
|
||||
input: amount,
|
||||
fillData: { poolAddress: pool.id },
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
public getMStableSellQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
@ -997,6 +1062,12 @@ export class SamplerOperations {
|
||||
.map(poolAddress =>
|
||||
this.getBalancerSellQuotes(poolAddress, makerToken, takerToken, takerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.Cream:
|
||||
return this.creamPoolsCache
|
||||
.getCachedPoolAddressesForPair(takerToken, makerToken)!
|
||||
.map(poolAddress =>
|
||||
this.getBalancerSellQuotes(poolAddress, makerToken, takerToken, takerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.Shell:
|
||||
return this.getShellSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
default:
|
||||
@ -1086,6 +1157,12 @@ export class SamplerOperations {
|
||||
.map(poolAddress =>
|
||||
this.getBalancerBuyQuotes(poolAddress, makerToken, takerToken, makerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.Cream:
|
||||
return this.creamPoolsCache
|
||||
.getCachedPoolAddressesForPair(takerToken, makerToken)!
|
||||
.map(poolAddress =>
|
||||
this.getBalancerBuyQuotes(poolAddress, makerToken, takerToken, makerFillAmounts),
|
||||
);
|
||||
case ERC20BridgeSource.Shell:
|
||||
return this.getShellBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
default:
|
||||
|
@ -37,6 +37,7 @@ export enum ERC20BridgeSource {
|
||||
LiquidityProvider = 'LiquidityProvider',
|
||||
MultiBridge = 'MultiBridge',
|
||||
Balancer = 'Balancer',
|
||||
Cream = 'CREAM',
|
||||
Bancor = 'Bancor',
|
||||
MStable = 'mStable',
|
||||
Mooniswap = 'Mooniswap',
|
||||
@ -103,6 +104,10 @@ export interface BalancerFillData extends FillData {
|
||||
poolAddress: string;
|
||||
}
|
||||
|
||||
export interface CreamFillData extends FillData {
|
||||
poolAddress: string;
|
||||
}
|
||||
|
||||
export interface UniswapV2FillData extends FillData {
|
||||
tokenAddressPath: string[];
|
||||
}
|
||||
|
@ -504,6 +504,7 @@ describe('DexSampler tests', () => {
|
||||
undefined, // sampler overrides
|
||||
provider,
|
||||
undefined, // balancer cache
|
||||
undefined, // cream cache
|
||||
() => bancorService,
|
||||
);
|
||||
const quotes = await dexOrderSampler.getBancorSellQuotesOffChainAsync(
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
SOURCE_FLAGS,
|
||||
ZERO_AMOUNT,
|
||||
} from '../src/utils/market_operation_utils/constants';
|
||||
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';
|
||||
@ -51,6 +52,7 @@ const DEFAULT_EXCLUDED = [
|
||||
ERC20BridgeSource.SushiSwap,
|
||||
ERC20BridgeSource.MultiHop,
|
||||
ERC20BridgeSource.Shell,
|
||||
ERC20BridgeSource.Cream,
|
||||
];
|
||||
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
|
||||
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
|
||||
@ -288,6 +290,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.SushiSwap]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.MultiHop]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Shell]: _.times(NUM_SAMPLES, () => 0),
|
||||
[ERC20BridgeSource.Cream]: _.times(NUM_SAMPLES, () => 0),
|
||||
};
|
||||
|
||||
const DEFAULT_RATES: RatesBySource = {
|
||||
@ -334,6 +337,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
[ERC20BridgeSource.Native]: { order: createOrder() },
|
||||
[ERC20BridgeSource.MultiHop]: {},
|
||||
[ERC20BridgeSource.Shell]: {},
|
||||
[ERC20BridgeSource.Cream]: { poolAddress: randomAddress() },
|
||||
};
|
||||
|
||||
const DEFAULT_OPS = {
|
||||
@ -370,6 +374,30 @@ describe('MarketOperationUtils tests', () => {
|
||||
DEFAULT_FILL_DATA[ERC20BridgeSource.Balancer],
|
||||
),
|
||||
],
|
||||
getCreamSellQuotesOffChainAsync: (
|
||||
_makerToken: string,
|
||||
_takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
) => [
|
||||
createSamplesFromRates(
|
||||
ERC20BridgeSource.Cream,
|
||||
takerFillAmounts,
|
||||
createDecreasingRates(takerFillAmounts.length),
|
||||
DEFAULT_FILL_DATA[ERC20BridgeSource.Cream],
|
||||
),
|
||||
],
|
||||
getCreamBuyQuotesOffChainAsync: (
|
||||
_makerToken: string,
|
||||
_takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
) => [
|
||||
createSamplesFromRates(
|
||||
ERC20BridgeSource.Cream,
|
||||
makerFillAmounts,
|
||||
createDecreasingRates(makerFillAmounts.length).map(r => new BigNumber(1).div(r)),
|
||||
DEFAULT_FILL_DATA[ERC20BridgeSource.Cream],
|
||||
),
|
||||
],
|
||||
getBancorSellQuotesOffChainAsync: (_makerToken: string, _takerToken: string, takerFillAmounts: BigNumber[]) =>
|
||||
createSamplesFromRates(
|
||||
ERC20BridgeSource.Bancor,
|
||||
@ -389,6 +417,7 @@ describe('MarketOperationUtils tests', () => {
|
||||
return ops;
|
||||
},
|
||||
balancerPoolsCache: new BalancerPoolsCache(),
|
||||
creamPoolsCache: new CreamPoolsCache(),
|
||||
} as any) as DexOrderSampler;
|
||||
|
||||
function replaceSamplerOps(ops: Partial<typeof DEFAULT_OPS> = {}): void {
|
||||
@ -492,6 +521,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
getCreamSellQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
});
|
||||
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||
...DEFAULT_OPTS,
|
||||
@ -522,6 +559,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
args.sources = args.sources.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
getCreamSellQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
args.sources = args.sources.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
});
|
||||
const registryAddress = randomAddress();
|
||||
const newMarketOperationUtils = new MarketOperationUtils(
|
||||
@ -563,6 +608,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
getCreamSellQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
});
|
||||
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||
...DEFAULT_OPTS,
|
||||
@ -594,6 +647,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
getCreamSellQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
takerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamSellQuotesOffChainAsync(makerToken, takerToken, takerFillAmounts);
|
||||
},
|
||||
});
|
||||
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||
...DEFAULT_OPTS,
|
||||
@ -984,6 +1045,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
getCreamBuyQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
});
|
||||
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||
...DEFAULT_OPTS,
|
||||
@ -1014,6 +1083,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
args.sources = args.sources.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
getCreamBuyQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
args.sources = args.sources.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
});
|
||||
const registryAddress = randomAddress();
|
||||
const newMarketOperationUtils = new MarketOperationUtils(
|
||||
@ -1055,6 +1132,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
getCreamBuyQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
});
|
||||
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||
...DEFAULT_OPTS,
|
||||
@ -1086,6 +1171,14 @@ describe('MarketOperationUtils tests', () => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Balancer);
|
||||
return DEFAULT_OPS.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
getCreamBuyQuotesOffChainAsync: (
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
) => {
|
||||
sourcesPolled = sourcesPolled.concat(ERC20BridgeSource.Cream);
|
||||
return DEFAULT_OPS.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, makerFillAmounts);
|
||||
},
|
||||
});
|
||||
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||
...DEFAULT_OPTS,
|
||||
|
@ -325,6 +325,7 @@ export async function runMigrationsAsync(
|
||||
uniswapExchangeFactory: NULL_ADDRESS,
|
||||
mStable: NULL_ADDRESS,
|
||||
shellBridge: NULL_ADDRESS,
|
||||
creamBridge: NULL_ADDRESS,
|
||||
shell: NULL_ADDRESS,
|
||||
weth: etherToken.address,
|
||||
},
|
||||
|
@ -5510,6 +5510,14 @@ coveralls@^3.0.0:
|
||||
minimist "^1.2.0"
|
||||
request "^2.79.0"
|
||||
|
||||
cream-sor@^0.3.3:
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/cream-sor/-/cream-sor-0.3.3.tgz#ae7ab50c68cfd36a89e2101187ceebbb79e1b14c"
|
||||
integrity sha512-taQSvCUunPhwyebwbjxh1l9NDp39lsre+Q2oRMK+gqzbu+Wlbg5GAquwoV2/GLgzia70gi4x1rJCJsUmc5Kygg==
|
||||
dependencies:
|
||||
bignumber.js "^9.0.0"
|
||||
isomorphic-fetch "^2.2.1"
|
||||
|
||||
create-ecdh@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.1.tgz#44223dfed533193ba5ba54e0df5709b89acf1f82"
|
||||
|
Loading…
x
Reference in New Issue
Block a user