finished exchange swap quote consumer

This commit is contained in:
David Sun 2019-06-21 10:15:06 -07:00
parent 4b09204936
commit ac771e2865
3 changed files with 108 additions and 17 deletions

View File

@ -11,16 +11,15 @@ import {
SmartContractParamsInfo, SmartContractParamsInfo,
SwapQuote, SwapQuote,
SwapQuoteConsumer, SwapQuoteConsumer,
SwapQuoteConsumerError,
SwapQuoteConsumerOpts, SwapQuoteConsumerOpts,
SwapQuoteExecutionOpts, SwapQuoteExecutionOpts,
SwapQuoteGetOutputOpts, SwapQuoteGetOutputOpts,
SwapQuoteInfo,
} from '../types'; } from '../types';
import { assert } from '../utils/assert'; import { assert } from '../utils/assert';
import { SwapQuoteConsumerUtils } from '../utils/swap_quote_consumer_utils';
import { utils } from '../utils/utils'; import { utils } from '../utils/utils';
import { assetDataUtils } from '../utils/asset_data_utils';
export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumer<ExchangeMarketBuySmartContractParams> { export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumer<ExchangeMarketBuySmartContractParams> {
public readonly provider: ZeroExProvider; public readonly provider: ZeroExProvider;
@ -28,17 +27,11 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumer<ExchangeMark
private readonly _contractWrappers: ContractWrappers; private readonly _contractWrappers: ContractWrappers;
constructor( constructor(supportedProvider: SupportedProvider, options: Partial<SwapQuoteConsumerOpts> = {}) {
supportedProvider: SupportedProvider, const { networkId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
options: Partial<SwapQuoteConsumerOpts> = {},
) {
const { networkId } = _.merge(
{},
constants.DEFAULT_SWAP_QUOTER_OPTS,
options,
);
const provider = providerUtils.standardizeOrThrow(supportedProvider);
assert.isNumber('networkId', networkId); assert.isNumber('networkId', networkId);
const provider = providerUtils.standardizeOrThrow(supportedProvider);
this.provider = provider; this.provider = provider;
this.networkId = networkId; this.networkId = networkId;
this._contractWrappers = new ContractWrappers(this.provider, { this._contractWrappers = new ContractWrappers(this.provider, {
@ -47,14 +40,88 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumer<ExchangeMark
} }
public getCalldataOrThrow = (quote: SwapQuote, opts: Partial<SwapQuoteGetOutputOpts>): CalldataInfo => { public getCalldataOrThrow = (quote: SwapQuote, opts: Partial<SwapQuoteGetOutputOpts>): CalldataInfo => {
assert.isValidSwapQuote('quote', quote);
const { params, to, ethAmount, methodAbi } = this.getSmartContractParamsOrThrow(quote, opts);
const abiEncoder = new AbiEncoder.Method(methodAbi);
const args = [
params.orders,
params.makerAssetFillAmount,
params.signatures,
];
const calldataHexString = abiEncoder.encode(args);
return {
calldataHexString,
methodAbi,
to,
ethAmount,
};
} }
public getSmartContractParamsOrThrow = (quote: SwapQuote, opts: Partial<SwapQuoteGetOutputOpts>): SmartContractParamsInfo<ExchangeMarketBuySmartContractParams> => { public getSmartContractParamsOrThrow = (quote: SwapQuote, opts: Partial<SwapQuoteGetOutputOpts>): SmartContractParamsInfo<ExchangeMarketBuySmartContractParams> => {
assert.isValidSwapQuote('quote', quote);
const { orders, makerAssetFillAmount } = quote;
const signatures = _.map(orders, o => o.signature);
const params: ExchangeMarketBuySmartContractParams = {
orders,
signatures,
makerAssetFillAmount,
};
const methodAbi = utils.getMethodAbiFromContractAbi(
this._contractWrappers.exchange.abi,
'marketBuyOrdersNoThrow',
) as MethodAbi;
return {
params,
to: this._contractWrappers.exchange.address,
methodAbi,
};
} }
public executeSwapQuoteOrThrowAsync = async (quote: SwapQuote, opts: Partial<SwapQuoteExecutionOpts>): Promise<string> => { public executeSwapQuoteOrThrowAsync = async (quote: SwapQuote, opts: Partial<SwapQuoteExecutionOpts>): Promise<string> => {
assert.isValidSwapQuote('quote', quote);
}; const { takerAddress, gasLimit, gasPrice } = opts;
if (takerAddress !== undefined) {
assert.isETHAddressHex('takerAddress', takerAddress);
}
if (gasLimit !== undefined) {
assert.isNumber('gasLimit', gasLimit);
}
if (gasPrice !== undefined) {
assert.isBigNumber('gasPrice', gasPrice);
}
const { orders, makerAssetFillAmount } = quote;
const finalTakerAddress = await SwapQuoteConsumerUtils.getTakerAddressOrThrowAsync(this.provider, opts);
try {
const txHash = await this._contractWrappers.exchange.marketBuyOrdersNoThrowAsync(
orders,
makerAssetFillAmount,
finalTakerAddress,
{
gasLimit,
gasPrice,
shouldValidate: true,
},
);
return txHash;
} catch (err) {
if (_.includes(err.message, ContractWrappersError.SignatureRequestDenied)) {
throw new Error(SwapQuoteConsumerError.SignatureRequestDenied);
} else if (_.includes(err.message, ForwarderWrapperError.CompleteFillFailed)) {
throw new Error(SwapQuoteConsumerError.TransactionValueTooLow);
} else {
throw err;
}
}
}
} }

View File

@ -62,7 +62,7 @@ export interface CalldataInfo {
export interface SmartContractParamsInfo<T> { export interface SmartContractParamsInfo<T> {
params: T; params: T;
to: string; to: string;
ethAmount: BigNumber; ethAmount?: BigNumber;
methodAbi: MethodAbi; methodAbi: MethodAbi;
} }

View File

@ -0,0 +1,24 @@
import { SupportedProvider, Web3Wrapper, ZeroExProvider } from '@0x/web3-wrapper';
import * as _ from 'lodash';
import {
SwapQuoteConsumerError,
SwapQuoteExecutionOpts,
} from '../types';
export const SwapQuoteConsumerUtils = {
async getTakerAddressOrThrowAsync(provider: SupportedProvider, opts: Partial<SwapQuoteExecutionOpts>): Promise<string> {
if (opts.takerAddress !== undefined) {
return opts.takerAddress;
} else {
const web3Wrapper = new Web3Wrapper(provider);
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
const firstAvailableAddress = _.head(availableAddresses);
if (firstAvailableAddress !== undefined) {
return firstAvailableAddress;
} else {
throw new Error(SwapQuoteConsumerError.NoAddressAvailable);
}
}
},
};