protocol/packages/asset-swapper/test/utils/mock_sampler_contract.ts
Jacob Evans 7e8b56eef4
feat: mStable + FQT Rollup (#2662)
* 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>
2020-08-20 08:18:44 +10:00

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);
},
};
}
}