@0x/asset-swapper
: Support more varied curves.
This commit is contained in:
parent
b6700af6a8
commit
0450e430f1
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"version": "4.6.1",
|
||||
"version": "4.7.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Allow an empty override for sampler overrides",
|
||||
@ -9,6 +9,10 @@
|
||||
{
|
||||
"note": "Potentially heavy CPU functions inside the optimizer now yield to the event loop. As such they are now async.",
|
||||
"pr": 2637
|
||||
},
|
||||
{
|
||||
"note": "Support more varied curves",
|
||||
"pr": 2633
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -72,6 +72,7 @@ export {
|
||||
BalancerFillData,
|
||||
CollapsedFill,
|
||||
CurveFillData,
|
||||
CurveInfo,
|
||||
ERC20BridgeSource,
|
||||
FeeSchedule,
|
||||
FillData,
|
||||
@ -80,6 +81,7 @@ export {
|
||||
NativeFillData,
|
||||
OptimizedMarketOrder,
|
||||
UniswapV2FillData,
|
||||
CurveFunctionSelectors,
|
||||
} from './utils/market_operation_utils/types';
|
||||
export { ProtocolFeeUtils } from './utils/protocol_fee_utils';
|
||||
export { QuoteRequestor } from './utils/quote_requestor';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { ERC20BridgeSource, FakeBuyOpts, GetMarketOrdersOpts } from './types';
|
||||
import { CurveFunctionSelectors, CurveInfo, ERC20BridgeSource, GetMarketOrdersOpts } from './types';
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
@ -42,11 +42,6 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
|
||||
shouldBatchBridgeOrders: true,
|
||||
};
|
||||
|
||||
export const DEFAULT_FAKE_BUY_OPTS: FakeBuyOpts = {
|
||||
targetSlippageBps: new BigNumber(5),
|
||||
maxIterations: new BigNumber(5),
|
||||
};
|
||||
|
||||
/**
|
||||
* Sources to poll for ETH fee price estimates.
|
||||
*/
|
||||
@ -60,34 +55,82 @@ export const FEE_QUOTE_SOURCES = [
|
||||
/**
|
||||
* Mainnet Curve configuration
|
||||
*/
|
||||
export const MAINNET_CURVE_CONTRACTS: { [curveAddress: string]: string[] } = {
|
||||
'0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56': [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
||||
],
|
||||
'0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c': [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
|
||||
],
|
||||
'0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51': [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
|
||||
'0x0000000000085d4780b73119b644ae5ecd22b376', // TUSD
|
||||
],
|
||||
'0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27': [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
|
||||
'0x4fabb145d64652a948d72533023f6e7a623c7c53', // BUSD
|
||||
],
|
||||
'0xa5407eae9ba41422680e2e00537571bcc53efbfd': [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
|
||||
'0x57ab1ec28d129707052df4df418d58a2d46d5f51', // SUSD
|
||||
],
|
||||
export const MAINNET_CURVE_INFOS: { [name: string]: CurveInfo } = {
|
||||
// Busted?
|
||||
// DaiUsdc: {
|
||||
// exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
|
||||
// sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
|
||||
// buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
|
||||
// poolAddress: '0xa2b47e3d5c44877cca798226b7b8118f9bfb7a56',
|
||||
// tokens: ['0x6b175474e89094c44da98b954eedeac495271d0f', '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
|
||||
// },
|
||||
// Busted?
|
||||
// DaiUsdcUsdt: {
|
||||
// exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
|
||||
// sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
|
||||
// buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
|
||||
// poolAddress: '0x52ea46506b9cc5ef470c5bf89f17dc28bb35d85c',
|
||||
// tokens: [
|
||||
// '0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
// '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
// '0xdac17f958d2ee523a2206206994597c13d831ec7',
|
||||
// ],
|
||||
// },
|
||||
DaiUsdcUsdtTusd: {
|
||||
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
|
||||
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
|
||||
buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
|
||||
poolAddress: '0x45f783cce6b7ff23b2ab2d70e416cdb7d6055f51',
|
||||
tokens: [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7',
|
||||
'0x0000000000085d4780b73119b644ae5ecd22b376',
|
||||
],
|
||||
},
|
||||
// Looks like it's dying.
|
||||
DaiUsdcUsdtBusd: {
|
||||
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
|
||||
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
|
||||
buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
|
||||
poolAddress: '0x79a8c46dea5ada233abaffd40f3a0a2b1e5a4f27',
|
||||
tokens: [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7',
|
||||
'0x4fabb145d64652a948d72533023f6e7a623c7c53',
|
||||
],
|
||||
},
|
||||
DaiUsdcUsdtSusd: {
|
||||
exchangeFunctionSelector: CurveFunctionSelectors.exchange_underlying,
|
||||
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy_underlying,
|
||||
buyQuoteFunctionSelector: CurveFunctionSelectors.get_dx_underlying,
|
||||
poolAddress: '0xa5407eae9ba41422680e2e00537571bcc53efbfd',
|
||||
tokens: [
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7',
|
||||
'0x57ab1ec28d129707052df4df418d58a2d46d5f51',
|
||||
],
|
||||
},
|
||||
RenbtcWbtc: {
|
||||
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
|
||||
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
|
||||
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
|
||||
poolAddress: '0x93054188d876f558f4a66b2ef1d97d16edf0895b',
|
||||
tokens: ['0xeb4c2781e4eba804ce9a9803c67d0893436bb27d', '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599'],
|
||||
},
|
||||
RenbtcWbtcSbtc: {
|
||||
exchangeFunctionSelector: CurveFunctionSelectors.exchange,
|
||||
sellQuoteFunctionSelector: CurveFunctionSelectors.get_dy,
|
||||
buyQuoteFunctionSelector: CurveFunctionSelectors.None,
|
||||
poolAddress: '0x7fc77b5c7614e1533320ea6ddc2eb61fa00a9714',
|
||||
tokens: [
|
||||
'0xeb4c2781e4eba804ce9a9803c67d0893436bb27d',
|
||||
'0x2260fac5e5542a773aa44fbcfedf7c193bc2c599',
|
||||
'0xfe18be6b3bd88a2d2a7f928d00292e7a9963cfc6',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const ERC20_PROXY_ID = '0xf47261b0';
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { MAINNET_CURVE_CONTRACTS } from './constants';
|
||||
import { MAINNET_CURVE_INFOS } from './constants';
|
||||
import { CurveInfo } from './types';
|
||||
|
||||
// tslint:disable completed-docs
|
||||
export function getCurveAddressesForPair(takerToken: string, makerToken: string): string[] {
|
||||
return Object.keys(MAINNET_CURVE_CONTRACTS).filter(a =>
|
||||
[makerToken, takerToken].every(t => MAINNET_CURVE_CONTRACTS[a].includes(t)),
|
||||
);
|
||||
export function getCurveInfosForPair(takerToken: string, makerToken: string): CurveInfo[] {
|
||||
return Object.values(MAINNET_CURVE_INFOS).filter(c => [makerToken, takerToken].every(t => c.tokens.includes(t)));
|
||||
}
|
||||
|
@ -219,10 +219,11 @@ function createBridgeOrder(fill: CollapsedFill, opts: CreateOrderFromPathOpts):
|
||||
makerToken,
|
||||
bridgeAddress,
|
||||
createCurveBridgeData(
|
||||
curveFillData.poolAddress,
|
||||
curveFillData.curve.poolAddress,
|
||||
curveFillData.curve.exchangeFunctionSelector,
|
||||
takerToken,
|
||||
curveFillData.fromTokenIdx,
|
||||
curveFillData.toTokenIdx,
|
||||
1, // "version"
|
||||
),
|
||||
);
|
||||
break;
|
||||
@ -341,17 +342,25 @@ function createBalancerBridgeData(takerToken: string, poolAddress: string): stri
|
||||
|
||||
function createCurveBridgeData(
|
||||
curveAddress: string,
|
||||
exchangeFunctionSelector: string,
|
||||
takerToken: string,
|
||||
fromTokenIdx: number,
|
||||
toTokenIdx: number,
|
||||
version: number,
|
||||
): string {
|
||||
const curveBridgeDataEncoder = AbiEncoder.create([
|
||||
{ name: 'curveAddress', type: 'address' },
|
||||
{ name: 'exchangeFunctionSelector', type: 'bytes4' },
|
||||
{ name: 'fromTokenAddress', type: 'address' },
|
||||
{ name: 'fromTokenIdx', type: 'int128' },
|
||||
{ name: 'toTokenIdx', type: 'int128' },
|
||||
{ name: 'version', type: 'int128' },
|
||||
]);
|
||||
return curveBridgeDataEncoder.encode([curveAddress, fromTokenIdx, toTokenIdx, version]);
|
||||
return curveBridgeDataEncoder.encode([
|
||||
curveAddress,
|
||||
exchangeFunctionSelector,
|
||||
takerToken,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
]);
|
||||
}
|
||||
|
||||
function createUniswapV2BridgeData(tokenAddressPath: string[]): string {
|
||||
|
@ -3,15 +3,14 @@ import * as _ from 'lodash';
|
||||
import { BigNumber, ERC20BridgeSource, SignedOrder } from '../..';
|
||||
|
||||
import { BalancerPool, BalancerPoolsCache, computeBalancerBuyQuote, computeBalancerSellQuote } from './balancer_utils';
|
||||
import { DEFAULT_FAKE_BUY_OPTS, MAINNET_CURVE_CONTRACTS } from './constants';
|
||||
import { getCurveAddressesForPair } from './curve_utils';
|
||||
import { getCurveInfosForPair } from './curve_utils';
|
||||
import { getMultiBridgeIntermediateToken } from './multibridge_utils';
|
||||
import {
|
||||
BalancerFillData,
|
||||
BatchedOperation,
|
||||
CurveFillData,
|
||||
CurveInfo,
|
||||
DexSample,
|
||||
FakeBuyOpts,
|
||||
SourceQuoteOperation,
|
||||
UniswapV2FillData,
|
||||
} from './types';
|
||||
@ -58,17 +57,12 @@ export const samplerOperations = {
|
||||
},
|
||||
};
|
||||
},
|
||||
getKyberBuyQuotes(
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
fakeBuyOpts: FakeBuyOpts = DEFAULT_FAKE_BUY_OPTS,
|
||||
): SourceQuoteOperation {
|
||||
getKyberBuyQuotes(makerToken: string, takerToken: string, makerFillAmounts: BigNumber[]): SourceQuoteOperation {
|
||||
return {
|
||||
source: ERC20BridgeSource.Kyber,
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleBuysFromKyberNetwork(takerToken, makerToken, makerFillAmounts, fakeBuyOpts)
|
||||
.sampleBuysFromKyberNetwork(takerToken, makerToken, makerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
@ -162,19 +156,12 @@ export const samplerOperations = {
|
||||
makerToken: string,
|
||||
takerToken: string,
|
||||
makerFillAmounts: BigNumber[],
|
||||
fakeBuyOpts: FakeBuyOpts = DEFAULT_FAKE_BUY_OPTS,
|
||||
): SourceQuoteOperation {
|
||||
return {
|
||||
source: ERC20BridgeSource.LiquidityProvider,
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleBuysFromLiquidityProviderRegistry(
|
||||
registryAddress,
|
||||
takerToken,
|
||||
makerToken,
|
||||
makerFillAmounts,
|
||||
fakeBuyOpts,
|
||||
)
|
||||
.sampleBuysFromLiquidityProviderRegistry(registryAddress, takerToken, makerToken, makerFillAmounts)
|
||||
.getABIEncodedTransactionData();
|
||||
},
|
||||
handleCallResultsAsync: async (contract, callResults) => {
|
||||
@ -237,7 +224,7 @@ export const samplerOperations = {
|
||||
};
|
||||
},
|
||||
getCurveSellQuotes(
|
||||
curveAddress: string,
|
||||
curve: CurveInfo,
|
||||
fromTokenIdx: number,
|
||||
toTokenIdx: number,
|
||||
takerFillAmounts: BigNumber[],
|
||||
@ -245,14 +232,18 @@ export const samplerOperations = {
|
||||
return {
|
||||
source: ERC20BridgeSource.Curve,
|
||||
fillData: {
|
||||
poolAddress: curveAddress,
|
||||
curve,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
},
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleSellsFromCurve(
|
||||
curveAddress,
|
||||
{
|
||||
poolAddress: curve.poolAddress,
|
||||
sellQuoteFunctionSelector: curve.sellQuoteFunctionSelector,
|
||||
buyQuoteFunctionSelector: curve.buyQuoteFunctionSelector,
|
||||
},
|
||||
new BigNumber(fromTokenIdx),
|
||||
new BigNumber(toTokenIdx),
|
||||
takerFillAmounts,
|
||||
@ -265,7 +256,7 @@ export const samplerOperations = {
|
||||
};
|
||||
},
|
||||
getCurveBuyQuotes(
|
||||
curveAddress: string,
|
||||
curve: CurveInfo,
|
||||
fromTokenIdx: number,
|
||||
toTokenIdx: number,
|
||||
makerFillAmounts: BigNumber[],
|
||||
@ -273,14 +264,18 @@ export const samplerOperations = {
|
||||
return {
|
||||
source: ERC20BridgeSource.Curve,
|
||||
fillData: {
|
||||
poolAddress: curveAddress,
|
||||
curve,
|
||||
fromTokenIdx,
|
||||
toTokenIdx,
|
||||
},
|
||||
encodeCall: contract => {
|
||||
return contract
|
||||
.sampleBuysFromCurve(
|
||||
curveAddress,
|
||||
{
|
||||
poolAddress: curve.poolAddress,
|
||||
sellQuoteFunctionSelector: curve.sellQuoteFunctionSelector,
|
||||
buyQuoteFunctionSelector: curve.buyQuoteFunctionSelector,
|
||||
},
|
||||
new BigNumber(fromTokenIdx),
|
||||
new BigNumber(toTokenIdx),
|
||||
makerFillAmounts,
|
||||
@ -416,11 +411,11 @@ export const samplerOperations = {
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||
case ERC20BridgeSource.Curve:
|
||||
return getCurveAddressesForPair(takerToken, makerToken).map(curveAddress =>
|
||||
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
||||
samplerOperations.getCurveSellQuotes(
|
||||
curveAddress,
|
||||
MAINNET_CURVE_CONTRACTS[curveAddress].indexOf(takerToken),
|
||||
MAINNET_CURVE_CONTRACTS[curveAddress].indexOf(makerToken),
|
||||
curve,
|
||||
curve.tokens.indexOf(takerToken),
|
||||
curve.tokens.indexOf(makerToken),
|
||||
takerFillAmounts,
|
||||
),
|
||||
);
|
||||
@ -502,7 +497,6 @@ export const samplerOperations = {
|
||||
wethAddress: string,
|
||||
balancerPoolsCache?: BalancerPoolsCache,
|
||||
liquidityProviderRegistryAddress?: string,
|
||||
fakeBuyOpts: FakeBuyOpts = DEFAULT_FAKE_BUY_OPTS,
|
||||
): Promise<BatchedOperation<DexSample[][]>> => {
|
||||
const subOps = _.flatten(
|
||||
await Promise.all(
|
||||
@ -527,18 +521,13 @@ export const samplerOperations = {
|
||||
}
|
||||
return ops;
|
||||
case ERC20BridgeSource.Kyber:
|
||||
return samplerOperations.getKyberBuyQuotes(
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
fakeBuyOpts,
|
||||
);
|
||||
return samplerOperations.getKyberBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||
case ERC20BridgeSource.Curve:
|
||||
return getCurveAddressesForPair(takerToken, makerToken).map(curveAddress =>
|
||||
return getCurveInfosForPair(takerToken, makerToken).map(curve =>
|
||||
samplerOperations.getCurveBuyQuotes(
|
||||
curveAddress,
|
||||
MAINNET_CURVE_CONTRACTS[curveAddress].indexOf(takerToken),
|
||||
MAINNET_CURVE_CONTRACTS[curveAddress].indexOf(makerToken),
|
||||
curve,
|
||||
curve.tokens.indexOf(takerToken),
|
||||
curve.tokens.indexOf(makerToken),
|
||||
makerFillAmounts,
|
||||
),
|
||||
);
|
||||
@ -553,7 +542,6 @@ export const samplerOperations = {
|
||||
makerToken,
|
||||
takerToken,
|
||||
makerFillAmounts,
|
||||
fakeBuyOpts,
|
||||
);
|
||||
case ERC20BridgeSource.Balancer:
|
||||
if (balancerPoolsCache === undefined) {
|
||||
|
@ -37,6 +37,32 @@ export enum ERC20BridgeSource {
|
||||
Balancer = 'Balancer',
|
||||
}
|
||||
|
||||
// tslint:disable: enum-naming
|
||||
/**
|
||||
* Curve contract function selectors.
|
||||
*/
|
||||
export enum CurveFunctionSelectors {
|
||||
None = '0x00000000',
|
||||
exchange = '0x3df02124',
|
||||
exchange_underlying = '0xa6417ed6',
|
||||
get_dy_underlying = '0x07211ef7',
|
||||
get_dx_underlying = '0x0e71d1b9',
|
||||
get_dy = '0x5e0d443f',
|
||||
get_dx = '0x67df02ca',
|
||||
}
|
||||
// tslint:enable: enum-naming
|
||||
|
||||
/**
|
||||
* Configuration info on a Curve pool.
|
||||
*/
|
||||
export interface CurveInfo {
|
||||
exchangeFunctionSelector: CurveFunctionSelectors;
|
||||
sellQuoteFunctionSelector: CurveFunctionSelectors;
|
||||
buyQuoteFunctionSelector: CurveFunctionSelectors;
|
||||
poolAddress: string;
|
||||
tokens: string[];
|
||||
}
|
||||
|
||||
// Internal `fillData` field for `Fill` objects.
|
||||
export interface FillData {}
|
||||
|
||||
@ -46,9 +72,9 @@ export interface NativeFillData extends FillData {
|
||||
}
|
||||
|
||||
export interface CurveFillData extends FillData {
|
||||
poolAddress: string;
|
||||
fromTokenIdx: number;
|
||||
toTokenIdx: number;
|
||||
curve: CurveInfo;
|
||||
}
|
||||
|
||||
export interface BalancerFillData extends FillData {
|
||||
@ -228,12 +254,3 @@ export interface SourceQuoteOperation<TFillData extends FillData = FillData> ext
|
||||
source: ERC20BridgeSource;
|
||||
fillData?: TFillData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in the ERC20BridgeSampler when a source does not natively
|
||||
* support sampling via a specific buy amount.
|
||||
*/
|
||||
export interface FakeBuyOpts {
|
||||
targetSlippageBps: BigNumber;
|
||||
maxIterations: BigNumber;
|
||||
}
|
||||
|
@ -302,7 +302,17 @@ describe('MarketOperationUtils tests', () => {
|
||||
const DEFAULT_FILL_DATA: FillDataBySource = {
|
||||
[ERC20BridgeSource.UniswapV2]: { tokenAddressPath: [] },
|
||||
[ERC20BridgeSource.Balancer]: { poolAddress: randomAddress() },
|
||||
[ERC20BridgeSource.Curve]: { poolAddress: randomAddress(), fromTokenIdx: 0, toTokenIdx: 1 },
|
||||
[ERC20BridgeSource.Curve]: {
|
||||
curve: {
|
||||
poolAddress: randomAddress(),
|
||||
tokens: [TAKER_TOKEN, MAKER_TOKEN],
|
||||
exchangeFunctionSelector: hexUtils.random(4),
|
||||
sellQuoteFunctionSelector: hexUtils.random(4),
|
||||
buyQuoteFunctionSelector: hexUtils.random(4),
|
||||
},
|
||||
fromTokenIdx: 0,
|
||||
toTokenIdx: 1,
|
||||
},
|
||||
};
|
||||
|
||||
const DEFAULT_OPS = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user