diff --git a/contracts/erc20-bridge-sampler/contracts/src/DummyLiquidityProvider.sol b/contracts/erc20-bridge-sampler/contracts/src/DummyLiquidityProvider.sol new file mode 100644 index 0000000000..fb7d44b9f4 --- /dev/null +++ b/contracts/erc20-bridge-sampler/contracts/src/DummyLiquidityProvider.sol @@ -0,0 +1,38 @@ +pragma solidity ^0.5.9; +pragma experimental ABIEncoderV2; + + +contract DummyLiquidityProvider +{ + /// @dev Quotes the amount of `makerToken` that would be obtained by + /// selling `sellAmount` of `takerToken`. + /// @param sellAmount Amount of `takerToken` to sell. + /// @return makerTokenAmount Amount of `makerToken` that would be obtained. + function getSellQuote( + address, /* takerToken */ + address, /* makerToken */ + uint256 sellAmount + ) + external + view + returns (uint256 makerTokenAmount) + { + makerTokenAmount = sellAmount - 1; + } + + /// @dev Quotes the amount of `takerToken` that would need to be sold in + /// order to obtain `buyAmount` of `makerToken`. + /// @param buyAmount Amount of `makerToken` to buy. + /// @return takerTokenAmount Amount of `takerToken` that would need to be sold. + function getBuyQuote( + address, /* takerToken */ + address, /* makerToken */ + uint256 buyAmount + ) + external + view + returns (uint256 takerTokenAmount) + { + takerTokenAmount = buyAmount + 1; + } +} \ No newline at end of file diff --git a/contracts/erc20-bridge-sampler/contracts/src/DummyLiquidityProviderRegistry.sol b/contracts/erc20-bridge-sampler/contracts/src/DummyLiquidityProviderRegistry.sol new file mode 100644 index 0000000000..e7e1244425 --- /dev/null +++ b/contracts/erc20-bridge-sampler/contracts/src/DummyLiquidityProviderRegistry.sol @@ -0,0 +1,44 @@ +pragma solidity ^0.5.9; +pragma experimental ABIEncoderV2; + + +contract DummyLiquidityProviderRegistry +{ + address private constant NULL_ADDRESS = address(0x0); + + mapping (address => mapping (address => address)) internal _gAddressBook; + + /// @dev Sets address of pool for a market given market (xAsset, yAsset). + /// @param xToken First asset managed by pool. + /// @param yToken Second asset managed by pool. + /// @param poolAddress Address of pool. + function setLiquidityProviderForMarket( + address xToken, + address yToken, + address poolAddress + ) + external + { + _gAddressBook[xToken][yToken] = poolAddress; + _gAddressBook[yToken][xToken] = poolAddress; + } + + /// @dev Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist. + /// @param xToken First asset managed by pool. + /// @param yToken Second asset managed by pool. + /// @return Address of pool. + function getLiquidityProviderForMarket( + address xToken, + address yToken + ) + external + view + returns (address poolAddress) + { + poolAddress = _gAddressBook[xToken][yToken]; + require( + poolAddress != NULL_ADDRESS, + "Registry/MARKET_PAIR_NOT_SET" + ); + } +} \ No newline at end of file diff --git a/contracts/erc20-bridge-sampler/package.json b/contracts/erc20-bridge-sampler/package.json index 35b2af4297..6bbff417ff 100644 --- a/contracts/erc20-bridge-sampler/package.json +++ b/contracts/erc20-bridge-sampler/package.json @@ -36,9 +36,9 @@ "compile:truffle": "truffle compile" }, "config": { - "publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry", + "publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler,ILiquidityProvider,ILiquidityProviderRegistry,DummyLiquidityProviderRegistry,DummyLiquidityProvider", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./test/generated-artifacts/@(ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json" + "abis": "./test/generated-artifacts/@(DummyLiquidityProvider|DummyLiquidityProviderRegistry|ERC20BridgeSampler|ICurve|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|ILiquidityProvider|ILiquidityProviderRegistry|IUniswapExchangeQuotes|TestERC20BridgeSampler).json" }, "repository": { "type": "git", diff --git a/contracts/erc20-bridge-sampler/src/artifacts.ts b/contracts/erc20-bridge-sampler/src/artifacts.ts index 1f15319fd0..837f883201 100644 --- a/contracts/erc20-bridge-sampler/src/artifacts.ts +++ b/contracts/erc20-bridge-sampler/src/artifacts.ts @@ -5,6 +5,8 @@ */ import { ContractArtifact } from 'ethereum-types'; +import * as DummyLiquidityProvider from '../generated-artifacts/DummyLiquidityProvider.json'; +import * as DummyLiquidityProviderRegistry from '../generated-artifacts/DummyLiquidityProviderRegistry.json'; import * as ERC20BridgeSampler from '../generated-artifacts/ERC20BridgeSampler.json'; import * as IERC20BridgeSampler from '../generated-artifacts/IERC20BridgeSampler.json'; import * as ILiquidityProvider from '../generated-artifacts/ILiquidityProvider.json'; @@ -14,4 +16,6 @@ export const artifacts = { IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact, ILiquidityProvider: ILiquidityProvider as ContractArtifact, ILiquidityProviderRegistry: ILiquidityProviderRegistry as ContractArtifact, + DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact, + DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact, }; diff --git a/contracts/erc20-bridge-sampler/src/wrappers.ts b/contracts/erc20-bridge-sampler/src/wrappers.ts index 968f08623c..bb1fd88c01 100644 --- a/contracts/erc20-bridge-sampler/src/wrappers.ts +++ b/contracts/erc20-bridge-sampler/src/wrappers.ts @@ -3,6 +3,8 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ +export * from '../generated-wrappers/dummy_liquidity_provider'; +export * from '../generated-wrappers/dummy_liquidity_provider_registry'; export * from '../generated-wrappers/erc20_bridge_sampler'; export * from '../generated-wrappers/i_erc20_bridge_sampler'; export * from '../generated-wrappers/i_liquidity_provider'; diff --git a/contracts/erc20-bridge-sampler/test/artifacts.ts b/contracts/erc20-bridge-sampler/test/artifacts.ts index 2ed14d12a6..153229adb0 100644 --- a/contracts/erc20-bridge-sampler/test/artifacts.ts +++ b/contracts/erc20-bridge-sampler/test/artifacts.ts @@ -5,6 +5,8 @@ */ import { ContractArtifact } from 'ethereum-types'; +import * as DummyLiquidityProvider from '../test/generated-artifacts/DummyLiquidityProvider.json'; +import * as DummyLiquidityProviderRegistry from '../test/generated-artifacts/DummyLiquidityProviderRegistry.json'; import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json'; import * as ICurve from '../test/generated-artifacts/ICurve.json'; import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json'; @@ -16,6 +18,8 @@ import * as ILiquidityProviderRegistry from '../test/generated-artifacts/ILiquid import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json'; import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json'; export const artifacts = { + DummyLiquidityProvider: DummyLiquidityProvider as ContractArtifact, + DummyLiquidityProviderRegistry: DummyLiquidityProviderRegistry as ContractArtifact, ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact, ICurve: ICurve as ContractArtifact, IDevUtils: IDevUtils as ContractArtifact, diff --git a/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts b/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts index d51d7285d9..a1d5bba154 100644 --- a/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts +++ b/contracts/erc20-bridge-sampler/test/erc20-bridge-sampler.ts @@ -11,7 +11,11 @@ import { BigNumber, hexUtils } from '@0x/utils'; import * as _ from 'lodash'; import { artifacts } from './artifacts'; -import { TestERC20BridgeSamplerContract } from './wrappers'; +import { + DummyLiquidityProviderContract, + DummyLiquidityProviderRegistryContract, + TestERC20BridgeSamplerContract, +} from './wrappers'; blockchainTests('erc20-bridge-sampler', env => { let testContract: TestERC20BridgeSamplerContract; @@ -716,6 +720,90 @@ blockchainTests('erc20-bridge-sampler', env => { }); }); + describe('getLiquidityProviderFromRegistry', () => { + const xAsset = randomAddress(); + const yAsset = randomAddress(); + const sampleAmounts = getSampleAmounts(yAsset); + let liquidityProvider: DummyLiquidityProviderContract; + let registryContract: DummyLiquidityProviderRegistryContract; + + before(async () => { + liquidityProvider = await DummyLiquidityProviderContract.deployFrom0xArtifactAsync( + artifacts.DummyLiquidityProvider, + env.provider, + env.txDefaults, + {}, + ); + + registryContract = await DummyLiquidityProviderRegistryContract.deployFrom0xArtifactAsync( + artifacts.DummyLiquidityProviderRegistry, + env.provider, + env.txDefaults, + {}, + ); + await registryContract + .setLiquidityProviderForMarket(xAsset, yAsset, liquidityProvider.address) + .awaitTransactionSuccessAsync(); + }); + + it('should be able to get the liquidity provider', async () => { + const xyLiquidityProvider = await testContract + .getLiquidityProviderFromRegistry(registryContract.address, xAsset, yAsset) + .callAsync(); + const yxLiquidityProvider = await testContract + .getLiquidityProviderFromRegistry(registryContract.address, yAsset, xAsset) + .callAsync(); + const unknownLiquidityProvider = await testContract + .getLiquidityProviderFromRegistry(registryContract.address, yAsset, randomAddress()) + .callAsync(); + + expect(xyLiquidityProvider).to.eq(liquidityProvider.address); + expect(yxLiquidityProvider).to.eq(liquidityProvider.address); + expect(unknownLiquidityProvider).to.eq(constants.NULL_ADDRESS); + }); + + it('should be able to query sells from the liquidity provider', async () => { + const result = await testContract + .sampleSellsFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts) + .callAsync(); + result.forEach((value, idx) => { + expect(value).is.bignumber.eql(sampleAmounts[idx].minus(1)); + }); + }); + + it('should be able to query buys from the liquidity provider', async () => { + const result = await testContract + .sampleBuysFromLiquidityProviderRegistry(registryContract.address, yAsset, xAsset, sampleAmounts) + .callAsync(); + result.forEach((value, idx) => { + expect(value).is.bignumber.eql(sampleAmounts[idx].plus(1)); + }); + }); + + it('should just return zeros if the liquidity provider cannot be found', async () => { + const result = await testContract + .sampleBuysFromLiquidityProviderRegistry( + registryContract.address, + yAsset, + randomAddress(), + sampleAmounts, + ) + .callAsync(); + result.forEach(value => { + expect(value).is.bignumber.eql(constants.ZERO_AMOUNT); + }); + }); + + it('should just return zeros if the registry does not exist', async () => { + const result = await testContract + .sampleBuysFromLiquidityProviderRegistry(randomAddress(), yAsset, xAsset, sampleAmounts) + .callAsync(); + result.forEach(value => { + expect(value).is.bignumber.eql(constants.ZERO_AMOUNT); + }); + }); + }); + describe('batchCall()', () => { it('can call one function', async () => { const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN); diff --git a/contracts/erc20-bridge-sampler/test/wrappers.ts b/contracts/erc20-bridge-sampler/test/wrappers.ts index 4465c09dfd..21f8312556 100644 --- a/contracts/erc20-bridge-sampler/test/wrappers.ts +++ b/contracts/erc20-bridge-sampler/test/wrappers.ts @@ -3,6 +3,8 @@ * Warning: This file is auto-generated by contracts-gen. Don't edit manually. * ----------------------------------------------------------------------------- */ +export * from '../test/generated-wrappers/dummy_liquidity_provider'; +export * from '../test/generated-wrappers/dummy_liquidity_provider_registry'; export * from '../test/generated-wrappers/erc20_bridge_sampler'; export * from '../test/generated-wrappers/i_curve'; export * from '../test/generated-wrappers/i_dev_utils'; diff --git a/contracts/erc20-bridge-sampler/tsconfig.json b/contracts/erc20-bridge-sampler/tsconfig.json index c8e6f55115..f2e3c070fe 100644 --- a/contracts/erc20-bridge-sampler/tsconfig.json +++ b/contracts/erc20-bridge-sampler/tsconfig.json @@ -3,10 +3,14 @@ "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "files": [ + "generated-artifacts/DummyLiquidityProvider.json", + "generated-artifacts/DummyLiquidityProviderRegistry.json", "generated-artifacts/ERC20BridgeSampler.json", "generated-artifacts/IERC20BridgeSampler.json", "generated-artifacts/ILiquidityProvider.json", "generated-artifacts/ILiquidityProviderRegistry.json", + "test/generated-artifacts/DummyLiquidityProvider.json", + "test/generated-artifacts/DummyLiquidityProviderRegistry.json", "test/generated-artifacts/ERC20BridgeSampler.json", "test/generated-artifacts/ICurve.json", "test/generated-artifacts/IDevUtils.json", diff --git a/packages/asset-swapper/src/swap_quoter.ts b/packages/asset-swapper/src/swap_quoter.ts index 86090b6205..6c4ad4cb88 100644 --- a/packages/asset-swapper/src/swap_quoter.ts +++ b/packages/asset-swapper/src/swap_quoter.ts @@ -21,8 +21,9 @@ import { } from './types'; import { assert } from './utils/assert'; import { calculateLiquidity } from './utils/calculate_liquidity'; -import { DexOrderSampler, MarketOperationUtils } from './utils/market_operation_utils'; +import { MarketOperationUtils } from './utils/market_operation_utils'; import { dummyOrderUtils } from './utils/market_operation_utils/dummy_order_utils'; +import { DexOrderSampler } from './utils/market_operation_utils/sampler'; import { orderPrunerUtils } from './utils/order_prune_utils'; import { OrderStateUtils } from './utils/order_state_utils'; import { ProtocolFeeUtils } from './utils/protocol_fee_utils'; @@ -144,11 +145,13 @@ export class SwapQuoter { * @return An instance of SwapQuoter */ constructor(supportedProvider: SupportedProvider, orderbook: Orderbook, options: Partial = {}) { - const { chainId, expiryBufferMs, permittedOrderFeeTypes, samplerGasLimit } = _.merge( - {}, - constants.DEFAULT_SWAP_QUOTER_OPTS, - options, - ); + const { + chainId, + expiryBufferMs, + permittedOrderFeeTypes, + samplerGasLimit, + liquidityProviderRegistryAddress, + } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); const provider = providerUtils.standardizeOrThrow(supportedProvider); assert.isValidOrderbook('orderbook', orderbook); assert.isNumber('chainId', chainId); @@ -167,10 +170,15 @@ export class SwapQuoter { gas: samplerGasLimit, }), ); - this._marketOperationUtils = new MarketOperationUtils(sampler, this._contractAddresses, { - chainId, - exchangeAddress: this._contractAddresses.exchange, - }); + this._marketOperationUtils = new MarketOperationUtils( + sampler, + this._contractAddresses, + { + chainId, + exchangeAddress: this._contractAddresses.exchange, + }, + liquidityProviderRegistryAddress, + ); this._swapQuoteCalculator = new SwapQuoteCalculator(this._protocolFeeUtils, this._marketOperationUtils); } diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index f5476b1fbd..ab466914ab 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -212,6 +212,7 @@ export interface SwapQuoterOpts extends OrderPrunerOpts { expiryBufferMs: number; contractAddresses?: ContractAddresses; samplerGasLimit?: number; + liquidityProviderRegistryAddress?: string; } /** diff --git a/packages/asset-swapper/src/utils/market_operation_utils/create_order.ts b/packages/asset-swapper/src/utils/market_operation_utils/create_order.ts index f47f9c8cc8..82a5f9b054 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/create_order.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/create_order.ts @@ -1,3 +1,4 @@ +import { assert } from '@0x/assert'; import { ContractAddresses } from '@0x/contract-addresses'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; @@ -48,6 +49,7 @@ export class CreateOrderUtils { outputToken: string, path: CollapsedFill[], bridgeSlippage: number, + liquidityProviderAddress?: string, ): OptimizedMarketOrder[] { const orders: OptimizedMarketOrder[] = []; for (const fill of path) { @@ -58,7 +60,7 @@ export class CreateOrderUtils { createBridgeOrder( orderDomain, fill, - this._getBridgeAddressFromSource(fill.source), + this._getBridgeAddressFromSource(fill.source, liquidityProviderAddress), outputToken, inputToken, bridgeSlippage, @@ -76,6 +78,7 @@ export class CreateOrderUtils { outputToken: string, path: CollapsedFill[], bridgeSlippage: number, + liquidityProviderAddress?: string, ): OptimizedMarketOrder[] { const orders: OptimizedMarketOrder[] = []; for (const fill of path) { @@ -86,7 +89,7 @@ export class CreateOrderUtils { createBridgeOrder( orderDomain, fill, - this._getBridgeAddressFromSource(fill.source), + this._getBridgeAddressFromSource(fill.source, liquidityProviderAddress), inputToken, outputToken, bridgeSlippage, @@ -98,7 +101,7 @@ export class CreateOrderUtils { return orders; } - private _getBridgeAddressFromSource(source: ERC20BridgeSource): string { + private _getBridgeAddressFromSource(source: ERC20BridgeSource, liquidityProviderAddress?: string): string { switch (source) { case ERC20BridgeSource.Eth2Dai: return this._contractAddress.eth2DaiBridge; @@ -111,6 +114,14 @@ export class CreateOrderUtils { case ERC20BridgeSource.CurveUsdcDaiUsdtTusd: case ERC20BridgeSource.CurveUsdcDaiUsdtBusd: return this._contractAddress.curveBridge; + case ERC20BridgeSource.LiquidityProvider: + if (liquidityProviderAddress === undefined) { + throw new Error( + 'Cannot create a LiquidityProvider order without a LiquidityProvider pool address.', + ); + } + assert.isETHAddressHex('liquidityProviderAddress', liquidityProviderAddress); + return liquidityProviderAddress; default: break; } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/index.ts b/packages/asset-swapper/src/utils/market_operation_utils/index.ts index 8b4ef86f89..93d0ad68bf 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -1,7 +1,7 @@ import { ContractAddresses } from '@0x/contract-addresses'; import { assetDataUtils, ERC20AssetData, orderCalculationUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, NULL_ADDRESS } from '@0x/utils'; import { constants } from '../../constants'; import { MarketOperation, SignedOrderWithFillableAmounts } from '../../types'; @@ -46,6 +46,7 @@ export class MarketOperationUtils { private readonly _sampler: DexOrderSampler, contractAddresses: ContractAddresses, private readonly _orderDomain: OrderDomain, + private readonly _liquidityProviderRegistry: string = NULL_ADDRESS, ) { this._createOrderUtils = new CreateOrderUtils(contractAddresses); this._wethAddress = contractAddresses.etherToken; @@ -72,23 +73,40 @@ export class MarketOperationUtils { ...opts, }; const [makerToken, takerToken] = getOrderTokens(nativeOrders[0]); - const [fillableAmounts, ethToMakerAssetRate, dexQuotes] = await this._sampler.executeAsync( + const [ + fillableAmounts, + liquidityProviderAddress, + ethToMakerAssetRate, + dexQuotes, + ] = await this._sampler.executeAsync( DexOrderSampler.ops.getOrderFillableTakerAmounts(nativeOrders), + DexOrderSampler.ops.getLiquidityProviderFromRegistry( + this._liquidityProviderRegistry, + takerToken, + makerToken, + ), makerToken.toLowerCase() === this._wethAddress.toLowerCase() ? DexOrderSampler.ops.constant(new BigNumber(1)) : DexOrderSampler.ops.getMedianSellRate( - difference(FEE_QUOTE_SOURCES, _opts.excludedSources), + difference(FEE_QUOTE_SOURCES, _opts.excludedSources).concat( + this._liquidityProviderSourceIfAvailable(_opts.excludedSources), + ), makerToken, this._wethAddress, ONE_ETHER, + this._liquidityProviderRegistry, ), DexOrderSampler.ops.getSellQuotes( - difference(SELL_SOURCES, _opts.excludedSources), + difference(SELL_SOURCES, _opts.excludedSources).concat( + this._liquidityProviderSourceIfAvailable(_opts.excludedSources), + ), makerToken, takerToken, getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase), + this._liquidityProviderRegistry, ), ); + const nativeOrdersWithFillableAmounts = createSignedOrdersWithFillableAmounts( nativeOrders, fillableAmounts, @@ -130,6 +148,7 @@ export class MarketOperationUtils { makerToken, collapsePath(optimalPath, false), _opts.bridgeSlippage, + liquidityProviderAddress, ); } @@ -154,21 +173,37 @@ export class MarketOperationUtils { ...opts, }; const [makerToken, takerToken] = getOrderTokens(nativeOrders[0]); - const [fillableAmounts, ethToTakerAssetRate, dexQuotes] = await this._sampler.executeAsync( + const [ + fillableAmounts, + liquidityProviderAddress, + ethToTakerAssetRate, + dexQuotes, + ] = await this._sampler.executeAsync( DexOrderSampler.ops.getOrderFillableMakerAmounts(nativeOrders), + DexOrderSampler.ops.getLiquidityProviderFromRegistry( + this._liquidityProviderRegistry, + takerToken, + makerToken, + ), takerToken.toLowerCase() === this._wethAddress.toLowerCase() ? DexOrderSampler.ops.constant(new BigNumber(1)) : DexOrderSampler.ops.getMedianSellRate( - difference(FEE_QUOTE_SOURCES, _opts.excludedSources), + difference(FEE_QUOTE_SOURCES, _opts.excludedSources).concat( + this._liquidityProviderSourceIfAvailable(_opts.excludedSources), + ), takerToken, this._wethAddress, ONE_ETHER, + this._liquidityProviderRegistry, ), DexOrderSampler.ops.getBuyQuotes( - difference(BUY_SOURCES, _opts.excludedSources), + difference(BUY_SOURCES, _opts.excludedSources).concat( + this._liquidityProviderSourceIfAvailable(_opts.excludedSources), + ), makerToken, takerToken, getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase), + this._liquidityProviderRegistry, ), ); const signedOrderWithFillableAmounts = this._createBuyOrdersPathFromSamplerResultIfExists( @@ -178,6 +213,7 @@ export class MarketOperationUtils { dexQuotes, ethToTakerAssetRate, _opts, + liquidityProviderAddress, ); if (!signedOrderWithFillableAmounts) { throw new Error(AggregationError.NoOptimalPath); @@ -188,6 +224,9 @@ export class MarketOperationUtils { /** * gets the orders required for a batch of market buy operations by (potentially) merging native orders with * generated bridge orders. + * + * NOTE: Currently `getBatchMarketBuyOrdersAsync()` does not support external liquidity providers. + * * @param batchNativeOrders Batch of Native orders. * @param makerAmounts Array amount of maker asset to buy for each batch. * @param opts Options object. @@ -240,6 +279,13 @@ export class MarketOperationUtils { ); } + private _liquidityProviderSourceIfAvailable(excludedSources: ERC20BridgeSource[]): ERC20BridgeSource[] { + return this._liquidityProviderRegistry !== NULL_ADDRESS && + !excludedSources.includes(ERC20BridgeSource.LiquidityProvider) + ? [ERC20BridgeSource.LiquidityProvider] + : []; + } + private _createBuyOrdersPathFromSamplerResultIfExists( nativeOrders: SignedOrder[], makerAmount: BigNumber, @@ -247,6 +293,7 @@ export class MarketOperationUtils { dexQuotes: DexSample[][], ethToTakerAssetRate: BigNumber, opts: GetMarketOrdersOpts, + liquidityProviderAddress?: string, ): OptimizedMarketOrder[] | undefined { const nativeOrdersWithFillableAmounts = createSignedOrdersWithFillableAmounts( nativeOrders, @@ -289,6 +336,7 @@ export class MarketOperationUtils { outputToken, collapsePath(optimalPath, true), opts.bridgeSlippage, + liquidityProviderAddress, ); } } @@ -470,6 +518,9 @@ function sourceToFillFlags(source: ERC20BridgeSource): number { if (source === ERC20BridgeSource.Uniswap) { return FillFlags.SourceUniswap; } + if (source === ERC20BridgeSource.LiquidityProvider) { + return FillFlags.SourceLiquidityPool; + } return FillFlags.SourceNative; } diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts index aed5405006..55a347600d 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler.ts @@ -1,283 +1,8 @@ import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers'; -import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { constants } from '../../constants'; - -import { DexSample, ERC20BridgeSource } from './types'; - -/** - * A composable operation the be run in `DexOrderSampler.executeAsync()`. - */ -export interface BatchedOperation { - encodeCall(contract: IERC20BridgeSamplerContract): string; - handleCallResultsAsync(contract: IERC20BridgeSamplerContract, callResults: string): Promise; -} - -/** - * Composable operations that can be batched in a single transaction, - * for use with `DexOrderSampler.executeAsync()`. - */ -const samplerOperations = { - getOrderFillableTakerAmounts(orders: SignedOrder[]): BatchedOperation { - return { - encodeCall: contract => { - return contract - .getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature)) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', callResults); - }, - }; - }, - getOrderFillableMakerAmounts(orders: SignedOrder[]): BatchedOperation { - return { - encodeCall: contract => { - return contract - .getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature)) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('getOrderFillableMakerAssetAmounts', callResults); - }, - }; - }, - getKyberSellQuotes( - makerToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ): BatchedOperation { - return { - encodeCall: contract => { - return contract - .sampleSellsFromKyberNetwork(takerToken, makerToken, takerFillAmounts) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromKyberNetwork', callResults); - }, - }; - }, - getUniswapSellQuotes( - makerToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ): BatchedOperation { - return { - encodeCall: contract => { - return contract - .sampleSellsFromUniswap(takerToken, makerToken, takerFillAmounts) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromUniswap', callResults); - }, - }; - }, - getEth2DaiSellQuotes( - makerToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ): BatchedOperation { - return { - encodeCall: contract => { - return contract - .sampleSellsFromEth2Dai(takerToken, makerToken, takerFillAmounts) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromEth2Dai', callResults); - }, - }; - }, - getCurveSellQuotes( - curveAddress: string, - fromTokenIdx: number, - toTokenIdx: number, - takerFillAmounts: BigNumber[], - ): BatchedOperation { - return { - encodeCall: contract => { - return contract - .sampleSellsFromCurve( - curveAddress, - new BigNumber(fromTokenIdx), - new BigNumber(toTokenIdx), - takerFillAmounts, - ) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleSellsFromCurve', callResults); - }, - }; - }, - getUniswapBuyQuotes( - makerToken: string, - takerToken: string, - makerFillAmounts: BigNumber[], - ): BatchedOperation { - return { - encodeCall: contract => { - return contract - .sampleBuysFromUniswap(takerToken, makerToken, makerFillAmounts) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromUniswap', callResults); - }, - }; - }, - getEth2DaiBuyQuotes( - makerToken: string, - takerToken: string, - makerFillAmounts: BigNumber[], - ): BatchedOperation { - return { - encodeCall: contract => { - return contract - .sampleBuysFromEth2Dai(takerToken, makerToken, makerFillAmounts) - .getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - return contract.getABIDecodedReturnData('sampleBuysFromEth2Dai', callResults); - }, - }; - }, - getMedianSellRate( - sources: ERC20BridgeSource[], - makerToken: string, - takerToken: string, - takerFillAmount: BigNumber, - ): BatchedOperation { - const getSellQuotes = samplerOperations.getSellQuotes(sources, makerToken, takerToken, [takerFillAmount]); - return { - encodeCall: contract => { - const subCalls = [getSellQuotes.encodeCall(contract)]; - return contract.batchCall(subCalls).getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); - const samples = await getSellQuotes.handleCallResultsAsync(contract, rawSubCallResults[0]); - if (samples.length === 0) { - return new BigNumber(0); - } - const flatSortedSamples = samples - .reduce((acc, v) => acc.concat(...v)) - .sort((a, b) => a.output.comparedTo(b.output)); - if (flatSortedSamples.length === 0) { - return new BigNumber(0); - } - const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)]; - return medianSample.output.div(medianSample.input); - }, - }; - }, - constant(result: T): BatchedOperation { - return { - encodeCall: contract => { - return '0x'; - }, - handleCallResultsAsync: async (contract, callResults) => { - return result; - }, - }; - }, - getSellQuotes( - sources: ERC20BridgeSource[], - makerToken: string, - takerToken: string, - takerFillAmounts: BigNumber[], - ): BatchedOperation { - const subOps = sources - .map(source => { - let batchedOperation; - if (source === ERC20BridgeSource.Eth2Dai) { - batchedOperation = samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts); - } else if (source === ERC20BridgeSource.Uniswap) { - batchedOperation = samplerOperations.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts); - } else if (source === ERC20BridgeSource.Kyber) { - batchedOperation = samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts); - } else if (Object.keys(constants.DEFAULT_CURVE_OPTS).includes(source)) { - const { curveAddress, tokens } = constants.DEFAULT_CURVE_OPTS[source]; - const fromTokenIdx = tokens.indexOf(takerToken); - const toTokenIdx = tokens.indexOf(makerToken); - if (fromTokenIdx !== -1 && toTokenIdx !== -1) { - batchedOperation = samplerOperations.getCurveSellQuotes( - curveAddress, - fromTokenIdx, - toTokenIdx, - takerFillAmounts, - ); - } - } else { - throw new Error(`Unsupported sell sample source: ${source}`); - } - return { batchedOperation, source }; - }) - .filter(op => op.batchedOperation) as Array<{ - batchedOperation: BatchedOperation; - source: ERC20BridgeSource; - }>; - return { - encodeCall: contract => { - const subCalls = subOps.map(op => op.batchedOperation.encodeCall(contract)); - return contract.batchCall(subCalls).getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); - const samples = await Promise.all( - subOps.map(async (op, i) => - op.batchedOperation.handleCallResultsAsync(contract, rawSubCallResults[i]), - ), - ); - return subOps.map((op, i) => { - return samples[i].map((output, j) => ({ - source: op.source, - output, - input: takerFillAmounts[j], - })); - }); - }, - }; - }, - getBuyQuotes( - sources: ERC20BridgeSource[], - makerToken: string, - takerToken: string, - makerFillAmounts: BigNumber[], - ): BatchedOperation { - const subOps = sources.map(source => { - if (source === ERC20BridgeSource.Eth2Dai) { - return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts); - } else if (source === ERC20BridgeSource.Uniswap) { - return samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts); - } else { - throw new Error(`Unsupported buy sample source: ${source}`); - } - }); - return { - encodeCall: contract => { - const subCalls = subOps.map(op => op.encodeCall(contract)); - return contract.batchCall(subCalls).getABIEncodedTransactionData(); - }, - handleCallResultsAsync: async (contract, callResults) => { - const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); - const samples = await Promise.all( - subOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])), - ); - return sources.map((source, i) => { - return samples[i].map((output, j) => ({ - source, - output, - input: makerFillAmounts[j], - })); - }); - }, - }; - }, -}; +import { samplerOperations } from './sampler_operations'; +import { BatchedOperation } from './types'; /** * Generate sample amounts up to `maxFillAmount`. diff --git a/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts new file mode 100644 index 0000000000..f5fbf71482 --- /dev/null +++ b/packages/asset-swapper/src/utils/market_operation_utils/sampler_operations.ts @@ -0,0 +1,368 @@ +import { BigNumber, ERC20BridgeSource, SignedOrder } from '../..'; +import { constants } from '../../constants'; + +import { BatchedOperation, DexSample } from './types'; + +/** + * Composable operations that can be batched in a single transaction, + * for use with `DexOrderSampler.executeAsync()`. + */ +export const samplerOperations = { + getOrderFillableTakerAmounts(orders: SignedOrder[]): BatchedOperation { + return { + encodeCall: contract => { + return contract + .getOrderFillableTakerAssetAmounts(orders, orders.map(o => o.signature)) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('getOrderFillableTakerAssetAmounts', callResults); + }, + }; + }, + getOrderFillableMakerAmounts(orders: SignedOrder[]): BatchedOperation { + return { + encodeCall: contract => { + return contract + .getOrderFillableMakerAssetAmounts(orders, orders.map(o => o.signature)) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('getOrderFillableMakerAssetAmounts', callResults); + }, + }; + }, + getKyberSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromKyberNetwork(takerToken, makerToken, takerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromKyberNetwork', callResults); + }, + }; + }, + getUniswapSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromUniswap(takerToken, makerToken, takerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromUniswap', callResults); + }, + }; + }, + getLiquidityProviderSellQuotes( + liquidityProviderRegistryAddress: string, + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromLiquidityProviderRegistry( + liquidityProviderRegistryAddress, + takerToken, + makerToken, + takerFillAmounts, + ) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData( + 'sampleSellsFromLiquidityProviderRegistry', + callResults, + ); + }, + }; + }, + getLiquidityProviderBuyQuotes( + liquidityProviderRegistryAddress: string, + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleBuysFromLiquidityProviderRegistry( + liquidityProviderRegistryAddress, + takerToken, + makerToken, + makerFillAmounts, + ) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData( + 'sampleBuysFromLiquidityProviderRegistry', + callResults, + ); + }, + }; + }, + getEth2DaiSellQuotes( + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromEth2Dai(takerToken, makerToken, takerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromEth2Dai', callResults); + }, + }; + }, + getCurveSellQuotes( + curveAddress: string, + fromTokenIdx: number, + toTokenIdx: number, + takerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleSellsFromCurve( + curveAddress, + new BigNumber(fromTokenIdx), + new BigNumber(toTokenIdx), + takerFillAmounts, + ) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleSellsFromCurve', callResults); + }, + }; + }, + getUniswapBuyQuotes( + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleBuysFromUniswap(takerToken, makerToken, makerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleBuysFromUniswap', callResults); + }, + }; + }, + getEth2DaiBuyQuotes( + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .sampleBuysFromEth2Dai(takerToken, makerToken, makerFillAmounts) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('sampleBuysFromEth2Dai', callResults); + }, + }; + }, + getMedianSellRate( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + takerFillAmount: BigNumber, + liquidityProviderRegistryAddress?: string | undefined, + ): BatchedOperation { + const getSellQuotes = samplerOperations.getSellQuotes( + sources, + makerToken, + takerToken, + [takerFillAmount], + liquidityProviderRegistryAddress, + ); + return { + encodeCall: contract => { + const subCalls = [getSellQuotes.encodeCall(contract)]; + return contract.batchCall(subCalls).getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); + const samples = await getSellQuotes.handleCallResultsAsync(contract, rawSubCallResults[0]); + if (samples.length === 0) { + return new BigNumber(0); + } + const flatSortedSamples = samples + .reduce((acc, v) => acc.concat(...v)) + .sort((a, b) => a.output.comparedTo(b.output)); + if (flatSortedSamples.length === 0) { + return new BigNumber(0); + } + const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)]; + return medianSample.output.div(medianSample.input); + }, + }; + }, + constant(result: T): BatchedOperation { + return { + encodeCall: contract => { + return '0x'; + }, + handleCallResultsAsync: async (contract, callResults) => { + return result; + }, + }; + }, + getLiquidityProviderFromRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + ): BatchedOperation { + return { + encodeCall: contract => { + return contract + .getLiquidityProviderFromRegistry(registryAddress, takerToken, makerToken) + .getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + return contract.getABIDecodedReturnData('getLiquidityProviderFromRegistry', callResults); + }, + }; + }, + getSellQuotes( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + takerFillAmounts: BigNumber[], + liquidityProviderRegistryAddress?: string | undefined, + ): BatchedOperation { + const subOps = sources + .map(source => { + let batchedOperation; + if (source === ERC20BridgeSource.Eth2Dai) { + batchedOperation = samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts); + } else if (source === ERC20BridgeSource.Uniswap) { + batchedOperation = samplerOperations.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts); + } else if (source === ERC20BridgeSource.Kyber) { + batchedOperation = samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts); + } else if (Object.keys(constants.DEFAULT_CURVE_OPTS).includes(source)) { + const { curveAddress, tokens } = constants.DEFAULT_CURVE_OPTS[source]; + const fromTokenIdx = tokens.indexOf(takerToken); + const toTokenIdx = tokens.indexOf(makerToken); + if (fromTokenIdx !== -1 && toTokenIdx !== -1) { + batchedOperation = samplerOperations.getCurveSellQuotes( + curveAddress, + fromTokenIdx, + toTokenIdx, + takerFillAmounts, + ); + } + } else if (source === ERC20BridgeSource.LiquidityProvider) { + if (liquidityProviderRegistryAddress === undefined) { + throw new Error( + 'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.', + ); + } + batchedOperation = samplerOperations.getLiquidityProviderSellQuotes( + liquidityProviderRegistryAddress, + makerToken, + takerToken, + takerFillAmounts, + ); + } else { + throw new Error(`Unsupported sell sample source: ${source}`); + } + return { batchedOperation, source }; + }) + .filter(op => op.batchedOperation) as Array<{ + batchedOperation: BatchedOperation; + source: ERC20BridgeSource; + }>; + return { + encodeCall: contract => { + const subCalls = subOps.map(op => op.batchedOperation.encodeCall(contract)); + return contract.batchCall(subCalls).getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); + const samples = await Promise.all( + subOps.map(async (op, i) => + op.batchedOperation.handleCallResultsAsync(contract, rawSubCallResults[i]), + ), + ); + return subOps.map((op, i) => { + return samples[i].map((output, j) => ({ + source: op.source, + output, + input: takerFillAmounts[j], + })); + }); + }, + }; + }, + getBuyQuotes( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + makerFillAmounts: BigNumber[], + liquidityProviderRegistryAddress?: string | undefined, + ): BatchedOperation { + const subOps = sources.map(source => { + if (source === ERC20BridgeSource.Eth2Dai) { + return samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts); + } else if (source === ERC20BridgeSource.Uniswap) { + return samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts); + } else if (source === ERC20BridgeSource.LiquidityProvider) { + if (liquidityProviderRegistryAddress === undefined) { + throw new Error( + 'Cannot sample liquidity from a LiquidityProvider liquidity pool, if a registry is not provided.', + ); + } + return samplerOperations.getLiquidityProviderBuyQuotes( + liquidityProviderRegistryAddress, + makerToken, + takerToken, + makerFillAmounts, + ); + } else { + throw new Error(`Unsupported buy sample source: ${source}`); + } + }); + return { + encodeCall: contract => { + const subCalls = subOps.map(op => op.encodeCall(contract)); + return contract.batchCall(subCalls).getABIEncodedTransactionData(); + }, + handleCallResultsAsync: async (contract, callResults) => { + const rawSubCallResults = contract.getABIDecodedReturnData('batchCall', callResults); + const samples = await Promise.all( + subOps.map(async (op, i) => op.handleCallResultsAsync(contract, rawSubCallResults[i])), + ); + return sources.map((source, i) => { + return samples[i].map((output, j) => ({ + source, + output, + input: makerFillAmounts[j], + })); + }); + }, + }; + }, +}; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index b5108d5c22..ae8c55593e 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -1,3 +1,4 @@ +import { IERC20BridgeSamplerContract } from '@0x/contract-wrappers'; import { BigNumber } from '@0x/utils'; import { SignedOrderWithFillableAmounts } from '../../types'; @@ -31,6 +32,7 @@ export enum ERC20BridgeSource { CurveUsdcDai = 'Curve_USDC_DAI', CurveUsdcDaiUsdt = 'Curve_USDC_DAI_USDT', CurveUsdcDaiUsdtTusd = 'Curve_USDC_DAI_USDT_TUSD', + LiquidityProvider = 'LiquidityProvider', CurveUsdcDaiUsdtBusd = 'Curve_USDC_DAI_USDT_BUSD', } @@ -61,6 +63,7 @@ export enum FillFlags { SourceUniswap = 0x2, SourceEth2Dai = 0x4, SourceKyber = 0x8, + SourceLiquidityPool = 0x10, } /** @@ -175,3 +178,11 @@ export interface GetMarketOrdersOpts { */ fees: { [source: string]: BigNumber }; } + +/** + * A composable operation the be run in `DexOrderSampler.executeAsync()`. + */ +export interface BatchedOperation { + encodeCall(contract: IERC20BridgeSamplerContract): string; + handleCallResultsAsync(contract: IERC20BridgeSamplerContract, callResults: string): Promise; +} diff --git a/packages/asset-swapper/test/dex_sampler_test.ts b/packages/asset-swapper/test/dex_sampler_test.ts index 50db083f51..dc9d174215 100644 --- a/packages/asset-swapper/test/dex_sampler_test.ts +++ b/packages/asset-swapper/test/dex_sampler_test.ts @@ -1,4 +1,11 @@ -import { constants, expect, getRandomFloat, getRandomInteger, randomAddress } from '@0x/contracts-test-utils'; +import { + constants, + expect, + getRandomFloat, + getRandomInteger, + randomAddress, + toBaseUnitAmount, +} from '@0x/contracts-test-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; import { BigNumber, hexUtils } from '@0x/utils'; @@ -134,6 +141,72 @@ describe('DexSampler tests', () => { expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts); }); + it('getLiquidityProviderSellQuotes()', async () => { + const expectedMakerToken = randomAddress(); + const expectedTakerToken = randomAddress(); + const registry = randomAddress(); + const sampler = new MockSamplerContract({ + sampleSellsFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, fillAmounts) => { + expect(registryAddress).to.eq(registry); + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + return [toBaseUnitAmount(1001)]; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [result] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getSellQuotes( + [ERC20BridgeSource.LiquidityProvider], + expectedMakerToken, + expectedTakerToken, + [toBaseUnitAmount(1000)], + registry, + ), + ); + expect(result).to.deep.equal([ + [ + { + source: 'LiquidityProvider', + output: toBaseUnitAmount(1001), + input: toBaseUnitAmount(1000), + }, + ], + ]); + }); + + it('getLiquidityProviderBuyQuotes()', async () => { + const expectedMakerToken = randomAddress(); + const expectedTakerToken = randomAddress(); + const registry = randomAddress(); + const sampler = new MockSamplerContract({ + sampleBuysFromLiquidityProviderRegistry: (registryAddress, takerToken, makerToken, fillAmounts) => { + expect(registryAddress).to.eq(registry); + expect(takerToken).to.eq(expectedTakerToken); + expect(makerToken).to.eq(expectedMakerToken); + return [toBaseUnitAmount(999)]; + }, + }); + const dexOrderSampler = new DexOrderSampler(sampler); + const [result] = await dexOrderSampler.executeAsync( + DexOrderSampler.ops.getBuyQuotes( + [ERC20BridgeSource.LiquidityProvider], + expectedMakerToken, + expectedTakerToken, + [toBaseUnitAmount(1000)], + registry, + ), + ); + expect(result).to.deep.equal([ + [ + { + source: 'LiquidityProvider', + output: toBaseUnitAmount(999), + input: toBaseUnitAmount(1000), + }, + ], + ]); + }); + it('getEth2DaiSellQuotes()', async () => { const expectedTakerToken = randomAddress(); const expectedMakerToken = randomAddress(); diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index 04e289f7af..5375327269 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -8,10 +8,10 @@ import { Numberish, randomAddress, } from '@0x/contracts-test-utils'; - +import { Web3Wrapper } from '@0x/dev-utils'; import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber, hexUtils } from '@0x/utils'; +import { AssetProxyId, ERC20BridgeAssetData, SignedOrder } from '@0x/types'; +import { BigNumber, fromTokenUnitAmount, hexUtils, NULL_ADDRESS } from '@0x/utils'; import * as _ from 'lodash'; import { constants as assetSwapperConstants } from '../src/constants'; @@ -141,6 +141,7 @@ describe('MarketOperationUtils tests', () => { makerToken: string, takerToken: string, fillAmounts: BigNumber[], + liquidityProviderAddress?: string, ) => DexSample[][]; function createGetMultipleSellQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation { @@ -155,6 +156,28 @@ describe('MarketOperationUtils tests', () => { }; } + function callTradeOperationAndRetainLiquidityProviderParams( + tradeOperation: (rates: RatesBySource) => GetMultipleQuotesOperation, + rates: RatesBySource, + ): [{ sources: ERC20BridgeSource[]; liquidityProviderAddress?: string }, GetMultipleQuotesOperation] { + const liquidityPoolParams: { sources: ERC20BridgeSource[]; liquidityProviderAddress?: string } = { + sources: [], + liquidityProviderAddress: undefined, + }; + const fn = ( + sources: ERC20BridgeSource[], + makerToken: string, + takerToken: string, + fillAmounts: BigNumber[], + liquidityProviderAddress?: string, + ) => { + liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress; + liquidityPoolParams.sources = sources; + return tradeOperation(rates)(sources, makerToken, takerToken, fillAmounts, liquidityProviderAddress); + }; + return [liquidityPoolParams, fn]; + } + function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation { return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => { return sources.map(s => @@ -172,14 +195,47 @@ describe('MarketOperationUtils tests', () => { makerToken: string, takerToken: string, fillAmounts: BigNumber[], + liquidityProviderAddress?: string, ) => BigNumber; + type GetLiquidityProviderFromRegistryOperation = ( + registryAddress: string, + takerToken: string, + makerToken: string, + ) => string; + function createGetMedianSellRate(rate: Numberish): GetMedianRateOperation { return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => { return new BigNumber(rate); }; } + function getLiquidityProviderFromRegistry(): GetLiquidityProviderFromRegistryOperation { + return (registryAddress: string, takerToken: string, makerToken: string): string => { + return NULL_ADDRESS; + }; + } + + function getLiquidityProviderFromRegistryAndReturnCallParameters( + liquidityProviderAddress: string = NULL_ADDRESS, + ): [ + { registryAddress?: string; takerToken?: string; makerToken?: string }, + GetLiquidityProviderFromRegistryOperation + ] { + const callArgs: { registryAddress?: string; takerToken?: string; makerToken?: string } = { + registryAddress: undefined, + takerToken: undefined, + makerToken: undefined, + }; + const fn = (registryAddress: string, takerToken: string, makerToken: string): string => { + callArgs.makerToken = makerToken; + callArgs.takerToken = takerToken; + callArgs.registryAddress = registryAddress; + return liquidityProviderAddress; + }; + return [callArgs, fn]; + } + function createDecreasingRates(count: number): BigNumber[] { const rates: BigNumber[] = []; const initialRate = getRandomFloat(1e-3, 1e2); @@ -205,6 +261,7 @@ describe('MarketOperationUtils tests', () => { [ERC20BridgeSource.CurveUsdcDaiUsdt]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.CurveUsdcDaiUsdtTusd]: _.times(NUM_SAMPLES, () => 0), [ERC20BridgeSource.CurveUsdcDaiUsdtBusd]: _.times(NUM_SAMPLES, () => 0), + [ERC20BridgeSource.LiquidityProvider]: _.times(NUM_SAMPLES, () => 0), }; function findSourceWithMaxOutput(rates: RatesBySource): ERC20BridgeSource { @@ -239,6 +296,7 @@ describe('MarketOperationUtils tests', () => { getSellQuotes: createGetMultipleSellQuotesOperationFromRates(DEFAULT_RATES), getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(DEFAULT_RATES), getMedianSellRate: createGetMedianSellRate(1), + getLiquidityProviderFromRegistry: getLiquidityProviderFromRegistry(), }; function replaceSamplerOps(ops: Partial = {}): void { @@ -313,6 +371,31 @@ describe('MarketOperationUtils tests', () => { expect(sourcesPolled.sort()).to.deep.eq(SELL_SOURCES.slice().sort()); }); + it('polls the liquidity provider when the registry is provided in the arguments', async () => { + const [args, fn] = callTradeOperationAndRetainLiquidityProviderParams( + createGetMultipleSellQuotesOperationFromRates, + DEFAULT_RATES, + ); + replaceSamplerOps({ + getSellQuotes: fn, + }); + const registryAddress = randomAddress(); + const newMarketOperationUtils = new MarketOperationUtils( + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + registryAddress, + ); + await newMarketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { + ...DEFAULT_OPTS, + excludedSources: [], + }); + expect(args.sources.sort()).to.deep.eq( + SELL_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(), + ); + expect(args.liquidityProviderAddress).to.eql(registryAddress); + }); + it('does not poll DEXes in `excludedSources`', async () => { const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length)); let sourcesPolled: ERC20BridgeSource[] = []; @@ -530,6 +613,62 @@ describe('MarketOperationUtils tests', () => { const expectedSources = [ERC20BridgeSource.Native, ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber]; expect(orderSources).to.deep.eq(expectedSources); }); + + it('is able to create a order from LiquidityProvider', async () => { + const registryAddress = randomAddress(); + const liquidityProviderAddress = randomAddress(); + const xAsset = randomAddress(); + const yAsset = randomAddress(); + const toSell = fromTokenUnitAmount(10); + + const [getSellQuotesParams, getSellQuotesFn] = callTradeOperationAndRetainLiquidityProviderParams( + createGetMultipleSellQuotesOperationFromRates, + { + [ERC20BridgeSource.LiquidityProvider]: createDecreasingRates(5), + }, + ); + const [ + getLiquidityProviderParams, + getLiquidityProviderFn, + ] = getLiquidityProviderFromRegistryAndReturnCallParameters(liquidityProviderAddress); + replaceSamplerOps({ + getOrderFillableTakerAmounts: () => [constants.ZERO_AMOUNT], + getSellQuotes: getSellQuotesFn, + getLiquidityProviderFromRegistry: getLiquidityProviderFn, + }); + + const sampler = new MarketOperationUtils( + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + registryAddress, + ); + const result = await sampler.getMarketSellOrdersAsync( + [ + createOrder({ + makerAssetData: assetDataUtils.encodeERC20AssetData(xAsset), + takerAssetData: assetDataUtils.encodeERC20AssetData(yAsset), + }), + ], + Web3Wrapper.toBaseUnitAmount(10, 18), + { excludedSources: SELL_SOURCES, numSamples: 4 }, + ); + expect(result.length).to.eql(1); + expect(result[0].makerAddress).to.eql(liquidityProviderAddress); + + // tslint:disable-next-line:no-unnecessary-type-assertion + const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow( + result[0].makerAssetData, + ) as ERC20BridgeAssetData; + expect(decodedAssetData.assetProxyId).to.eql(AssetProxyId.ERC20Bridge); + expect(decodedAssetData.bridgeAddress).to.eql(liquidityProviderAddress); + expect(result[0].takerAssetAmount).to.bignumber.eql(toSell); + expect(getSellQuotesParams.sources).contains(ERC20BridgeSource.LiquidityProvider); + expect(getSellQuotesParams.liquidityProviderAddress).is.eql(registryAddress); + expect(getLiquidityProviderParams.registryAddress).is.eql(registryAddress); + expect(getLiquidityProviderParams.makerToken).is.eql(xAsset); + expect(getLiquidityProviderParams.takerToken).is.eql(yAsset); + }); }); describe('getMarketBuyOrdersAsync()', () => { @@ -580,6 +719,31 @@ describe('MarketOperationUtils tests', () => { expect(sourcesPolled).to.deep.eq(BUY_SOURCES); }); + it('polls the liquidity provider when the registry is provided in the arguments', async () => { + const [args, fn] = callTradeOperationAndRetainLiquidityProviderParams( + createGetMultipleBuyQuotesOperationFromRates, + DEFAULT_RATES, + ); + replaceSamplerOps({ + getBuyQuotes: fn, + }); + const registryAddress = randomAddress(); + const newMarketOperationUtils = new MarketOperationUtils( + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + registryAddress, + ); + await newMarketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { + ...DEFAULT_OPTS, + excludedSources: [], + }); + expect(args.sources.sort()).to.deep.eq( + BUY_SOURCES.concat([ERC20BridgeSource.LiquidityProvider]).sort(), + ); + expect(args.liquidityProviderAddress).to.eql(registryAddress); + }); + it('does not poll DEXes in `excludedSources`', async () => { const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length)); let sourcesPolled: ERC20BridgeSource[] = []; diff --git a/packages/asset-swapper/test/utils/mock_sampler_contract.ts b/packages/asset-swapper/test/utils/mock_sampler_contract.ts index 0ddc580b8f..8eb7320afb 100644 --- a/packages/asset-swapper/test/utils/mock_sampler_contract.ts +++ b/packages/asset-swapper/test/utils/mock_sampler_contract.ts @@ -21,6 +21,12 @@ export type SampleBuysHandler = ( makerToken: string, makerTokenAmounts: BigNumber[], ) => SampleResults; +export type SampleSellsLPHandler = ( + registryAddress: string, + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], +) => SampleResults; const DUMMY_PROVIDER = { sendAsync: (...args: any[]): any => { @@ -32,10 +38,12 @@ interface Handlers { getOrderFillableMakerAssetAmounts: GetOrderFillableAssetAmountHandler; getOrderFillableTakerAssetAmounts: GetOrderFillableAssetAmountHandler; sampleSellsFromKyberNetwork: SampleSellsHandler; + sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler; sampleSellsFromEth2Dai: SampleSellsHandler; sampleSellsFromUniswap: SampleSellsHandler; sampleBuysFromEth2Dai: SampleBuysHandler; sampleBuysFromUniswap: SampleBuysHandler; + sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler; } export class MockSamplerContract extends IERC20BridgeSamplerContract { @@ -119,6 +127,22 @@ export class MockSamplerContract extends IERC20BridgeSamplerContract { ); } + public sampleSellsFromLiquidityProviderRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + takerAssetAmounts: BigNumber[], + ): ContractFunctionObj { + return this._wrapCall( + super.sampleSellsFromLiquidityProviderRegistry, + this._handlers.sampleSellsFromLiquidityProviderRegistry, + registryAddress, + takerToken, + makerToken, + takerAssetAmounts, + ); + } + public sampleBuysFromEth2Dai( takerToken: string, makerToken: string, diff --git a/packages/contract-artifacts/artifacts/DummyLiquidityProvider.json b/packages/contract-artifacts/artifacts/DummyLiquidityProvider.json new file mode 100644 index 0000000000..e06cf8a361 --- /dev/null +++ b/packages/contract-artifacts/artifacts/DummyLiquidityProvider.json @@ -0,0 +1,81 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "DummyLiquidityProvider", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "buyAmount", "type": "uint256" } + ], + "name": "getBuyQuote", + "outputs": [{ "internalType": "uint256", "name": "takerTokenAmount", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" } + ], + "name": "getSellQuote", + "outputs": [{ "internalType": "uint256", "name": "makerTokenAmount", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "methods": { + "getBuyQuote(address,address,uint256)": { + "details": "Quotes the amount of `takerToken` that would need to be sold in order to obtain `buyAmount` of `makerToken`.", + "params": { "buyAmount": "Amount of `makerToken` to buy." }, + "return": "takerTokenAmount Amount of `takerToken` that would need to be sold." + }, + "getSellQuote(address,address,uint256)": { + "details": "Quotes the amount of `makerToken` that would be obtained by selling `sellAmount` of `takerToken`.", + "params": { "sellAmount": "Amount of `takerToken` to sell." }, + "return": "makerTokenAmount Amount of `makerToken` that would be obtained." + } + } + }, + "evm": { + "bytecode": { + "object": "0x608060405234801561001057600080fd5b50610159806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063343fbcdd1461003b57806345060eb014610064575b600080fd5b61004e6100493660046100a8565b610077565b60405161005b91906100e8565b60405180910390f35b61004e6100723660046100a8565b61009f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b60010192915050565b6000806000606084860312156100bc578283fd5b83356100c7816100f1565b925060208401356100d7816100f1565b929592945050506040919091013590565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461011357600080fd5b5056fea365627a7a72315820981135e6e25d9062a0a9bcf7e08e326cde449b18310db7488d1db4e79ef0f6f36c6578706572696d656e74616cf564736f6c63430005100040" + }, + "deployedBytecode": { + "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063343fbcdd1461003b57806345060eb014610064575b600080fd5b61004e6100493660046100a8565b610077565b60405161005b91906100e8565b60405180910390f35b61004e6100723660046100a8565b61009f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b60010192915050565b6000806000606084860312156100bc578283fd5b83356100c7816100f1565b925060208401356100d7816100f1565b929592945050506040919091013590565b90815260200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461011357600080fd5b5056fea365627a7a72315820981135e6e25d9062a0a9bcf7e08e326cde449b18310db7488d1db4e79ef0f6f36c6578706572696d656e74616cf564736f6c63430005100040" + } + } + }, + "compiler": { + "name": "solc", + "version": "soljson-v0.5.16+commit.9c3226ce.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "devdoc", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "istanbul" + } + }, + "chains": {} +} diff --git a/packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json b/packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json new file mode 100644 index 0000000000..6d6a0f0baf --- /dev/null +++ b/packages/contract-artifacts/artifacts/DummyLiquidityProviderRegistry.json @@ -0,0 +1,83 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "DummyLiquidityProviderRegistry", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "xToken", "type": "address" }, + { "internalType": "address", "name": "yToken", "type": "address" } + ], + "name": "getLiquidityProviderForMarket", + "outputs": [{ "internalType": "address", "name": "poolAddress", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "xToken", "type": "address" }, + { "internalType": "address", "name": "yToken", "type": "address" }, + { "internalType": "address", "name": "poolAddress", "type": "address" } + ], + "name": "setLiquidityProviderForMarket", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "devdoc": { + "methods": { + "getLiquidityProviderForMarket(address,address)": { + "details": "Returns the address of pool for a market given market (xAsset, yAsset), or reverts if pool does not exist.", + "params": { "xToken": "First asset managed by pool.", "yToken": "Second asset managed by pool." }, + "return": "Address of pool." + }, + "setLiquidityProviderForMarket(address,address,address)": { + "details": "Sets address of pool for a market given market (xAsset, yAsset).", + "params": { + "poolAddress": "Address of pool.", + "xToken": "First asset managed by pool.", + "yToken": "Second asset managed by pool." + } + } + } + }, + "evm": { + "bytecode": { + "object": "0x608060405234801561001057600080fd5b506102a6806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063153f59971461003b57806384da8d1e14610064575b600080fd5b61004e610049366004610192565b610079565b60405161005b919061020b565b60405180910390f35b6100776100723660046101c6565b6100f2565b005b73ffffffffffffffffffffffffffffffffffffffff808316600090815260208181526040808320858516845290915290205416806100ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e39061022c565b60405180910390fd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff92831660008181526020818152604080832095871683529481528482208054969094167fffffffffffffffffffffffff0000000000000000000000000000000000000000968716811790945581815284822092825291909152919091208054909216179055565b803573ffffffffffffffffffffffffffffffffffffffff811681146100ec57600080fd5b600080604083850312156101a4578182fd5b6101ae848461016e565b91506101bd846020850161016e565b90509250929050565b6000806000606084860312156101da578081fd5b6101e4858561016e565b92506101f3856020860161016e565b9150610202856040860161016e565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252601c908201527f52656769737472792f4d41524b45545f504149525f4e4f545f5345540000000060408201526060019056fea365627a7a723158200b589233a17eab806bfb7e334f40bc1ba4502479e55b2aa562c069bc440ceb476c6578706572696d656e74616cf564736f6c63430005100040" + }, + "deployedBytecode": { + "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063153f59971461003b57806384da8d1e14610064575b600080fd5b61004e610049366004610192565b610079565b60405161005b919061020b565b60405180910390f35b6100776100723660046101c6565b6100f2565b005b73ffffffffffffffffffffffffffffffffffffffff808316600090815260208181526040808320858516845290915290205416806100ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100e39061022c565b60405180910390fd5b92915050565b73ffffffffffffffffffffffffffffffffffffffff92831660008181526020818152604080832095871683529481528482208054969094167fffffffffffffffffffffffff0000000000000000000000000000000000000000968716811790945581815284822092825291909152919091208054909216179055565b803573ffffffffffffffffffffffffffffffffffffffff811681146100ec57600080fd5b600080604083850312156101a4578182fd5b6101ae848461016e565b91506101bd846020850161016e565b90509250929050565b6000806000606084860312156101da578081fd5b6101e4858561016e565b92506101f3856020860161016e565b9150610202856040860161016e565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252601c908201527f52656769737472792f4d41524b45545f504149525f4e4f545f5345540000000060408201526060019056fea365627a7a723158200b589233a17eab806bfb7e334f40bc1ba4502479e55b2aa562c069bc440ceb476c6578706572696d656e74616cf564736f6c63430005100040" + } + } + }, + "compiler": { + "name": "solc", + "version": "soljson-v0.5.16+commit.9c3226ce.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "devdoc", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "istanbul" + } + }, + "chains": {} +} diff --git a/packages/contract-artifacts/artifacts/ERC20BridgeSampler.json b/packages/contract-artifacts/artifacts/ERC20BridgeSampler.json new file mode 100644 index 0000000000..f4f7a148e0 --- /dev/null +++ b/packages/contract-artifacts/artifacts/ERC20BridgeSampler.json @@ -0,0 +1,346 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "ERC20BridgeSampler", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [{ "internalType": "bytes[]", "name": "callDatas", "type": "bytes[]" }], + "name": "batchCall", + "outputs": [{ "internalType": "bytes[]", "name": "callResults", "type": "bytes[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "registryAddress", "type": "address" }, + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" } + ], + "name": "getLiquidityProviderFromRegistry", + "outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "makerAddress", "type": "address" }, + { "internalType": "address", "name": "takerAddress", "type": "address" }, + { "internalType": "address", "name": "feeRecipientAddress", "type": "address" }, + { "internalType": "address", "name": "senderAddress", "type": "address" }, + { "internalType": "uint256", "name": "makerAssetAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "takerAssetAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "makerFee", "type": "uint256" }, + { "internalType": "uint256", "name": "takerFee", "type": "uint256" }, + { "internalType": "uint256", "name": "expirationTimeSeconds", "type": "uint256" }, + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "bytes", "name": "makerAssetData", "type": "bytes" }, + { "internalType": "bytes", "name": "takerAssetData", "type": "bytes" }, + { "internalType": "bytes", "name": "makerFeeAssetData", "type": "bytes" }, + { "internalType": "bytes", "name": "takerFeeAssetData", "type": "bytes" } + ], + "internalType": "struct LibOrder.Order[]", + "name": "orders", + "type": "tuple[]" + }, + { "internalType": "bytes[]", "name": "orderSignatures", "type": "bytes[]" } + ], + "name": "getOrderFillableMakerAssetAmounts", + "outputs": [ + { "internalType": "uint256[]", "name": "orderFillableMakerAssetAmounts", "type": "uint256[]" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "makerAddress", "type": "address" }, + { "internalType": "address", "name": "takerAddress", "type": "address" }, + { "internalType": "address", "name": "feeRecipientAddress", "type": "address" }, + { "internalType": "address", "name": "senderAddress", "type": "address" }, + { "internalType": "uint256", "name": "makerAssetAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "takerAssetAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "makerFee", "type": "uint256" }, + { "internalType": "uint256", "name": "takerFee", "type": "uint256" }, + { "internalType": "uint256", "name": "expirationTimeSeconds", "type": "uint256" }, + { "internalType": "uint256", "name": "salt", "type": "uint256" }, + { "internalType": "bytes", "name": "makerAssetData", "type": "bytes" }, + { "internalType": "bytes", "name": "takerAssetData", "type": "bytes" }, + { "internalType": "bytes", "name": "makerFeeAssetData", "type": "bytes" }, + { "internalType": "bytes", "name": "takerFeeAssetData", "type": "bytes" } + ], + "internalType": "struct LibOrder.Order[]", + "name": "orders", + "type": "tuple[]" + }, + { "internalType": "bytes[]", "name": "orderSignatures", "type": "bytes[]" } + ], + "name": "getOrderFillableTakerAssetAmounts", + "outputs": [ + { "internalType": "uint256[]", "name": "orderFillableTakerAssetAmounts", "type": "uint256[]" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleBuysFromEth2Dai", + "outputs": [{ "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "registryAddress", "type": "address" }, + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleBuysFromLiquidityProviderRegistry", + "outputs": [{ "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleBuysFromUniswap", + "outputs": [{ "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "curveAddress", "type": "address" }, + { "internalType": "int128", "name": "fromTokenIdx", "type": "int128" }, + { "internalType": "int128", "name": "toTokenIdx", "type": "int128" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromCurve", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromEth2Dai", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromKyberNetwork", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "registryAddress", "type": "address" }, + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromLiquidityProviderRegistry", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromUniswap", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "methods": { + "batchCall(bytes[])": { + "details": "Call multiple public functions on this contract in a single transaction.", + "params": { "callDatas": "ABI-encoded call data for each function call." }, + "return": "callResults ABI-encoded results data for each call." + }, + "getLiquidityProviderFromRegistry(address,address,address)": { + "details": "Returns the address of a liquidity provider for the given market (takerToken, makerToken), from a registry of liquidity providers. Returns address(0) if no such provider exists in the registry.", + "params": { + "makerToken": "Maker asset managed by liquidity provider.", + "takerToken": "Taker asset managed by liquidity provider." + }, + "return": "providerAddress Address of the liquidity provider." + }, + "getOrderFillableMakerAssetAmounts((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[])": { + "details": "Queries the fillable taker asset amounts of native orders. Effectively ignores orders that have empty signatures or", + "params": { + "orderSignatures": "Signatures for each respective order in `orders`.", + "orders": "Native orders to query." + }, + "return": "orderFillableMakerAssetAmounts How much maker asset can be filled by each order in `orders`." + }, + "getOrderFillableTakerAssetAmounts((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[])": { + "details": "Queries the fillable taker asset amounts of native orders. Effectively ignores orders that have empty signatures or maker/taker asset amounts (returning 0).", + "params": { + "orderSignatures": "Signatures for each respective order in `orders`.", + "orders": "Native orders to query." + }, + "return": "orderFillableTakerAssetAmounts How much taker asset can be filled by each order in `orders`." + }, + "sampleBuysFromEth2Dai(address,address,uint256[])": { + "details": "Sample buy quotes from Eth2Dai/Oasis.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Maker token sell amount for each sample." + }, + "return": "takerTokenAmounts Taker amounts sold at each maker token amount." + }, + "sampleBuysFromLiquidityProviderRegistry(address,address,address,uint256[])": { + "details": "Sample buy quotes from an arbitrary on-chain liquidity provider.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "makerTokenAmounts": "Maker token buy amount for each sample.", + "registryAddress": "Address of the liquidity provider registry contract.", + "takerToken": "Address of the taker token (what to sell)." + }, + "return": "takerTokenAmounts Taker amounts sold at each maker token amount." + }, + "sampleBuysFromUniswap(address,address,uint256[])": { + "details": "Sample buy quotes from Uniswap.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "makerTokenAmounts": "Maker token sell amount for each sample.", + "takerToken": "Address of the taker token (what to sell)." + }, + "return": "takerTokenAmounts Taker amounts sold at each maker token amount." + }, + "sampleSellsFromCurve(address,int128,int128,uint256[])": { + "details": "Sample sell quotes from Curve.", + "params": { + "curveAddress": "Address of the Curve contract.", + "fromTokenIdx": "Index of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample.", + "toTokenIdx": "Index of the maker token (what to buy)." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, + "sampleSellsFromEth2Dai(address,address,uint256[])": { + "details": "Sample sell quotes from Eth2Dai/Oasis.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, + "sampleSellsFromKyberNetwork(address,address,uint256[])": { + "details": "Sample sell quotes from Kyber.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, + "sampleSellsFromLiquidityProviderRegistry(address,address,address,uint256[])": { + "details": "Sample sell quotes from an arbitrary on-chain liquidity provider.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "registryAddress": "Address of the liquidity provider registry contract.", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, + "sampleSellsFromUniswap(address,address,uint256[])": { + "details": "Sample sell quotes from Uniswap.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + } + } + }, + "evm": { + "bytecode": { + "object": "0x608060405234801561001057600080fd5b50612a0d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806368be3cf2116100815780639f76ad351161005b5780639f76ad35146101a7578063a2c28d4b146101ba578063c7f7142e146101cd576100d4565b806368be3cf2146101615780636dd6b78d146101815780638b123a0214610194576100d4565b806359f515d0116100b257806359f515d01461012857806360ee052a1461013b57806364ee6ade1461014e576100d4565b8063354152a3146100d95780634703a7e6146101025780634cb8e25314610115575b600080fd5b6100ec6100e736600461237c565b6101ed565b6040516100f991906126e3565b60405180910390f35b6100ec61011036600461231c565b6103be565b6100ec61012336600461231c565b61059a565b6100ec610136366004612426565b61088a565b6100ec61014936600461231c565b610933565b6100ec61015c36600461231c565b610bf3565b61017461016f3660046123ba565b610db9565b6040516100f99190612665565b6100ec61018f36600461231c565b610ef8565b6100ec6101a2366004612426565b6111a0565b6100ec6101b53660046122a9565b611468565b6100ec6101c83660046122a9565b61166d565b6101e06101db36600461225f565b611859565b6040516100f991906125ec565b60606000825190508060405190808252806020026020018201604052801561021f578160200160208202803883390190505b50915060005b818110156103b457600060608873ffffffffffffffffffffffffffffffffffffffff16620927c0600073ffffffffffffffffffffffffffffffffffffffff166307211ef7905060e01b8a8a8a888151811061027c57fe5b602002602001015160405160240161029693929190612756565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161031f91906125d0565b6000604051808303818686fa925050503d806000811461035b576040519150601f19603f3d011682016040523d82523d6000602084013e610360565b606091505b5090925090506000821561038957818060200190516103829190810190612544565b9050610391565b5050506103b4565b8086858151811061039e57fe5b6020908102919091010152505050600101610225565b5050949350505050565b60606103ca8385611994565b81516040805182815260208084028201019091528180156103f5578160200160208202803883390190505b50915060005b81811015610591576000606061040f611a07565b73ffffffffffffffffffffffffffffffffffffffff16620f4240600073ffffffffffffffffffffffffffffffffffffffff1663ff1fd974905060e01b8a8a8a888151811061045957fe5b602002602001015160405160240161047393929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516104fc91906125d0565b6000604051808303818686fa925050503d8060008114610538576040519150601f19603f3d011682016040523d82523d6000602084013e61053d565b606091505b50909250905060008215610566578180602001905161055f9190810190612544565b905061056e565b505050610591565b8086858151811061057b57fe5b60209081029190910101525050506001016103fb565b50509392505050565b60606105a68385611994565b60006105b0611a1f565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16146105e857846105fe565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b9050600061060a611a1f565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16146106425784610658565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b9050600061066587611a37565b60ff169050600061067587611a37565b60ff169050600086519050806040519080825280602002602001820160405280156106aa578160200160208202803883390190505b50955060005b8181101561087d57600060606106c4611a48565b73ffffffffffffffffffffffffffffffffffffffff166216e360600073ffffffffffffffffffffffffffffffffffffffff1663809a9e55905060e01b8a8a8e888151811061070e57fe5b602002602001015160405160240161072893929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516107b191906125d0565b6000604051808303818686fa925050503d80600081146107ed576040519150601f19603f3d011682016040523d82523d6000602084013e6107f2565b606091505b5090925090506000821561081b57818060200190516108149190810190612544565b9050610823565b50505061087d565b670de0b6b3a764000087600a0a87600a0a8d878151811061084057fe5b60200260200101518402028161085257fe5b048161085a57fe5b048a858151811061086757fe5b60209081029190910101525050506001016106b0565b5050505050509392505050565b606061089683836111a0565b905060005b835181101561092c578181815181106108b057fe5b60200260200101516000146109245761090b8282815181106108ce57fe5b60200260200101518583815181106108e257fe5b602002602001015160a001518684815181106108fa57fe5b602002602001015160800151611a60565b82828151811061091757fe5b6020026020010181815250505b60010161089b565b5092915050565b606061093f8385611994565b815160408051828152602080840282010190915281801561096a578160200160208202803883390190505b5091506000610977611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16146109b7576109b286611aa2565b6109ba565b60005b905060006109c6611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610a0657610a0186611aa2565b610a09565b60005b905060005b83811015610be8576001610a20611a1f565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415610ab7578651610a969085907f2640f62c00000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b6020026020010151611b34565b878481518110610aa257fe5b60200260200101819350828152505050610bd4565b610abf611a1f565b73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff161415610b28578651610a969084907f59e9486200000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b8651600090610b619085907f59e9486200000000000000000000000000000000000000000000000000000000908b9087908110610a8957fe5b925090508015610bb757610b96857f2640f62c0000000000000000000000000000000000000000000000000000000083611b34565b888581518110610ba257fe5b60200260200101819450828152505050610bd2565b6000878481518110610bc557fe5b6020026020010181815250505b505b80610bdf5750610be8565b50600101610a0e565b505050509392505050565b6060610bff8385611994565b8151604080518281526020808402820101909152818015610c2a578160200160208202803883390190505b50915060005b818110156105915760006060610c44611a07565b73ffffffffffffffffffffffffffffffffffffffff16620f4240600073ffffffffffffffffffffffffffffffffffffffff1663144a2752905060e01b898b8a8881518110610c8e57fe5b6020026020010151604051602401610ca893929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610d3191906125d0565b6000604051808303818686fa925050503d8060008114610d6d576040519150601f19603f3d011682016040523d82523d6000602084013e610d72565b606091505b509092509050600082156105665781806020019051610d949190810190612544565b905080868581518110610da357fe5b6020908102919091010152505050600101610c30565b604080518281526020808402820101909152606090828015610def57816020015b6060815260200190600190039081610dda5790505b50905060005b80831461092c576000606030868685818110610e0d57fe5b6020028201905080357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe136849003018112610e4757600080fd5b9091016020810191503567ffffffffffffffff811115610e6657600080fd5b36819003821315610e7657600080fd5b604051610e849291906125c0565b600060405180830381855afa9150503d8060008114610ebf576040519150601f19603f3d011682016040523d82523d6000602084013e610ec4565b606091505b509150915081610ed657805160208201fd5b80848481518110610ee357fe5b60209081029190910101525050600101610df5565b6060610f048385611994565b8151604080518281526020808402820101909152818015610f2f578160200160208202803883390190505b5091506000610f3c611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610f7c57610f7786611aa2565b610f7f565b60005b90506000610f8b611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610fcb57610fc686611aa2565b610fce565b60005b905060005b83811015610be8576001610fe5611a1f565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16141561106f57865161104e9085907f95b68fe700000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b87848151811061105a57fe5b6020026020010181935082815250505061118c565b611077611a1f565b73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614156110e057865161104e9084907fcd7724c300000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b86516000906111199086907f95b68fe700000000000000000000000000000000000000000000000000000000908b9087908110610a8957fe5b92509050801561116f5761114e847fcd7724c30000000000000000000000000000000000000000000000000000000083611b34565b88858151811061115a57fe5b6020026020010181945082815250505061118a565b600087848151811061117d57fe5b6020026020010181815250505b505b806111975750610be8565b50600101610fd3565b606082516040519080825280602002602001820160405280156111cd578160200160208202803883390190505b50905060005b8351811461092c578281815181106111e757fe5b60200260200101515160001480611215575083818151811061120557fe5b6020026020010151608001516000145b80611237575083818151811061122757fe5b602002602001015160a001516000145b1561125b57600082828151811061124a57fe5b602002602001018181525050611460565b60006060611267611c7d565b73ffffffffffffffffffffffffffffffffffffffff166207a120611289611c7d565b5087517fe77286eb00000000000000000000000000000000000000000000000000000000908990879081106112ba57fe5b60200260200101518887815181106112ce57fe5b60200260200101516040516024016112e79291906127d1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161137091906125d0565b6000604051808303818686fa925050503d80600081146113ac576040519150601f19603f3d011682016040523d82523d6000602084013e6113b1565b606091505b5091509150816113dc5760008484815181106113c957fe5b6020026020010181815250505050611460565b6113e4611f5b565b600080838060200190516113fb91908101906124d7565b9194509250905060038351600681111561141157fe5b14158061141c575080155b1561144057600087878151811061142f57fe5b60200260200101818152505061145a565b8187878151811061144d57fe5b6020026020010181815250505b50505050505b6001016111d3565b60606000825190508060405190808252806020026020018201604052801561149a578160200160208202803883390190505b50915060006114aa878787611859565b905073ffffffffffffffffffffffffffffffffffffffff81166114cf57506116659050565b60005b8281101561166157600060608373ffffffffffffffffffffffffffffffffffffffff1662030d40600073ffffffffffffffffffffffffffffffffffffffff1663343fbcdd905060e01b8b8b8b888151811061152957fe5b602002602001015160405160240161154393929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516115cc91906125d0565b6000604051808303818686fa925050503d8060008114611608576040519150601f19603f3d011682016040523d82523d6000602084013e61160d565b606091505b50909250905060008215611636578180602001905161162f9190810190612544565b905061163e565b505050611661565b8087858151811061164b57fe5b60209081029190910101525050506001016114d2565b5050505b949350505050565b60606000825190508060405190808252806020026020018201604052801561169f578160200160208202803883390190505b50915060006116af878787611859565b905073ffffffffffffffffffffffffffffffffffffffff81166116d457506116659050565b60005b8281101561166157600060608373ffffffffffffffffffffffffffffffffffffffff1662030d40600073ffffffffffffffffffffffffffffffffffffffff166345060eb0905060e01b8b8b8b888151811061172e57fe5b602002602001015160405160240161174893929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516117d191906125d0565b6000604051808303818686fa925050503d806000811461180d576040519150601f19603f3d011682016040523d82523d6000602084013e611812565b606091505b5090925090506000821561163657818060200190516118349190810190612544565b90508087858151811061184357fe5b60209081029190910101525050506001016116d7565b6040516000906060907f153f59970000000000000000000000000000000000000000000000000000000090611894908690869060240161260d565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608673ffffffffffffffffffffffffffffffffffffffff168360405161191c91906125d0565b600060405180830381855afa9150503d8060008114611957576040519150601f19603f3d011682016040523d82523d6000602084013e61195c565b606091505b509150915081801561196f575080516020145b156119895761197f81600c611c95565b935050505061198d565b5050505b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611a03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119fa90612774565b60405180910390fd5b5050565b73794e6e91555438afc3ccf1c5076a74f42133d08d90565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290565b6000611a4282611cda565b92915050565b73818e6fecd516ecc3849daf6845e3ec868087b75590565b600061166583611a96611a7a82600163ffffffff611dab16565b611a8a888763ffffffff611dca16565b9063ffffffff611dfb16565b9063ffffffff611e1716565b6000611aac611e41565b73ffffffffffffffffffffffffffffffffffffffff166306f2bf62836040518263ffffffff1660e01b8152600401611ae491906125ec565b60206040518083038186803b158015611afc57600080fd5b505afa158015611b10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a429190810190612243565b60008073ffffffffffffffffffffffffffffffffffffffff8516611b5757611c75565b60608573ffffffffffffffffffffffffffffffffffffffff16620249f08686604051602401611b869190612925565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611c0f91906125d0565b6000604051808303818686fa925050503d8060008114611c4b576040519150601f19603f3d011682016040523d82523d6000602084013e611c50565b606091505b5090925090508115611c735780806020019051611c709190810190612544565b92505b505b935093915050565b7374134cf88b21383713e096a5ecf59e297dc7f54790565b60008160140183511015611cbb57611cbb611cb66004855185601401611e59565b611efe565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b600060129050600060608373ffffffffffffffffffffffffffffffffffffffff166040518060400160405280600481526020017f313ce56700000000000000000000000000000000000000000000000000000000815250604051611d3e91906125d0565b600060405180830381855afa9150503d8060008114611d79576040519150601f19603f3d011682016040523d82523d6000602084013e611d7e565b606091505b5091509150818015611d91575080516020145b15611da457611da1816000611f06565b92505b5050919050565b600082821115611dc457611dc4611cb660028585611f12565b50900390565b600082611dd957506000611a42565b82820282848281611de657fe5b041461198d5761198d611cb660018686611f12565b60008282018381101561198d5761198d611cb660008686611f12565b600081611e2d57611e2d611cb660038585611f12565b6000828481611e3857fe5b04949350505050565b73c0a47dfe034b400b47bdad5fecda2621de6c4d9590565b6060632800659560e01b848484604051602401611e7893929190612748565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290509392505050565b805160208201fd5b600061198d8383611f31565b606063e946c1bb60e01b848484604051602401611e7893929190612726565b60008160200183511015611f5257611f52611cb66005855185602001611e59565b50016020015190565b6040805160608101909152806000815260006020820181905260409091015290565b8035611a42816129a5565b600082601f830112611f98578081fd5b8135611fab611fa682612955565b61292e565b8181529150602080830190840160005b83811015611fe857611fd3876020843589010161205b565b83526020928301929190910190600101611fbb565b5050505092915050565b600082601f830112612002578081fd5b8135612010611fa682612955565b81815291506020808301908481018184028601820187101561203157600080fd5b60005b8481101561205057813584529282019290820190600101612034565b505050505092915050565b600082601f83011261206b578081fd5b813567ffffffffffffffff811115612081578182fd5b6120b260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161292e565b91508082528360208285010111156120c957600080fd5b8060208401602084013760009082016020015292915050565b8035600f81900b8114611a4257600080fd5b60006101c0808385031215612107578182fd5b6121108161292e565b91505061211d8383611f7d565b815261212c8360208401611f7d565b602082015261213e8360408401611f7d565b60408201526121508360608401611f7d565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff808211156121b257600080fd5b6121be8683870161205b565b838501526101609250828501359150808211156121da57600080fd5b6121e68683870161205b565b8385015261018092508285013591508082111561220257600080fd5b61220e8683870161205b565b838501526101a092508285013591508082111561222a57600080fd5b506122378582860161205b565b82840152505092915050565b600060208284031215612254578081fd5b815161198d816129a5565b600080600060608486031215612273578182fd5b833561227e816129a5565b9250602084013561228e816129a5565b9150604084013561229e816129a5565b809150509250925092565b600080600080608085870312156122be578081fd5b84356122c9816129a5565b935060208501356122d9816129a5565b925060408501356122e9816129a5565b9150606085013567ffffffffffffffff811115612304578182fd5b61231087828801611ff2565b91505092959194509250565b600080600060608486031215612330578283fd5b833561233b816129a5565b9250602084013561234b816129a5565b9150604084013567ffffffffffffffff811115612366578182fd5b61237286828701611ff2565b9150509250925092565b60008060008060808587031215612391578182fd5b843561239c816129a5565b93506123ab86602087016120e2565b92506122e986604087016120e2565b600080602083850312156123cc578182fd5b823567ffffffffffffffff808211156123e3578384fd5b81850186601f8201126123f4578485fd5b8035925081831115612404578485fd5b8660208085028301011115612417578485fd5b60200196919550909350505050565b60008060408385031215612438578182fd5b823567ffffffffffffffff8082111561244f578384fd5b81850186601f820112612460578485fd5b80359250612470611fa684612955565b83815260208082019190838101885b878110156124a8576124968c8484358901016120f4565b8552938201939082019060010161247f565b509197508801359450505050808211156124c0578283fd5b506124cd85828601611f88565b9150509250929050565b600080600083850360a08112156124ec578182fd5b60608112156124f9578182fd5b50612504606061292e565b845160078110612512578283fd5b81526020858101519082015260408086015190820152606085015160808601519194509250801515811461229e578182fd5b600060208284031215612555578081fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845261258e816020860160208601612975565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000828483379101908152919050565b600082516125e2818460208701612975565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b6000602080830181845280855180835260408601915060408482028701019250838701855b828110156126d6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526126c4858351612576565b9450928501929085019060010161268a565b5092979650505050505050565b602080825282518282018190526000918401906040840190835b8181101561271b5783518352602093840193909201916001016126fd565b509095945050505050565b606081016004851061273457fe5b938152602081019290925260409091015290565b606081016008851061273457fe5b600f93840b81529190920b6020820152604081019190915260600190565b60208082526025908201527f455243323042726964676553616d706c65722f494e56414c49445f544f4b454e60408201527f5f50414952000000000000000000000000000000000000000000000000000000606082015260800190565b6000604082526127e560408301855161255c565b60208401516127f7606084018261255c565b50604084015161280a608084018261255c565b50606084015161281d60a084018261255c565b50608084015160c083015260a084015160e083015260c0840151610100818185015260e086015191506101208281860152818701519250610140915082828601528087015192505061016082818601528187015192506101c09150610180828187015261288e610200870185612576565b8289015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc092506101a08388830301818901526128cd8287612576565b838b015196508489820301868a01526128e68188612576565b955050808a0151955050505080858303016101e0860152506129088183612576565b848103602086015261291a8187612576565b979650505050505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561294d57600080fd5b604052919050565b600067ffffffffffffffff82111561296b578081fd5b5060209081020190565b60005b83811015612990578181015183820152602001612978565b8381111561299f576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146129c757600080fd5b5056fea365627a7a7231582034e7eab64809a5ab7420c524f487ac0ca03a80f2b355b2d12a392dde2df0522e6c6578706572696d656e74616cf564736f6c63430005100040" + }, + "deployedBytecode": { + "object": "0x608060405234801561001057600080fd5b50600436106100d45760003560e01c806368be3cf2116100815780639f76ad351161005b5780639f76ad35146101a7578063a2c28d4b146101ba578063c7f7142e146101cd576100d4565b806368be3cf2146101615780636dd6b78d146101815780638b123a0214610194576100d4565b806359f515d0116100b257806359f515d01461012857806360ee052a1461013b57806364ee6ade1461014e576100d4565b8063354152a3146100d95780634703a7e6146101025780634cb8e25314610115575b600080fd5b6100ec6100e736600461237c565b6101ed565b6040516100f991906126e3565b60405180910390f35b6100ec61011036600461231c565b6103be565b6100ec61012336600461231c565b61059a565b6100ec610136366004612426565b61088a565b6100ec61014936600461231c565b610933565b6100ec61015c36600461231c565b610bf3565b61017461016f3660046123ba565b610db9565b6040516100f99190612665565b6100ec61018f36600461231c565b610ef8565b6100ec6101a2366004612426565b6111a0565b6100ec6101b53660046122a9565b611468565b6100ec6101c83660046122a9565b61166d565b6101e06101db36600461225f565b611859565b6040516100f991906125ec565b60606000825190508060405190808252806020026020018201604052801561021f578160200160208202803883390190505b50915060005b818110156103b457600060608873ffffffffffffffffffffffffffffffffffffffff16620927c0600073ffffffffffffffffffffffffffffffffffffffff166307211ef7905060e01b8a8a8a888151811061027c57fe5b602002602001015160405160240161029693929190612756565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161031f91906125d0565b6000604051808303818686fa925050503d806000811461035b576040519150601f19603f3d011682016040523d82523d6000602084013e610360565b606091505b5090925090506000821561038957818060200190516103829190810190612544565b9050610391565b5050506103b4565b8086858151811061039e57fe5b6020908102919091010152505050600101610225565b5050949350505050565b60606103ca8385611994565b81516040805182815260208084028201019091528180156103f5578160200160208202803883390190505b50915060005b81811015610591576000606061040f611a07565b73ffffffffffffffffffffffffffffffffffffffff16620f4240600073ffffffffffffffffffffffffffffffffffffffff1663ff1fd974905060e01b8a8a8a888151811061045957fe5b602002602001015160405160240161047393929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516104fc91906125d0565b6000604051808303818686fa925050503d8060008114610538576040519150601f19603f3d011682016040523d82523d6000602084013e61053d565b606091505b50909250905060008215610566578180602001905161055f9190810190612544565b905061056e565b505050610591565b8086858151811061057b57fe5b60209081029190910101525050506001016103fb565b50509392505050565b60606105a68385611994565b60006105b0611a1f565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16146105e857846105fe565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b9050600061060a611a1f565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16146106425784610658565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b9050600061066587611a37565b60ff169050600061067587611a37565b60ff169050600086519050806040519080825280602002602001820160405280156106aa578160200160208202803883390190505b50955060005b8181101561087d57600060606106c4611a48565b73ffffffffffffffffffffffffffffffffffffffff166216e360600073ffffffffffffffffffffffffffffffffffffffff1663809a9e55905060e01b8a8a8e888151811061070e57fe5b602002602001015160405160240161072893929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516107b191906125d0565b6000604051808303818686fa925050503d80600081146107ed576040519150601f19603f3d011682016040523d82523d6000602084013e6107f2565b606091505b5090925090506000821561081b57818060200190516108149190810190612544565b9050610823565b50505061087d565b670de0b6b3a764000087600a0a87600a0a8d878151811061084057fe5b60200260200101518402028161085257fe5b048161085a57fe5b048a858151811061086757fe5b60209081029190910101525050506001016106b0565b5050505050509392505050565b606061089683836111a0565b905060005b835181101561092c578181815181106108b057fe5b60200260200101516000146109245761090b8282815181106108ce57fe5b60200260200101518583815181106108e257fe5b602002602001015160a001518684815181106108fa57fe5b602002602001015160800151611a60565b82828151811061091757fe5b6020026020010181815250505b60010161089b565b5092915050565b606061093f8385611994565b815160408051828152602080840282010190915281801561096a578160200160208202803883390190505b5091506000610977611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16146109b7576109b286611aa2565b6109ba565b60005b905060006109c6611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610a0657610a0186611aa2565b610a09565b60005b905060005b83811015610be8576001610a20611a1f565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415610ab7578651610a969085907f2640f62c00000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b6020026020010151611b34565b878481518110610aa257fe5b60200260200101819350828152505050610bd4565b610abf611a1f565b73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff161415610b28578651610a969084907f59e9486200000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b8651600090610b619085907f59e9486200000000000000000000000000000000000000000000000000000000908b9087908110610a8957fe5b925090508015610bb757610b96857f2640f62c0000000000000000000000000000000000000000000000000000000083611b34565b888581518110610ba257fe5b60200260200101819450828152505050610bd2565b6000878481518110610bc557fe5b6020026020010181815250505b505b80610bdf5750610be8565b50600101610a0e565b505050509392505050565b6060610bff8385611994565b8151604080518281526020808402820101909152818015610c2a578160200160208202803883390190505b50915060005b818110156105915760006060610c44611a07565b73ffffffffffffffffffffffffffffffffffffffff16620f4240600073ffffffffffffffffffffffffffffffffffffffff1663144a2752905060e01b898b8a8881518110610c8e57fe5b6020026020010151604051602401610ca893929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610d3191906125d0565b6000604051808303818686fa925050503d8060008114610d6d576040519150601f19603f3d011682016040523d82523d6000602084013e610d72565b606091505b509092509050600082156105665781806020019051610d949190810190612544565b905080868581518110610da357fe5b6020908102919091010152505050600101610c30565b604080518281526020808402820101909152606090828015610def57816020015b6060815260200190600190039081610dda5790505b50905060005b80831461092c576000606030868685818110610e0d57fe5b6020028201905080357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe136849003018112610e4757600080fd5b9091016020810191503567ffffffffffffffff811115610e6657600080fd5b36819003821315610e7657600080fd5b604051610e849291906125c0565b600060405180830381855afa9150503d8060008114610ebf576040519150601f19603f3d011682016040523d82523d6000602084013e610ec4565b606091505b509150915081610ed657805160208201fd5b80848481518110610ee357fe5b60209081029190910101525050600101610df5565b6060610f048385611994565b8151604080518281526020808402820101909152818015610f2f578160200160208202803883390190505b5091506000610f3c611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610f7c57610f7786611aa2565b610f7f565b60005b90506000610f8b611a1f565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610fcb57610fc686611aa2565b610fce565b60005b905060005b83811015610be8576001610fe5611a1f565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16141561106f57865161104e9085907f95b68fe700000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b87848151811061105a57fe5b6020026020010181935082815250505061118c565b611077611a1f565b73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614156110e057865161104e9084907fcd7724c300000000000000000000000000000000000000000000000000000000908a9086908110610a8957fe5b86516000906111199086907f95b68fe700000000000000000000000000000000000000000000000000000000908b9087908110610a8957fe5b92509050801561116f5761114e847fcd7724c30000000000000000000000000000000000000000000000000000000083611b34565b88858151811061115a57fe5b6020026020010181945082815250505061118a565b600087848151811061117d57fe5b6020026020010181815250505b505b806111975750610be8565b50600101610fd3565b606082516040519080825280602002602001820160405280156111cd578160200160208202803883390190505b50905060005b8351811461092c578281815181106111e757fe5b60200260200101515160001480611215575083818151811061120557fe5b6020026020010151608001516000145b80611237575083818151811061122757fe5b602002602001015160a001516000145b1561125b57600082828151811061124a57fe5b602002602001018181525050611460565b60006060611267611c7d565b73ffffffffffffffffffffffffffffffffffffffff166207a120611289611c7d565b5087517fe77286eb00000000000000000000000000000000000000000000000000000000908990879081106112ba57fe5b60200260200101518887815181106112ce57fe5b60200260200101516040516024016112e79291906127d1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161137091906125d0565b6000604051808303818686fa925050503d80600081146113ac576040519150601f19603f3d011682016040523d82523d6000602084013e6113b1565b606091505b5091509150816113dc5760008484815181106113c957fe5b6020026020010181815250505050611460565b6113e4611f5b565b600080838060200190516113fb91908101906124d7565b9194509250905060038351600681111561141157fe5b14158061141c575080155b1561144057600087878151811061142f57fe5b60200260200101818152505061145a565b8187878151811061144d57fe5b6020026020010181815250505b50505050505b6001016111d3565b60606000825190508060405190808252806020026020018201604052801561149a578160200160208202803883390190505b50915060006114aa878787611859565b905073ffffffffffffffffffffffffffffffffffffffff81166114cf57506116659050565b60005b8281101561166157600060608373ffffffffffffffffffffffffffffffffffffffff1662030d40600073ffffffffffffffffffffffffffffffffffffffff1663343fbcdd905060e01b8b8b8b888151811061152957fe5b602002602001015160405160240161154393929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516115cc91906125d0565b6000604051808303818686fa925050503d8060008114611608576040519150601f19603f3d011682016040523d82523d6000602084013e61160d565b606091505b50909250905060008215611636578180602001905161162f9190810190612544565b905061163e565b505050611661565b8087858151811061164b57fe5b60209081029190910101525050506001016114d2565b5050505b949350505050565b60606000825190508060405190808252806020026020018201604052801561169f578160200160208202803883390190505b50915060006116af878787611859565b905073ffffffffffffffffffffffffffffffffffffffff81166116d457506116659050565b60005b8281101561166157600060608373ffffffffffffffffffffffffffffffffffffffff1662030d40600073ffffffffffffffffffffffffffffffffffffffff166345060eb0905060e01b8b8b8b888151811061172e57fe5b602002602001015160405160240161174893929190612634565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516117d191906125d0565b6000604051808303818686fa925050503d806000811461180d576040519150601f19603f3d011682016040523d82523d6000602084013e611812565b606091505b5090925090506000821561163657818060200190516118349190810190612544565b90508087858151811061184357fe5b60209081029190910101525050506001016116d7565b6040516000906060907f153f59970000000000000000000000000000000000000000000000000000000090611894908690869060240161260d565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608673ffffffffffffffffffffffffffffffffffffffff168360405161191c91906125d0565b600060405180830381855afa9150503d8060008114611957576040519150601f19603f3d011682016040523d82523d6000602084013e61195c565b606091505b509150915081801561196f575080516020145b156119895761197f81600c611c95565b935050505061198d565b5050505b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611a03576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119fa90612774565b60405180910390fd5b5050565b73794e6e91555438afc3ccf1c5076a74f42133d08d90565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290565b6000611a4282611cda565b92915050565b73818e6fecd516ecc3849daf6845e3ec868087b75590565b600061166583611a96611a7a82600163ffffffff611dab16565b611a8a888763ffffffff611dca16565b9063ffffffff611dfb16565b9063ffffffff611e1716565b6000611aac611e41565b73ffffffffffffffffffffffffffffffffffffffff166306f2bf62836040518263ffffffff1660e01b8152600401611ae491906125ec565b60206040518083038186803b158015611afc57600080fd5b505afa158015611b10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611a429190810190612243565b60008073ffffffffffffffffffffffffffffffffffffffff8516611b5757611c75565b60608573ffffffffffffffffffffffffffffffffffffffff16620249f08686604051602401611b869190612925565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611c0f91906125d0565b6000604051808303818686fa925050503d8060008114611c4b576040519150601f19603f3d011682016040523d82523d6000602084013e611c50565b606091505b5090925090508115611c735780806020019051611c709190810190612544565b92505b505b935093915050565b7374134cf88b21383713e096a5ecf59e297dc7f54790565b60008160140183511015611cbb57611cbb611cb66004855185601401611e59565b611efe565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b600060129050600060608373ffffffffffffffffffffffffffffffffffffffff166040518060400160405280600481526020017f313ce56700000000000000000000000000000000000000000000000000000000815250604051611d3e91906125d0565b600060405180830381855afa9150503d8060008114611d79576040519150601f19603f3d011682016040523d82523d6000602084013e611d7e565b606091505b5091509150818015611d91575080516020145b15611da457611da1816000611f06565b92505b5050919050565b600082821115611dc457611dc4611cb660028585611f12565b50900390565b600082611dd957506000611a42565b82820282848281611de657fe5b041461198d5761198d611cb660018686611f12565b60008282018381101561198d5761198d611cb660008686611f12565b600081611e2d57611e2d611cb660038585611f12565b6000828481611e3857fe5b04949350505050565b73c0a47dfe034b400b47bdad5fecda2621de6c4d9590565b6060632800659560e01b848484604051602401611e7893929190612748565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290509392505050565b805160208201fd5b600061198d8383611f31565b606063e946c1bb60e01b848484604051602401611e7893929190612726565b60008160200183511015611f5257611f52611cb66005855185602001611e59565b50016020015190565b6040805160608101909152806000815260006020820181905260409091015290565b8035611a42816129a5565b600082601f830112611f98578081fd5b8135611fab611fa682612955565b61292e565b8181529150602080830190840160005b83811015611fe857611fd3876020843589010161205b565b83526020928301929190910190600101611fbb565b5050505092915050565b600082601f830112612002578081fd5b8135612010611fa682612955565b81815291506020808301908481018184028601820187101561203157600080fd5b60005b8481101561205057813584529282019290820190600101612034565b505050505092915050565b600082601f83011261206b578081fd5b813567ffffffffffffffff811115612081578182fd5b6120b260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161292e565b91508082528360208285010111156120c957600080fd5b8060208401602084013760009082016020015292915050565b8035600f81900b8114611a4257600080fd5b60006101c0808385031215612107578182fd5b6121108161292e565b91505061211d8383611f7d565b815261212c8360208401611f7d565b602082015261213e8360408401611f7d565b60408201526121508360608401611f7d565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff808211156121b257600080fd5b6121be8683870161205b565b838501526101609250828501359150808211156121da57600080fd5b6121e68683870161205b565b8385015261018092508285013591508082111561220257600080fd5b61220e8683870161205b565b838501526101a092508285013591508082111561222a57600080fd5b506122378582860161205b565b82840152505092915050565b600060208284031215612254578081fd5b815161198d816129a5565b600080600060608486031215612273578182fd5b833561227e816129a5565b9250602084013561228e816129a5565b9150604084013561229e816129a5565b809150509250925092565b600080600080608085870312156122be578081fd5b84356122c9816129a5565b935060208501356122d9816129a5565b925060408501356122e9816129a5565b9150606085013567ffffffffffffffff811115612304578182fd5b61231087828801611ff2565b91505092959194509250565b600080600060608486031215612330578283fd5b833561233b816129a5565b9250602084013561234b816129a5565b9150604084013567ffffffffffffffff811115612366578182fd5b61237286828701611ff2565b9150509250925092565b60008060008060808587031215612391578182fd5b843561239c816129a5565b93506123ab86602087016120e2565b92506122e986604087016120e2565b600080602083850312156123cc578182fd5b823567ffffffffffffffff808211156123e3578384fd5b81850186601f8201126123f4578485fd5b8035925081831115612404578485fd5b8660208085028301011115612417578485fd5b60200196919550909350505050565b60008060408385031215612438578182fd5b823567ffffffffffffffff8082111561244f578384fd5b81850186601f820112612460578485fd5b80359250612470611fa684612955565b83815260208082019190838101885b878110156124a8576124968c8484358901016120f4565b8552938201939082019060010161247f565b509197508801359450505050808211156124c0578283fd5b506124cd85828601611f88565b9150509250929050565b600080600083850360a08112156124ec578182fd5b60608112156124f9578182fd5b50612504606061292e565b845160078110612512578283fd5b81526020858101519082015260408086015190820152606085015160808601519194509250801515811461229e578182fd5b600060208284031215612555578081fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff169052565b6000815180845261258e816020860160208601612975565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000828483379101908152919050565b600082516125e2818460208701612975565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b6000602080830181845280855180835260408601915060408482028701019250838701855b828110156126d6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526126c4858351612576565b9450928501929085019060010161268a565b5092979650505050505050565b602080825282518282018190526000918401906040840190835b8181101561271b5783518352602093840193909201916001016126fd565b509095945050505050565b606081016004851061273457fe5b938152602081019290925260409091015290565b606081016008851061273457fe5b600f93840b81529190920b6020820152604081019190915260600190565b60208082526025908201527f455243323042726964676553616d706c65722f494e56414c49445f544f4b454e60408201527f5f50414952000000000000000000000000000000000000000000000000000000606082015260800190565b6000604082526127e560408301855161255c565b60208401516127f7606084018261255c565b50604084015161280a608084018261255c565b50606084015161281d60a084018261255c565b50608084015160c083015260a084015160e083015260c0840151610100818185015260e086015191506101208281860152818701519250610140915082828601528087015192505061016082818601528187015192506101c09150610180828187015261288e610200870185612576565b8289015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc092506101a08388830301818901526128cd8287612576565b838b015196508489820301868a01526128e68188612576565b955050808a0151955050505080858303016101e0860152506129088183612576565b848103602086015261291a8187612576565b979650505050505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561294d57600080fd5b604052919050565b600067ffffffffffffffff82111561296b578081fd5b5060209081020190565b60005b83811015612990578181015183820152602001612978565b8381111561299f576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146129c757600080fd5b5056fea365627a7a7231582034e7eab64809a5ab7420c524f487ac0ca03a80f2b355b2d12a392dde2df0522e6c6578706572696d656e74616cf564736f6c63430005100040" + } + } + }, + "compiler": { + "name": "solc", + "version": "soljson-v0.5.16+commit.9c3226ce.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "devdoc", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "istanbul" + } + }, + "chains": {} +} diff --git a/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json b/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json index bcf5c1fd6a..a851bba79c 100644 --- a/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json +++ b/packages/contract-artifacts/artifacts/IERC20BridgeSampler.json @@ -12,6 +12,19 @@ "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "registryAddress", "type": "address" }, + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" } + ], + "name": "getLiquidityProviderFromRegistry", + "outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -93,6 +106,20 @@ "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "registryAddress", "type": "address" }, + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleBuysFromLiquidityProviderRegistry", + "outputs": [{ "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -146,6 +173,20 @@ "stateMutability": "view", "type": "function" }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "registryAddress", "type": "address" }, + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256[]", "name": "takerTokenAmounts", "type": "uint256[]" } + ], + "name": "sampleSellsFromLiquidityProviderRegistry", + "outputs": [{ "internalType": "uint256[]", "name": "makerTokenAmounts", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, { "constant": true, "inputs": [ @@ -167,6 +208,14 @@ "params": { "callDatas": "ABI-encoded call data for each function call." }, "return": "callResults ABI-encoded results data for each call." }, + "getLiquidityProviderFromRegistry(address,address,address)": { + "details": "Returns the address of a liquidity provider for the given market (takerToken, makerToken), from a registry of liquidity providers. Returns address(0) if no such provider exists in the registry.", + "params": { + "makerToken": "Maker asset managed by liquidity provider.", + "takerToken": "Taker asset managed by liquidity provider." + }, + "return": "providerAddress Address of the liquidity provider." + }, "getOrderFillableMakerAssetAmounts((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[])": { "details": "Queries the fillable maker asset amounts of native orders.", "params": { @@ -192,6 +241,16 @@ }, "return": "takerTokenAmounts Taker amounts sold at each maker token amount." }, + "sampleBuysFromLiquidityProviderRegistry(address,address,address,uint256[])": { + "details": "Sample buy quotes from an arbitrary on-chain liquidity provider.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "makerTokenAmounts": "Maker token buy amount for each sample.", + "registryAddress": "Address of the liquidity provider registry contract.", + "takerToken": "Address of the taker token (what to sell)." + }, + "return": "takerTokenAmounts Taker amounts sold at each maker token amount." + }, "sampleBuysFromUniswap(address,address,uint256[])": { "details": "Sample buy quotes from Uniswap.", "params": { @@ -229,6 +288,16 @@ }, "return": "makerTokenAmounts Maker amounts bought at each taker token amount." }, + "sampleSellsFromLiquidityProviderRegistry(address,address,address,uint256[])": { + "details": "Sample sell quotes from an arbitrary on-chain liquidity provider.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "registryAddress": "Address of the liquidity provider registry contract.", + "takerToken": "Address of the taker token (what to sell).", + "takerTokenAmounts": "Taker token sell amount for each sample." + }, + "return": "makerTokenAmounts Maker amounts bought at each taker token amount." + }, "sampleSellsFromUniswap(address,address,uint256[])": { "details": "Sample sell quotes from Uniswap.", "params": { diff --git a/packages/contract-artifacts/artifacts/ILiquidityProvider.json b/packages/contract-artifacts/artifacts/ILiquidityProvider.json new file mode 100644 index 0000000000..ce14770f26 --- /dev/null +++ b/packages/contract-artifacts/artifacts/ILiquidityProvider.json @@ -0,0 +1,108 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "ILiquidityProvider", + "compilerOutput": { + "abi": [ + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "tokenAddress", "type": "address" }, + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" }, + { "internalType": "bytes", "name": "bridgeData", "type": "bytes" } + ], + "name": "bridgeTransferFrom", + "outputs": [{ "internalType": "bytes4", "name": "success", "type": "bytes4" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256", "name": "buyAmount", "type": "uint256" } + ], + "name": "getBuyQuote", + "outputs": [{ "internalType": "uint256", "name": "takerTokenAmount", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" } + ], + "name": "getSellQuote", + "outputs": [{ "internalType": "uint256", "name": "makerTokenAmount", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "methods": { + "bridgeTransferFrom(address,address,address,uint256,bytes)": { + "details": "Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.", + "params": { + "amount": "Amount of asset to transfer.", + "bridgeData": "Arbitrary asset data needed by the bridge contract.", + "from": "Address to transfer asset from.", + "to": "Address to transfer asset to.", + "tokenAddress": "The address of the ERC20 token to transfer." + }, + "return": "success The magic bytes `0xdc1600f3` if successful." + }, + "getBuyQuote(address,address,uint256)": { + "details": "Quotes the amount of `takerToken` that would need to be sold in order to obtain `buyAmount` of `makerToken`.", + "params": { + "buyAmount": "Amount of `makerToken` to buy.", + "makerToken": "Address of the maker token (what to buy).", + "takerToken": "Address of the taker token (what to sell)." + }, + "return": "takerTokenAmount Amount of `takerToken` that would need to be sold." + }, + "getSellQuote(address,address,uint256)": { + "details": "Quotes the amount of `makerToken` that would be obtained by selling `sellAmount` of `takerToken`.", + "params": { + "makerToken": "Address of the maker token (what to buy).", + "sellAmount": "Amount of `takerToken` to sell.", + "takerToken": "Address of the taker token (what to sell)." + }, + "return": "makerTokenAmount Amount of `makerToken` that would be obtained." + } + } + }, + "evm": { "bytecode": { "object": "0x" }, "deployedBytecode": { "object": "0x" } } + }, + "compiler": { + "name": "solc", + "version": "soljson-v0.5.16+commit.9c3226ce.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "devdoc", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "istanbul" + } + }, + "chains": {} +} diff --git a/packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json b/packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json new file mode 100644 index 0000000000..6264ca0b0d --- /dev/null +++ b/packages/contract-artifacts/artifacts/ILiquidityProviderRegistry.json @@ -0,0 +1,58 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "ILiquidityProviderRegistry", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "takerToken", "type": "address" }, + { "internalType": "address", "name": "makerToken", "type": "address" } + ], + "name": "getLiquidityProviderForMarket", + "outputs": [{ "internalType": "address", "name": "providerAddress", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "methods": { + "getLiquidityProviderForMarket(address,address)": { + "details": "Returns the address of a liquidity provider for the given market (takerToken, makerToken), reverting if the pool does not exist.", + "params": { + "makerToken": "Maker asset managed by liquidity provider.", + "takerToken": "Taker asset managed by liquidity provider." + }, + "return": "Address of the liquidity provider." + } + } + }, + "evm": { "bytecode": { "object": "0x" }, "deployedBytecode": { "object": "0x" } } + }, + "compiler": { + "name": "solc", + "version": "soljson-v0.5.16+commit.9c3226ce.js", + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000, + "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "devdoc", + "evm.bytecode.object", + "evm.bytecode.sourceMap", + "evm.deployedBytecode.object", + "evm.deployedBytecode.sourceMap" + ] + } + }, + "evmVersion": "istanbul" + } + }, + "chains": {} +} diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index da155a0289..866b679f6e 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -31,7 +31,7 @@ "wrappers:generate": "abi-gen --abis ${npm_package_config_abis} --output src/generated-wrappers --backend ethers" }, "config": { - "abis": "../contract-artifacts/artifacts/@(DevUtils|ERC20Token|ERC721Token|Exchange|Forwarder|IAssetData|LibTransactionDecoder|WETH9|Coordinator|Staking|StakingProxy|IERC20BridgeSampler|GodsUnchainedValidator|Broker|MaximumGasPrice).json" + "abis": "../contract-artifacts/artifacts/@(DevUtils|ERC20Token|ERC721Token|Exchange|Forwarder|IAssetData|LibTransactionDecoder|WETH9|Coordinator|Staking|StakingProxy|IERC20BridgeSampler|ERC20BridgeSampler|GodsUnchainedValidator|Broker|ILiquidityProvider|ILiquidityProviderRegistry|MaximumGasPrice).json" }, "repository": { "type": "git", diff --git a/packages/contract-wrappers/src/generated-wrappers/erc20_bridge_sampler.ts b/packages/contract-wrappers/src/generated-wrappers/erc20_bridge_sampler.ts new file mode 100644 index 0000000000..c7ae4fee03 --- /dev/null +++ b/packages/contract-wrappers/src/generated-wrappers/erc20_bridge_sampler.ts @@ -0,0 +1,1185 @@ +// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming +// tslint:disable:whitespace no-unbound-method no-trailing-whitespace +// tslint:disable:no-unused-variable +import { + AwaitTransactionSuccessOpts, + ContractFunctionObj, + ContractTxFunctionObj, + SendTransactionOpts, + BaseContract, + PromiseWithTransactionHash, + methodAbiToFunctionSignature, + linkLibrariesInBytecode, +} from '@0x/base-contract'; +import { schemas } from '@0x/json-schemas'; +import { + BlockParam, + BlockParamLiteral, + BlockRange, + CallData, + ContractAbi, + ContractArtifact, + DecodedLogArgs, + MethodAbi, + TransactionReceiptWithDecodedLogs, + TxData, + TxDataPayable, + SupportedProvider, +} from 'ethereum-types'; +import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; +import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { assert } from '@0x/assert'; +import * as ethers from 'ethers'; +// tslint:enable:no-unused-variable + +/* istanbul ignore next */ +// tslint:disable:array-type +// tslint:disable:no-parameter-reassignment +// tslint:disable-next-line:class-name +export class ERC20BridgeSamplerContract extends BaseContract { + /** + * @ignore + */ + public static deployedBytecode: string | undefined; + public static contractName = 'ERC20BridgeSampler'; + private readonly _methodABIIndex: { [name: string]: number } = {}; + public static async deployFrom0xArtifactAsync( + artifact: ContractArtifact | SimpleContractArtifact, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const bytecode = artifact.compilerOutput.evm.bytecode.object; + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ERC20BridgeSamplerContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + const libraryAddresses = await ERC20BridgeSamplerContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ERC20BridgeSamplerContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + + public static async deployAsync( + bytecode: string, + abi: ContractAbi, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, + ): Promise { + assert.isHexString('bytecode', bytecode); + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const constructorAbi = BaseContract._lookupConstructorAbi(abi); + [] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString); + const iface = new ethers.utils.Interface(abi); + const deployInfo = iface.deployFunction; + const txData = deployInfo.encode(bytecode, []); + const web3Wrapper = new Web3Wrapper(provider); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: txData, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`ERC20BridgeSampler successfully deployed at ${txReceipt.contractAddress}`); + const contractInstance = new ERC20BridgeSamplerContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); + contractInstance.constructorArgs = []; + return contractInstance; + } + + /** + * @returns The contract ABI + */ + public static ABI(): ContractAbi { + const abi = [ + { + constant: true, + inputs: [ + { + name: 'callDatas', + type: 'bytes[]', + }, + ], + name: 'batchCall', + outputs: [ + { + name: 'callResults', + type: 'bytes[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'registryAddress', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + ], + name: 'getLiquidityProviderFromRegistry', + outputs: [ + { + name: 'providerAddress', + type: 'address', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'orders', + type: 'tuple[]', + components: [ + { + name: 'makerAddress', + type: 'address', + }, + { + name: 'takerAddress', + type: 'address', + }, + { + name: 'feeRecipientAddress', + type: 'address', + }, + { + name: 'senderAddress', + type: 'address', + }, + { + name: 'makerAssetAmount', + type: 'uint256', + }, + { + name: 'takerAssetAmount', + type: 'uint256', + }, + { + name: 'makerFee', + type: 'uint256', + }, + { + name: 'takerFee', + type: 'uint256', + }, + { + name: 'expirationTimeSeconds', + type: 'uint256', + }, + { + name: 'salt', + type: 'uint256', + }, + { + name: 'makerAssetData', + type: 'bytes', + }, + { + name: 'takerAssetData', + type: 'bytes', + }, + { + name: 'makerFeeAssetData', + type: 'bytes', + }, + { + name: 'takerFeeAssetData', + type: 'bytes', + }, + ], + }, + { + name: 'orderSignatures', + type: 'bytes[]', + }, + ], + name: 'getOrderFillableMakerAssetAmounts', + outputs: [ + { + name: 'orderFillableMakerAssetAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'orders', + type: 'tuple[]', + components: [ + { + name: 'makerAddress', + type: 'address', + }, + { + name: 'takerAddress', + type: 'address', + }, + { + name: 'feeRecipientAddress', + type: 'address', + }, + { + name: 'senderAddress', + type: 'address', + }, + { + name: 'makerAssetAmount', + type: 'uint256', + }, + { + name: 'takerAssetAmount', + type: 'uint256', + }, + { + name: 'makerFee', + type: 'uint256', + }, + { + name: 'takerFee', + type: 'uint256', + }, + { + name: 'expirationTimeSeconds', + type: 'uint256', + }, + { + name: 'salt', + type: 'uint256', + }, + { + name: 'makerAssetData', + type: 'bytes', + }, + { + name: 'takerAssetData', + type: 'bytes', + }, + { + name: 'makerFeeAssetData', + type: 'bytes', + }, + { + name: 'takerFeeAssetData', + type: 'bytes', + }, + ], + }, + { + name: 'orderSignatures', + type: 'bytes[]', + }, + ], + name: 'getOrderFillableTakerAssetAmounts', + outputs: [ + { + name: 'orderFillableTakerAssetAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleBuysFromEth2Dai', + outputs: [ + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'registryAddress', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleBuysFromLiquidityProviderRegistry', + outputs: [ + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleBuysFromUniswap', + outputs: [ + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'curveAddress', + type: 'address', + }, + { + name: 'fromTokenIdx', + type: 'int128', + }, + { + name: 'toTokenIdx', + type: 'int128', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromCurve', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromEth2Dai', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromKyberNetwork', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'registryAddress', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromLiquidityProviderRegistry', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromUniswap', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + ] as ContractAbi; + return abi; + } + + protected static async _deployLibrariesAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + web3Wrapper: Web3Wrapper, + txDefaults: Partial, + libraryAddresses: { [libraryName: string]: string } = {}, + ): Promise<{ [libraryName: string]: string }> { + const links = artifact.compilerOutput.evm.bytecode.linkReferences; + // Go through all linked libraries, recursively deploying them if necessary. + for (const link of Object.values(links)) { + for (const libraryName of Object.keys(link)) { + if (!libraryAddresses[libraryName]) { + // Library not yet deployed. + const libraryArtifact = libraryArtifacts[libraryName]; + if (!libraryArtifact) { + throw new Error(`Missing artifact for linked library "${libraryName}"`); + } + // Deploy any dependent libraries used by this library. + await ERC20BridgeSamplerContract._deployLibrariesAsync( + libraryArtifact, + libraryArtifacts, + web3Wrapper, + txDefaults, + libraryAddresses, + ); + // Deploy this library. + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: linkedLibraryBytecode, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); + libraryAddresses[libraryArtifact.contractName] = contractAddress as string; + } + } + } + return libraryAddresses; + } + + public getFunctionSignature(methodName: string): string { + const index = this._methodABIIndex[methodName]; + const methodAbi = ERC20BridgeSamplerContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion + const functionSignature = methodAbiToFunctionSignature(methodAbi); + return functionSignature; + } + + public getABIDecodedTransactionData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ERC20BridgeSamplerContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + } + + public getABIDecodedReturnData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ERC20BridgeSamplerContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); + return abiDecodedCallData; + } + + public getSelector(methodName: string): string { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ERC20BridgeSamplerContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + return abiEncoder.getSelector(); + } + + /** + * Call multiple public functions on this contract in a single transaction. + * @param callDatas ABI-encoded call data for each function call. + * @returns callResults ABI-encoded results data for each call. + */ + public batchCall(callDatas: string[]): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isArray('callDatas', callDatas); + const functionSignature = 'batchCall(bytes[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [callDatas]); + }, + }; + } + /** + * Returns the address of a liquidity provider for the given market + * (takerToken, makerToken), from a registry of liquidity providers. + * Returns address(0) if no such provider exists in the registry. + * @param takerToken Taker asset managed by liquidity provider. + * @param makerToken Maker asset managed by liquidity provider. + * @returns providerAddress Address of the liquidity provider. + */ + public getLiquidityProviderFromRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('registryAddress', registryAddress); + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + const functionSignature = 'getLiquidityProviderFromRegistry(address,address,address)'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + registryAddress.toLowerCase(), + takerToken.toLowerCase(), + makerToken.toLowerCase(), + ]); + }, + }; + } + /** + * Queries the fillable taker asset amounts of native orders. + * Effectively ignores orders that have empty signatures or + * @param orders Native orders to query. + * @param orderSignatures Signatures for each respective order in `orders`. + * @returns orderFillableMakerAssetAmounts How much maker asset can be filled by each order in `orders`. + */ + public getOrderFillableMakerAssetAmounts( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + makerFeeAssetData: string; + takerFeeAssetData: string; + }>, + orderSignatures: string[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isArray('orders', orders); + assert.isArray('orderSignatures', orderSignatures); + const functionSignature = + 'getOrderFillableMakerAssetAmounts((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [orders, orderSignatures]); + }, + }; + } + /** + * Queries the fillable taker asset amounts of native orders. + * Effectively ignores orders that have empty signatures or + * maker/taker asset amounts (returning 0). + * @param orders Native orders to query. + * @param orderSignatures Signatures for each respective order in `orders`. + * @returns orderFillableTakerAssetAmounts How much taker asset can be filled by each order in `orders`. + */ + public getOrderFillableTakerAssetAmounts( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + makerFeeAssetData: string; + takerFeeAssetData: string; + }>, + orderSignatures: string[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isArray('orders', orders); + assert.isArray('orderSignatures', orderSignatures); + const functionSignature = + 'getOrderFillableTakerAssetAmounts((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes,bytes,bytes)[],bytes[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [orders, orderSignatures]); + }, + }; + } + /** + * Sample buy quotes from Eth2Dai/Oasis. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @returns takerTokenAmounts Taker amounts sold at each maker token amount. + */ + public sampleBuysFromEth2Dai( + takerToken: string, + makerToken: string, + makerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('makerTokenAmounts', makerTokenAmounts); + const functionSignature = 'sampleBuysFromEth2Dai(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + makerTokenAmounts, + ]); + }, + }; + } + /** + * Sample buy quotes from an arbitrary on-chain liquidity provider. + * @param registryAddress Address of the liquidity provider registry contract. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param makerTokenAmounts Maker token buy amount for each sample. + * @returns takerTokenAmounts Taker amounts sold at each maker token amount. + */ + public sampleBuysFromLiquidityProviderRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + makerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('registryAddress', registryAddress); + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('makerTokenAmounts', makerTokenAmounts); + const functionSignature = 'sampleBuysFromLiquidityProviderRegistry(address,address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + registryAddress.toLowerCase(), + takerToken.toLowerCase(), + makerToken.toLowerCase(), + makerTokenAmounts, + ]); + }, + }; + } + /** + * Sample buy quotes from Uniswap. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param makerTokenAmounts Maker token sell amount for each sample. + * @returns takerTokenAmounts Taker amounts sold at each maker token amount. + */ + public sampleBuysFromUniswap( + takerToken: string, + makerToken: string, + makerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('makerTokenAmounts', makerTokenAmounts); + const functionSignature = 'sampleBuysFromUniswap(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + makerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Curve. + * @param curveAddress Address of the Curve contract. + * @param fromTokenIdx Index of the taker token (what to sell). + * @param toTokenIdx Index of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromCurve( + curveAddress: string, + fromTokenIdx: BigNumber, + toTokenIdx: BigNumber, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('curveAddress', curveAddress); + assert.isBigNumber('fromTokenIdx', fromTokenIdx); + assert.isBigNumber('toTokenIdx', toTokenIdx); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromCurve(address,int128,int128,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + curveAddress.toLowerCase(), + fromTokenIdx, + toTokenIdx, + takerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Eth2Dai/Oasis. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromEth2Dai( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromEth2Dai(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Kyber. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromKyberNetwork( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromKyberNetwork(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from an arbitrary on-chain liquidity provider. + * @param registryAddress Address of the liquidity provider registry contract. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromLiquidityProviderRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('registryAddress', registryAddress); + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromLiquidityProviderRegistry(address,address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + registryAddress.toLowerCase(), + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } + /** + * Sample sell quotes from Uniswap. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromUniswap( + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as ERC20BridgeSamplerContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromUniswap(address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } + + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + deployedBytecode: string | undefined = ERC20BridgeSamplerContract.deployedBytecode, + ) { + super( + 'ERC20BridgeSampler', + ERC20BridgeSamplerContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + deployedBytecode, + ); + classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + ERC20BridgeSamplerContract.ABI().forEach((item, index) => { + if (item.type === 'function') { + const methodAbi = item as MethodAbi; + this._methodABIIndex[methodAbi.name] = index; + } + }); + } +} + +// tslint:disable:max-file-line-count +// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align +// tslint:enable:trailing-comma whitespace no-trailing-whitespace diff --git a/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts b/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts index 2b68743e82..612c63263b 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_erc20_bridge_sampler.ts @@ -180,6 +180,33 @@ export class IERC20BridgeSamplerContract extends BaseContract { stateMutability: 'view', type: 'function', }, + { + constant: true, + inputs: [ + { + name: 'registryAddress', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + ], + name: 'getLiquidityProviderFromRegistry', + outputs: [ + { + name: 'providerAddress', + type: 'address', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, { constant: true, inputs: [ @@ -369,6 +396,37 @@ export class IERC20BridgeSamplerContract extends BaseContract { stateMutability: 'view', type: 'function', }, + { + constant: true, + inputs: [ + { + name: 'registryAddress', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleBuysFromLiquidityProviderRegistry', + outputs: [ + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, { constant: true, inputs: [ @@ -481,6 +539,37 @@ export class IERC20BridgeSamplerContract extends BaseContract { stateMutability: 'view', type: 'function', }, + { + constant: true, + inputs: [ + { + name: 'registryAddress', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerTokenAmounts', + type: 'uint256[]', + }, + ], + name: 'sampleSellsFromLiquidityProviderRegistry', + outputs: [ + { + name: 'makerTokenAmounts', + type: 'uint256[]', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, { constant: true, inputs: [ @@ -613,6 +702,45 @@ export class IERC20BridgeSamplerContract extends BaseContract { }, }; } + /** + * Returns the address of a liquidity provider for the given market + * (takerToken, makerToken), from a registry of liquidity providers. + * Returns address(0) if no such provider exists in the registry. + * @param takerToken Taker asset managed by liquidity provider. + * @param makerToken Maker asset managed by liquidity provider. + * @returns providerAddress Address of the liquidity provider. + */ + public getLiquidityProviderFromRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + ): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isString('registryAddress', registryAddress); + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + const functionSignature = 'getLiquidityProviderFromRegistry(address,address,address)'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + registryAddress.toLowerCase(), + takerToken.toLowerCase(), + makerToken.toLowerCase(), + ]); + }, + }; + } /** * Queries the fillable maker asset amounts of native orders. * @param orders Native orders to query. @@ -744,6 +872,48 @@ export class IERC20BridgeSamplerContract extends BaseContract { }, }; } + /** + * Sample buy quotes from an arbitrary on-chain liquidity provider. + * @param registryAddress Address of the liquidity provider registry contract. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param makerTokenAmounts Maker token buy amount for each sample. + * @returns takerTokenAmounts Taker amounts sold at each maker token amount. + */ + public sampleBuysFromLiquidityProviderRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + makerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isString('registryAddress', registryAddress); + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('makerTokenAmounts', makerTokenAmounts); + const functionSignature = 'sampleBuysFromLiquidityProviderRegistry(address,address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + registryAddress.toLowerCase(), + takerToken.toLowerCase(), + makerToken.toLowerCase(), + makerTokenAmounts, + ]); + }, + }; + } /** * Sample buy quotes from Uniswap. * @param takerToken Address of the taker token (what to sell). @@ -900,6 +1070,48 @@ export class IERC20BridgeSamplerContract extends BaseContract { }, }; } + /** + * Sample sell quotes from an arbitrary on-chain liquidity provider. + * @param registryAddress Address of the liquidity provider registry contract. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param takerTokenAmounts Taker token sell amount for each sample. + * @returns makerTokenAmounts Maker amounts bought at each taker token amount. + */ + public sampleSellsFromLiquidityProviderRegistry( + registryAddress: string, + takerToken: string, + makerToken: string, + takerTokenAmounts: BigNumber[], + ): ContractFunctionObj { + const self = (this as any) as IERC20BridgeSamplerContract; + assert.isString('registryAddress', registryAddress); + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isArray('takerTokenAmounts', takerTokenAmounts); + const functionSignature = 'sampleSellsFromLiquidityProviderRegistry(address,address,address,uint256[])'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + registryAddress.toLowerCase(), + takerToken.toLowerCase(), + makerToken.toLowerCase(), + takerTokenAmounts, + ]); + }, + }; + } /** * Sample sell quotes from Uniswap. * @param takerToken Address of the taker token (what to sell). diff --git a/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider.ts b/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider.ts new file mode 100644 index 0000000000..5182ba1eea --- /dev/null +++ b/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider.ts @@ -0,0 +1,503 @@ +// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming +// tslint:disable:whitespace no-unbound-method no-trailing-whitespace +// tslint:disable:no-unused-variable +import { + AwaitTransactionSuccessOpts, + ContractFunctionObj, + ContractTxFunctionObj, + SendTransactionOpts, + BaseContract, + PromiseWithTransactionHash, + methodAbiToFunctionSignature, + linkLibrariesInBytecode, +} from '@0x/base-contract'; +import { schemas } from '@0x/json-schemas'; +import { + BlockParam, + BlockParamLiteral, + BlockRange, + CallData, + ContractAbi, + ContractArtifact, + DecodedLogArgs, + MethodAbi, + TransactionReceiptWithDecodedLogs, + TxData, + TxDataPayable, + SupportedProvider, +} from 'ethereum-types'; +import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; +import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { assert } from '@0x/assert'; +import * as ethers from 'ethers'; +// tslint:enable:no-unused-variable + +/* istanbul ignore next */ +// tslint:disable:array-type +// tslint:disable:no-parameter-reassignment +// tslint:disable-next-line:class-name +export class ILiquidityProviderContract extends BaseContract { + /** + * @ignore + */ + public static deployedBytecode: string | undefined; + public static contractName = 'ILiquidityProvider'; + private readonly _methodABIIndex: { [name: string]: number } = {}; + public static async deployFrom0xArtifactAsync( + artifact: ContractArtifact | SimpleContractArtifact, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const bytecode = artifact.compilerOutput.evm.bytecode.object; + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ILiquidityProviderContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + const libraryAddresses = await ILiquidityProviderContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ILiquidityProviderContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + + public static async deployAsync( + bytecode: string, + abi: ContractAbi, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, + ): Promise { + assert.isHexString('bytecode', bytecode); + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const constructorAbi = BaseContract._lookupConstructorAbi(abi); + [] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString); + const iface = new ethers.utils.Interface(abi); + const deployInfo = iface.deployFunction; + const txData = deployInfo.encode(bytecode, []); + const web3Wrapper = new Web3Wrapper(provider); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: txData, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`ILiquidityProvider successfully deployed at ${txReceipt.contractAddress}`); + const contractInstance = new ILiquidityProviderContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); + contractInstance.constructorArgs = []; + return contractInstance; + } + + /** + * @returns The contract ABI + */ + public static ABI(): ContractAbi { + const abi = [ + { + constant: false, + inputs: [ + { + name: 'tokenAddress', + type: 'address', + }, + { + name: 'from', + type: 'address', + }, + { + name: 'to', + type: 'address', + }, + { + name: 'amount', + type: 'uint256', + }, + { + name: 'bridgeData', + type: 'bytes', + }, + ], + name: 'bridgeTransferFrom', + outputs: [ + { + name: 'success', + type: 'bytes4', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'buyAmount', + type: 'uint256', + }, + ], + name: 'getBuyQuote', + outputs: [ + { + name: 'takerTokenAmount', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + { + name: 'sellAmount', + type: 'uint256', + }, + ], + name: 'getSellQuote', + outputs: [ + { + name: 'makerTokenAmount', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + ] as ContractAbi; + return abi; + } + + protected static async _deployLibrariesAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + web3Wrapper: Web3Wrapper, + txDefaults: Partial, + libraryAddresses: { [libraryName: string]: string } = {}, + ): Promise<{ [libraryName: string]: string }> { + const links = artifact.compilerOutput.evm.bytecode.linkReferences; + // Go through all linked libraries, recursively deploying them if necessary. + for (const link of Object.values(links)) { + for (const libraryName of Object.keys(link)) { + if (!libraryAddresses[libraryName]) { + // Library not yet deployed. + const libraryArtifact = libraryArtifacts[libraryName]; + if (!libraryArtifact) { + throw new Error(`Missing artifact for linked library "${libraryName}"`); + } + // Deploy any dependent libraries used by this library. + await ILiquidityProviderContract._deployLibrariesAsync( + libraryArtifact, + libraryArtifacts, + web3Wrapper, + txDefaults, + libraryAddresses, + ); + // Deploy this library. + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: linkedLibraryBytecode, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); + libraryAddresses[libraryArtifact.contractName] = contractAddress as string; + } + } + } + return libraryAddresses; + } + + public getFunctionSignature(methodName: string): string { + const index = this._methodABIIndex[methodName]; + const methodAbi = ILiquidityProviderContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion + const functionSignature = methodAbiToFunctionSignature(methodAbi); + return functionSignature; + } + + public getABIDecodedTransactionData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ILiquidityProviderContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + } + + public getABIDecodedReturnData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ILiquidityProviderContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); + return abiDecodedCallData; + } + + public getSelector(methodName: string): string { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ILiquidityProviderContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + return abiEncoder.getSelector(); + } + + /** + * Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`. + * @param tokenAddress The address of the ERC20 token to transfer. + * @param from Address to transfer asset from. + * @param to Address to transfer asset to. + * @param amount Amount of asset to transfer. + * @param bridgeData Arbitrary asset data needed by the bridge contract. + * @returns success The magic bytes `0xdc1600f3` if successful. + */ + public bridgeTransferFrom( + tokenAddress: string, + from: string, + to: string, + amount: BigNumber, + bridgeData: string, + ): ContractTxFunctionObj { + const self = (this as any) as ILiquidityProviderContract; + assert.isString('tokenAddress', tokenAddress); + assert.isString('from', from); + assert.isString('to', to); + assert.isBigNumber('amount', amount); + assert.isString('bridgeData', bridgeData); + const functionSignature = 'bridgeTransferFrom(address,address,address,uint256,bytes)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { ...txData, data: this.getABIEncodedTransactionData() }, + this.estimateGasAsync.bind(this), + ); + if (opts.shouldValidate !== false) { + await this.callAsync(txDataWithDefaults); + } + return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + }, + awaitTransactionSuccessAsync( + txData?: Partial, + opts: AwaitTransactionSuccessOpts = { shouldValidate: true }, + ): PromiseWithTransactionHash { + return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts); + }, + async estimateGasAsync(txData?: Partial | undefined): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + ...txData, + data: this.getABIEncodedTransactionData(), + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + tokenAddress.toLowerCase(), + from.toLowerCase(), + to.toLowerCase(), + amount, + bridgeData, + ]); + }, + }; + } + /** + * Quotes the amount of `takerToken` that would need to be sold in + * order to obtain `buyAmount` of `makerToken`. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param buyAmount Amount of `makerToken` to buy. + * @returns takerTokenAmount Amount of `takerToken` that would need to be sold. + */ + public getBuyQuote(takerToken: string, makerToken: string, buyAmount: BigNumber): ContractFunctionObj { + const self = (this as any) as ILiquidityProviderContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isBigNumber('buyAmount', buyAmount); + const functionSignature = 'getBuyQuote(address,address,uint256)'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + buyAmount, + ]); + }, + }; + } + /** + * Quotes the amount of `makerToken` that would be obtained by + * selling `sellAmount` of `takerToken`. + * @param takerToken Address of the taker token (what to sell). + * @param makerToken Address of the maker token (what to buy). + * @param sellAmount Amount of `takerToken` to sell. + * @returns makerTokenAmount Amount of `makerToken` that would be obtained. + */ + public getSellQuote(takerToken: string, makerToken: string, sellAmount: BigNumber): ContractFunctionObj { + const self = (this as any) as ILiquidityProviderContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + assert.isBigNumber('sellAmount', sellAmount); + const functionSignature = 'getSellQuote(address,address,uint256)'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + sellAmount, + ]); + }, + }; + } + + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + deployedBytecode: string | undefined = ILiquidityProviderContract.deployedBytecode, + ) { + super( + 'ILiquidityProvider', + ILiquidityProviderContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + deployedBytecode, + ); + classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + ILiquidityProviderContract.ABI().forEach((item, index) => { + if (item.type === 'function') { + const methodAbi = item as MethodAbi; + this._methodABIIndex[methodAbi.name] = index; + } + }); + } +} + +// tslint:disable:max-file-line-count +// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align +// tslint:enable:trailing-comma whitespace no-trailing-whitespace diff --git a/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts b/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts new file mode 100644 index 0000000000..632fe6f41a --- /dev/null +++ b/packages/contract-wrappers/src/generated-wrappers/i_liquidity_provider_registry.ts @@ -0,0 +1,327 @@ +// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming +// tslint:disable:whitespace no-unbound-method no-trailing-whitespace +// tslint:disable:no-unused-variable +import { + AwaitTransactionSuccessOpts, + ContractFunctionObj, + ContractTxFunctionObj, + SendTransactionOpts, + BaseContract, + PromiseWithTransactionHash, + methodAbiToFunctionSignature, + linkLibrariesInBytecode, +} from '@0x/base-contract'; +import { schemas } from '@0x/json-schemas'; +import { + BlockParam, + BlockParamLiteral, + BlockRange, + CallData, + ContractAbi, + ContractArtifact, + DecodedLogArgs, + MethodAbi, + TransactionReceiptWithDecodedLogs, + TxData, + TxDataPayable, + SupportedProvider, +} from 'ethereum-types'; +import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils'; +import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { assert } from '@0x/assert'; +import * as ethers from 'ethers'; +// tslint:enable:no-unused-variable + +/* istanbul ignore next */ +// tslint:disable:array-type +// tslint:disable:no-parameter-reassignment +// tslint:disable-next-line:class-name +export class ILiquidityProviderRegistryContract extends BaseContract { + /** + * @ignore + */ + public static deployedBytecode: string | undefined; + public static contractName = 'ILiquidityProviderRegistry'; + private readonly _methodABIIndex: { [name: string]: number } = {}; + public static async deployFrom0xArtifactAsync( + artifact: ContractArtifact | SimpleContractArtifact, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const bytecode = artifact.compilerOutput.evm.bytecode.object; + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ILiquidityProviderRegistryContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + + public static async deployWithLibrariesFrom0xArtifactAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, + ): Promise { + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (artifact.compilerOutput === undefined) { + throw new Error('Compiler output not found in the artifact file'); + } + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + const libraryAddresses = await ILiquidityProviderRegistryContract._deployLibrariesAsync( + artifact, + libraryArtifacts, + new Web3Wrapper(provider), + txDefaults, + ); + const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses); + return ILiquidityProviderRegistryContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); + } + + public static async deployAsync( + bytecode: string, + abi: ContractAbi, + supportedProvider: SupportedProvider, + txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, + ): Promise { + assert.isHexString('bytecode', bytecode); + assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + const provider = providerUtils.standardizeOrThrow(supportedProvider); + const constructorAbi = BaseContract._lookupConstructorAbi(abi); + [] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString); + const iface = new ethers.utils.Interface(abi); + const deployInfo = iface.deployFunction; + const txData = deployInfo.encode(bytecode, []); + const web3Wrapper = new Web3Wrapper(provider); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: txData, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`ILiquidityProviderRegistry successfully deployed at ${txReceipt.contractAddress}`); + const contractInstance = new ILiquidityProviderRegistryContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); + contractInstance.constructorArgs = []; + return contractInstance; + } + + /** + * @returns The contract ABI + */ + public static ABI(): ContractAbi { + const abi = [ + { + constant: true, + inputs: [ + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerToken', + type: 'address', + }, + ], + name: 'getLiquidityProviderForMarket', + outputs: [ + { + name: 'providerAddress', + type: 'address', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, + ] as ContractAbi; + return abi; + } + + protected static async _deployLibrariesAsync( + artifact: ContractArtifact, + libraryArtifacts: { [libraryName: string]: ContractArtifact }, + web3Wrapper: Web3Wrapper, + txDefaults: Partial, + libraryAddresses: { [libraryName: string]: string } = {}, + ): Promise<{ [libraryName: string]: string }> { + const links = artifact.compilerOutput.evm.bytecode.linkReferences; + // Go through all linked libraries, recursively deploying them if necessary. + for (const link of Object.values(links)) { + for (const libraryName of Object.keys(link)) { + if (!libraryAddresses[libraryName]) { + // Library not yet deployed. + const libraryArtifact = libraryArtifacts[libraryName]; + if (!libraryArtifact) { + throw new Error(`Missing artifact for linked library "${libraryName}"`); + } + // Deploy any dependent libraries used by this library. + await ILiquidityProviderRegistryContract._deployLibrariesAsync( + libraryArtifact, + libraryArtifacts, + web3Wrapper, + txDefaults, + libraryAddresses, + ); + // Deploy this library. + const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses); + const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync( + { + data: linkedLibraryBytecode, + ...txDefaults, + }, + web3Wrapper.estimateGasAsync.bind(web3Wrapper), + ); + const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults); + logUtils.log(`transactionHash: ${txHash}`); + const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash); + logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`); + libraryAddresses[libraryArtifact.contractName] = contractAddress as string; + } + } + } + return libraryAddresses; + } + + public getFunctionSignature(methodName: string): string { + const index = this._methodABIIndex[methodName]; + const methodAbi = ILiquidityProviderRegistryContract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion + const functionSignature = methodAbiToFunctionSignature(methodAbi); + return functionSignature; + } + + public getABIDecodedTransactionData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ILiquidityProviderRegistryContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + } + + public getABIDecodedReturnData(methodName: string, callData: string): T { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ILiquidityProviderRegistryContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + const abiDecodedCallData = abiEncoder.strictDecodeReturnValue(callData); + return abiDecodedCallData; + } + + public getSelector(methodName: string): string { + const functionSignature = this.getFunctionSignature(methodName); + const self = (this as any) as ILiquidityProviderRegistryContract; + const abiEncoder = self._lookupAbiEncoder(functionSignature); + return abiEncoder.getSelector(); + } + + /** + * Returns the address of a liquidity provider for the given market + * (takerToken, makerToken), reverting if the pool does not exist. + * @param takerToken Taker asset managed by liquidity provider. + * @param makerToken Maker asset managed by liquidity provider. + * @returns Address of the liquidity provider. + */ + public getLiquidityProviderForMarket(takerToken: string, makerToken: string): ContractFunctionObj { + const self = (this as any) as ILiquidityProviderRegistryContract; + assert.isString('takerToken', takerToken); + assert.isString('makerToken', makerToken); + const functionSignature = 'getLiquidityProviderForMarket(address,address)'; + + return { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { ...callData, data: this.getABIEncodedTransactionData() }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + takerToken.toLowerCase(), + makerToken.toLowerCase(), + ]); + }, + }; + } + + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + deployedBytecode: string | undefined = ILiquidityProviderRegistryContract.deployedBytecode, + ) { + super( + 'ILiquidityProviderRegistry', + ILiquidityProviderRegistryContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + deployedBytecode, + ); + classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + ILiquidityProviderRegistryContract.ABI().forEach((item, index) => { + if (item.type === 'function') { + const methodAbi = item as MethodAbi; + this._methodABIIndex[methodAbi.name] = index; + } + }); + } +} + +// tslint:disable:max-file-line-count +// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align +// tslint:enable:trailing-comma whitespace no-trailing-whitespace diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index afe2195848..091bfb06b5 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -1,3 +1,5 @@ +export { ERC20BridgeSamplerContract } from './generated-wrappers/erc20_bridge_sampler'; + export { ContractAddresses } from '@0x/contract-addresses'; export { ContractWrappers } from './contract_wrappers';