* feat: mStable * deploy and CHANGELOG * `@0x/contracts-utils`: Add more testnet addresses. * `@0x/contract-addresses`: Deply Mstable on testnets * `@0x/contract-addresses`: Remove testnet deployments of mStable :-) * move `erc20-bridge-sampler` into `asset-swapper` remove `DevUtils` dependency from sampler contract. * `@0x/asset-swapper`: Add ERC20BridgeSampler support for validating orders in maker fees denominated in non-maker assets. `@0x/asset-swapper`: Add tests for `NativeOrderSampler`. * `@0x/asset-swapper`: Return `0` sample if native order asset data is unsupported. * `@0x/asset-swapper`: Fix failing test. * feat: ExchangeProxy FQT fruit rollup (#2645) * feat: Optimize Bridges in ExchangeProxy * compile and most work * work around to trust the delecall contract * force allowances * Update Kyber/Eth2Dai bridges * Remove memory state where not required * cleanup * Combine Bridges into one adapter * mixins * refactor out ZeroExBridge * move out interface * comment out hacks * update migrations * remove simbot hacks * AdapterAddresses and mStable * Share constructor arg * fix migration * Remove whitespace * `@0x/contracts-zero-ex`: BridgeAdapter -- revert if bridge address is 0. * `@0x/contract-addresses`: Deploy FQT. Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: Lawrence Forman <lawrence@0xproject.com> * update ganache contract addresses * fix: asset-swapper empty batch call (#2669) * update ganache contract addresses * fix: asset-swapper prevent empty sampler batch call * add sampler to migrations * change migrations version * Use contract-wrappers and artifacts * remove extra data * remove deps, set sampler to NULL_ADDRESS * all the exports * noop sell rate too * update ganache contract addresses Co-authored-by: Lawrence Forman <me@merklejerk.com> Co-authored-by: Lawrence Forman <lawrence@0xproject.com>
272 lines
9.1 KiB
TypeScript
272 lines
9.1 KiB
TypeScript
import { ContractFunctionObj } from '@0x/base-contract';
|
|
import { constants } from '@0x/contracts-test-utils';
|
|
import { Order } from '@0x/types';
|
|
import { BigNumber, hexUtils } from '@0x/utils';
|
|
|
|
import { ERC20BridgeSamplerContract } from '../../src/wrappers';
|
|
|
|
export type GetOrderFillableAssetAmountResult = BigNumber[];
|
|
export type GetOrderFillableAssetAmountHandler = (
|
|
orders: Order[],
|
|
signatures: string[],
|
|
devUtilsAddress: string,
|
|
) => GetOrderFillableAssetAmountResult;
|
|
|
|
export type SampleResults = BigNumber[];
|
|
export type SampleSellsHandler = (
|
|
takerToken: string,
|
|
makerToken: string,
|
|
takerTokenAmounts: BigNumber[],
|
|
) => SampleResults;
|
|
export type SampleBuysHandler = (
|
|
takerToken: string,
|
|
makerToken: string,
|
|
makerTokenAmounts: BigNumber[],
|
|
) => SampleResults;
|
|
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
|
export type SampleSellsLPHandler = (
|
|
registryAddress: string,
|
|
takerToken: string,
|
|
makerToken: string,
|
|
takerTokenAmounts: BigNumber[],
|
|
) => SampleResults;
|
|
export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
|
export type SampleSellsMBHandler = (
|
|
multiBridgeAddress: string,
|
|
takerToken: string,
|
|
intermediateToken: string,
|
|
makerToken: string,
|
|
takerTokenAmounts: BigNumber[],
|
|
) => SampleResults;
|
|
|
|
const DUMMY_PROVIDER = {
|
|
sendAsync: (...args: any[]): any => {
|
|
/* no-op */
|
|
},
|
|
};
|
|
|
|
interface Handlers {
|
|
getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
|
getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler;
|
|
sampleSellsFromKyberNetwork: SampleSellsHandler;
|
|
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
|
sampleSellsFromMultiBridge: SampleSellsMBHandler;
|
|
sampleSellsFromEth2Dai: SampleSellsHandler;
|
|
sampleSellsFromUniswap: SampleSellsHandler;
|
|
sampleSellsFromUniswapV2: SampleSellsMultihopHandler;
|
|
sampleBuysFromEth2Dai: SampleBuysHandler;
|
|
sampleBuysFromUniswap: SampleBuysHandler;
|
|
sampleBuysFromUniswapV2: SampleBuysMultihopHandler;
|
|
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
|
}
|
|
|
|
// tslint:disable: no-unbound-method
|
|
|
|
export class MockSamplerContract extends ERC20BridgeSamplerContract {
|
|
private readonly _handlers: Partial<Handlers> = {};
|
|
|
|
public constructor(handlers: Partial<Handlers> = {}) {
|
|
super(constants.NULL_ADDRESS, DUMMY_PROVIDER);
|
|
this._handlers = handlers;
|
|
}
|
|
|
|
public batchCall(callDatas: string[]): ContractFunctionObj<string[]> {
|
|
return {
|
|
...super.batchCall(callDatas),
|
|
callAsync: async (...callArgs: any[]) => callDatas.map(callData => this._callEncodedFunction(callData)),
|
|
};
|
|
}
|
|
|
|
public getOrderFillableMakerAssetAmounts(
|
|
orders: Order[],
|
|
signatures: string[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.getOrderFillableMakerAssetAmounts,
|
|
this._handlers.getOrderFillableMakerAssetAmounts,
|
|
orders,
|
|
signatures,
|
|
constants.NULL_ADDRESS,
|
|
);
|
|
}
|
|
|
|
public getOrderFillableTakerAssetAmounts(
|
|
orders: Order[],
|
|
signatures: string[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.getOrderFillableTakerAssetAmounts,
|
|
this._handlers.getOrderFillableTakerAssetAmounts,
|
|
orders,
|
|
signatures,
|
|
constants.NULL_ADDRESS,
|
|
);
|
|
}
|
|
|
|
public sampleSellsFromKyberNetwork(
|
|
takerToken: string,
|
|
makerToken: string,
|
|
takerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleSellsFromKyberNetwork,
|
|
this._handlers.sampleSellsFromKyberNetwork,
|
|
takerToken,
|
|
makerToken,
|
|
takerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleSellsFromEth2Dai(
|
|
takerToken: string,
|
|
makerToken: string,
|
|
takerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleSellsFromEth2Dai,
|
|
this._handlers.sampleSellsFromEth2Dai,
|
|
takerToken,
|
|
makerToken,
|
|
takerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleSellsFromUniswap(
|
|
takerToken: string,
|
|
makerToken: string,
|
|
takerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleSellsFromUniswap,
|
|
this._handlers.sampleSellsFromUniswap,
|
|
takerToken,
|
|
makerToken,
|
|
takerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleSellsFromUniswapV2(
|
|
path: string[],
|
|
takerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleSellsFromUniswapV2,
|
|
this._handlers.sampleSellsFromUniswapV2,
|
|
path,
|
|
takerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleSellsFromLiquidityProviderRegistry(
|
|
registryAddress: string,
|
|
takerToken: string,
|
|
makerToken: string,
|
|
takerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleSellsFromLiquidityProviderRegistry,
|
|
this._handlers.sampleSellsFromLiquidityProviderRegistry,
|
|
registryAddress,
|
|
takerToken,
|
|
makerToken,
|
|
takerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleSellsFromMultiBridge(
|
|
multiBridgeAddress: string,
|
|
takerToken: string,
|
|
intermediateToken: string,
|
|
makerToken: string,
|
|
takerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleSellsFromMultiBridge,
|
|
this._handlers.sampleSellsFromMultiBridge,
|
|
multiBridgeAddress,
|
|
takerToken,
|
|
intermediateToken,
|
|
makerToken,
|
|
takerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleBuysFromEth2Dai(
|
|
takerToken: string,
|
|
makerToken: string,
|
|
makerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleBuysFromEth2Dai,
|
|
this._handlers.sampleBuysFromEth2Dai,
|
|
takerToken,
|
|
makerToken,
|
|
makerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleBuysFromUniswap(
|
|
takerToken: string,
|
|
makerToken: string,
|
|
makerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleBuysFromUniswap,
|
|
this._handlers.sampleBuysFromUniswap,
|
|
takerToken,
|
|
makerToken,
|
|
makerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
public sampleBuysFromUniswapV2(
|
|
path: string[],
|
|
makerAssetAmounts: BigNumber[],
|
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
|
return this._wrapCall(
|
|
super.sampleBuysFromUniswapV2,
|
|
this._handlers.sampleBuysFromUniswapV2,
|
|
path,
|
|
makerAssetAmounts,
|
|
);
|
|
}
|
|
|
|
private _callEncodedFunction(callData: string): string {
|
|
if (callData === '0x') {
|
|
return callData;
|
|
}
|
|
// tslint:disable-next-line: custom-no-magic-numbers
|
|
const selector = hexUtils.slice(callData, 0, 4);
|
|
for (const [name, handler] of Object.entries(this._handlers)) {
|
|
if (handler && this.getSelector(name) === selector) {
|
|
const args = this.getABIDecodedTransactionData<any>(name, callData);
|
|
const result = (handler as any)(...args);
|
|
return this._lookupAbiEncoder(this.getFunctionSignature(name)).encodeReturnValues([result]);
|
|
}
|
|
}
|
|
if (selector === this.getSelector('batchCall')) {
|
|
const calls = this.getABIDecodedTransactionData<string[]>('batchCall', callData);
|
|
const results = calls.map(cd => this._callEncodedFunction(cd));
|
|
return this._lookupAbiEncoder(this.getFunctionSignature('batchCall')).encodeReturnValues([results]);
|
|
}
|
|
throw new Error(`Unkown selector: ${selector}`);
|
|
}
|
|
|
|
private _wrapCall<TArgs extends any[], TResult>(
|
|
superFn: (this: MockSamplerContract, ...args: TArgs) => ContractFunctionObj<TResult>,
|
|
handler?: (this: MockSamplerContract, ...args: TArgs) => TResult,
|
|
// tslint:disable-next-line: trailing-comma
|
|
...args: TArgs
|
|
): ContractFunctionObj<TResult> {
|
|
return {
|
|
...superFn.call(this, ...args),
|
|
callAsync: async (...callArgs: any[]): Promise<TResult> => {
|
|
if (!handler) {
|
|
throw new Error(`${superFn.name} handler undefined`);
|
|
}
|
|
return handler.call(this, ...args);
|
|
},
|
|
};
|
|
}
|
|
}
|