diff --git a/contracts/zero-ex/CHANGELOG.json b/contracts/zero-ex/CHANGELOG.json index 5c777ec959..5cc8f75b4c 100644 --- a/contracts/zero-ex/CHANGELOG.json +++ b/contracts/zero-ex/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "0.29.0", + "changes": [ + { + "note": "Export TransformERC20FeatureContract", + "pr": 282 + } + ] + }, { "timestamp": 1631710679, "version": "0.28.5", diff --git a/contracts/zero-ex/src/index.ts b/contracts/zero-ex/src/index.ts index f6d5778cde..e4552b5e3b 100644 --- a/contracts/zero-ex/src/index.ts +++ b/contracts/zero-ex/src/index.ts @@ -47,6 +47,7 @@ export { MultiplexFeatureContract, PayTakerTransformerContract, PositiveSlippageFeeTransformerContract, + TransformERC20FeatureContract, WethTransformerContract, ZeroExContract, } from './wrappers'; diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index 5c40bff106..9394b59ec8 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "16.28.0", + "changes": [ + { + "note": "Update ExchangeProxySwapQuoteConsumer for Multiplex V2 and friends", + "pr": 282 + } + ] + }, { "version": "16.27.5", "changes": [ diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index 6dc1fa3bbf..e7e2ef0bb0 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -63,7 +63,7 @@ "@0x/contract-addresses": "^6.7.0", "@0x/contract-wrappers": "^13.17.7", "@0x/contracts-erc20": "^3.3.20", - "@0x/contracts-zero-ex": "^0.27.1", + "@0x/contracts-zero-ex": "^0.28.4", "@0x/dev-utils": "^4.2.9", "@0x/json-schemas": "^6.3.0", "@0x/protocol-utils": "^1.9.0", diff --git a/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts b/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts index 5c14d93713..effe3951fc 100644 --- a/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts +++ b/packages/asset-swapper/src/quote_consumers/exchange_proxy_swap_quote_consumer.ts @@ -1,6 +1,6 @@ import { ChainId, ContractAddresses } from '@0x/contract-addresses'; -import { IZeroExContract, WETH9Contract } from '@0x/contract-wrappers'; -import { MultiplexFeatureContract } from '@0x/contracts-zero-ex'; +import { IZeroExContract } from '@0x/contract-wrappers'; +import { TransformERC20FeatureContract } from '@0x/contracts-zero-ex'; import { encodeAffiliateFeeTransformerData, encodeCurveLiquidityProviderData, @@ -51,6 +51,7 @@ import { import { multiplexPlpEncoder, multiplexRfqEncoder, + MultiplexSubcall, multiplexTransformERC20Encoder, multiplexUniswapEncoder, } from './multiplex_encoders'; @@ -82,7 +83,6 @@ const FAKE_PROVIDER: any = { return; }, }; -const DUMMY_WETH_CONTRACT = new WETH9Contract(NULL_ADDRESS, FAKE_PROVIDER); export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { public readonly chainId: ChainId; @@ -95,7 +95,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { }; private readonly _exchangeProxy: IZeroExContract; - private readonly _multiplex: MultiplexFeatureContract; + private readonly _transformERC20Feature: TransformERC20FeatureContract; constructor(public readonly contractAddresses: ContractAddresses, options: Partial = {}) { const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); @@ -103,7 +103,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { this.chainId = chainId; this.contractAddresses = contractAddresses; this._exchangeProxy = new IZeroExContract(contractAddresses.exchangeProxy, FAKE_PROVIDER); - this._multiplex = new MultiplexFeatureContract(contractAddresses.exchangeProxy, FAKE_PROVIDER); + this._transformERC20Feature = new TransformERC20FeatureContract(contractAddresses.exchangeProxy, FAKE_PROVIDER); this.transformerNonces = { wethTransformer: findTransformerNonce( contractAddresses.transformers.wethTransformer, @@ -338,7 +338,10 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) { return { - calldataHexString: this._encodeMultiplexBatchFillCalldata({ ...quote, orders: slippedOrders }), + calldataHexString: this._encodeMultiplexBatchFillCalldata( + { ...quote, orders: slippedOrders }, + optsWithDefaults, + ), ethAmount, toAddress: this._exchangeProxy.address, allowanceTarget: this._exchangeProxy.address, @@ -473,17 +476,27 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { } } + // Return any unspent sell tokens. + const payTakerTokens = [sellToken]; + // Return any unspent intermediate tokens for two-hop swaps. + if (quote.isTwoHop) { + payTakerTokens.push(intermediateToken); + } + // Return any unspent ETH. If ETH is the buy token, it will + // be returned in TransformERC20Feature rather than PayTakerTransformer. + if (!isToETH) { + payTakerTokens.push(ETH_TOKEN_ADDRESS); + } // The final transformer will send all funds to the taker. transforms.push({ deploymentNonce: this.transformerNonces.payTakerTransformer, data: encodePayTakerTransformerData({ - tokens: [sellToken, buyToken, ETH_TOKEN_ADDRESS].concat(quote.isTwoHop ? intermediateToken : []), + tokens: payTakerTokens, amounts: [], }), }); - - const calldataHexString = this._exchangeProxy - .transformERC20( + const calldataHexString = this._transformERC20Feature + .transformERC20Staging( isFromETH ? ETH_TOKEN_ADDRESS : sellToken, isToETH ? ETH_TOKEN_ADDRESS : buyToken, shouldSellEntireBalance ? MAX_UINT256 : sellAmount, @@ -509,8 +522,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { throw new Error('Execution not supported for Exchange Proxy quotes'); } - private _encodeMultiplexBatchFillCalldata(quote: SwapQuote): string { - const wrappedBatchCalls = []; + private _encodeMultiplexBatchFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string { + const subcalls = []; for_loop: for (const [i, order] of quote.orders.entries()) { switch_statement: switch (order.source) { case ERC20BridgeSource.Native: @@ -519,8 +532,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { // before calling this function. throw new Error('Multiplex batch fill only supported for RFQ native orders'); } - wrappedBatchCalls.push({ - selector: this._exchangeProxy.getSelector('_fillRfqOrder'), + subcalls.push({ + id: MultiplexSubcall.Rfq, sellAmount: order.takerAmount, data: multiplexRfqEncoder.encode({ order: order.fillData.order, @@ -530,8 +543,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { break switch_statement; case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.SushiSwap: - wrappedBatchCalls.push({ - selector: this._multiplex.getSelector('_sellToUniswap'), + subcalls.push({ + id: MultiplexSubcall.UniswapV2, sellAmount: order.takerAmount, data: multiplexUniswapEncoder.encode({ tokens: (order.fillData as UniswapV2FillData).tokenAddressPath, @@ -540,8 +553,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { }); break switch_statement; case ERC20BridgeSource.LiquidityProvider: - wrappedBatchCalls.push({ - selector: this._multiplex.getSelector('_sellToLiquidityProvider'), + subcalls.push({ + id: MultiplexSubcall.LiquidityProvider, sellAmount: order.takerAmount, data: multiplexPlpEncoder.encode({ provider: (order.fillData as LiquidityProviderFillData).poolAddress, @@ -551,8 +564,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { break switch_statement; case ERC20BridgeSource.UniswapV3: const fillData = (order as OptimizedMarketBridgeOrder).fillData; - wrappedBatchCalls.push({ - selector: this._exchangeProxy.getSelector('sellTokenForTokenToUniswapV3'), + subcalls.push({ + id: MultiplexSubcall.UniswapV3, sellAmount: order.takerAmount, data: fillData.uniswapPath, }); @@ -571,54 +584,59 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { { deploymentNonce: this.transformerNonces.payTakerTransformer, data: encodePayTakerTransformerData({ - tokens: [quote.takerToken, quote.makerToken], + tokens: [quote.takerToken], amounts: [], }), }, ]; - wrappedBatchCalls.push({ - selector: this._exchangeProxy.getSelector('_transformERC20'), + subcalls.push({ + id: MultiplexSubcall.TransformERC20, sellAmount: BigNumber.sum(...quote.orders.slice(i).map(o => o.takerAmount)), data: multiplexTransformERC20Encoder.encode({ transformations, - ethValue: constants.ZERO_AMOUNT, }), }); break for_loop; } } - return this._exchangeProxy - .batchFill( - { - inputToken: quote.takerToken, - outputToken: quote.makerToken, - sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount, - calls: wrappedBatchCalls, - }, - quote.worstCaseQuoteInfo.makerAmount, - ) - .getABIEncodedTransactionData(); + if (opts.isFromETH) { + return this._exchangeProxy + .multiplexBatchSellEthForToken(quote.makerToken, subcalls, quote.worstCaseQuoteInfo.makerAmount) + .getABIEncodedTransactionData(); + } else if (opts.isToETH) { + return this._exchangeProxy + .multiplexBatchSellTokenForEth( + quote.takerToken, + subcalls, + quote.worstCaseQuoteInfo.totalTakerAmount, + quote.worstCaseQuoteInfo.makerAmount, + ) + .getABIEncodedTransactionData(); + } else { + return this._exchangeProxy + .multiplexBatchSellTokenForToken( + quote.takerToken, + quote.makerToken, + subcalls, + quote.worstCaseQuoteInfo.totalTakerAmount, + quote.worstCaseQuoteInfo.makerAmount, + ) + .getABIEncodedTransactionData(); + } } private _encodeMultiplexMultiHopFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string { - const wrappedMultiHopCalls = []; - const tokens: string[] = []; - if (opts.isFromETH) { - wrappedMultiHopCalls.push({ - selector: DUMMY_WETH_CONTRACT.getSelector('deposit'), - data: NULL_BYTES, - }); - tokens.push(ETH_TOKEN_ADDRESS); - } + const subcalls = []; const [firstHopOrder, secondHopOrder] = quote.orders; const intermediateToken = firstHopOrder.makerToken; - tokens.push(quote.takerToken, intermediateToken, quote.makerToken); + const tokens = [quote.takerToken, intermediateToken, quote.makerToken]; + for (const order of [firstHopOrder, secondHopOrder]) { switch (order.source) { case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.SushiSwap: - wrappedMultiHopCalls.push({ - selector: this._multiplex.getSelector('_sellToUniswap'), + subcalls.push({ + id: MultiplexSubcall.UniswapV2, data: multiplexUniswapEncoder.encode({ tokens: (order.fillData as UniswapV2FillData).tokenAddressPath, isSushi: order.source === ERC20BridgeSource.SushiSwap, @@ -626,39 +644,49 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { }); break; case ERC20BridgeSource.LiquidityProvider: - wrappedMultiHopCalls.push({ - selector: this._multiplex.getSelector('_sellToLiquidityProvider'), + subcalls.push({ + id: MultiplexSubcall.LiquidityProvider, data: multiplexPlpEncoder.encode({ provider: (order.fillData as LiquidityProviderFillData).poolAddress, auxiliaryData: NULL_BYTES, }), }); break; + case ERC20BridgeSource.UniswapV3: + subcalls.push({ + id: MultiplexSubcall.UniswapV3, + data: (order.fillData as FinalUniswapV3FillData).uniswapPath, + }); + break; default: - // Note: we'll need to redeploy TransformERC20Feature before we can - // use other sources // Should never happen because we check `isMultiplexMultiHopFillCompatible` // before calling this function. throw new Error(`Multiplex multi-hop unsupported source: ${order.source}`); } } - if (opts.isToETH) { - wrappedMultiHopCalls.push({ - selector: DUMMY_WETH_CONTRACT.getSelector('withdraw'), - data: NULL_BYTES, - }); - tokens.push(ETH_TOKEN_ADDRESS); - } - return this._exchangeProxy - .multiHopFill( - { + if (opts.isFromETH) { + return this._exchangeProxy + .multiplexMultiHopSellEthForToken(tokens, subcalls, quote.worstCaseQuoteInfo.makerAmount) + .getABIEncodedTransactionData(); + } else if (opts.isToETH) { + return this._exchangeProxy + .multiplexMultiHopSellTokenForEth( tokens, - sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount, - calls: wrappedMultiHopCalls, - }, - quote.worstCaseQuoteInfo.makerAmount, - ) - .getABIEncodedTransactionData(); + subcalls, + quote.worstCaseQuoteInfo.totalTakerAmount, + quote.worstCaseQuoteInfo.makerAmount, + ) + .getABIEncodedTransactionData(); + } else { + return this._exchangeProxy + .multiplexMultiHopSellTokenForToken( + tokens, + subcalls, + quote.worstCaseQuoteInfo.totalTakerAmount, + quote.worstCaseQuoteInfo.makerAmount, + ) + .getABIEncodedTransactionData(); + } } } diff --git a/packages/asset-swapper/src/quote_consumers/multiplex_encoders.ts b/packages/asset-swapper/src/quote_consumers/multiplex_encoders.ts index 128097f492..0f26153719 100644 --- a/packages/asset-swapper/src/quote_consumers/multiplex_encoders.ts +++ b/packages/asset-swapper/src/quote_consumers/multiplex_encoders.ts @@ -1,6 +1,17 @@ import { RfqOrder, SIGNATURE_ABI } from '@0x/protocol-utils'; import { AbiEncoder } from '@0x/utils'; +export enum MultiplexSubcall { + Invalid, + Rfq, + Otc, + UniswapV2, + UniswapV3, + LiquidityProvider, + TransformERC20, + BatchSell, + MultiHopSell, +} export const multiplexTransformERC20Encoder = AbiEncoder.create([ { name: 'transformations', @@ -10,7 +21,6 @@ export const multiplexTransformERC20Encoder = AbiEncoder.create([ { name: 'data', type: 'bytes' }, ], }, - { name: 'ethValue', type: 'uint256' }, ]); export const multiplexRfqEncoder = AbiEncoder.create([ { name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI }, diff --git a/packages/asset-swapper/src/quote_consumers/quote_consumer_utils.ts b/packages/asset-swapper/src/quote_consumers/quote_consumer_utils.ts index ebfd348723..bc31f9022e 100644 --- a/packages/asset-swapper/src/quote_consumers/quote_consumer_utils.ts +++ b/packages/asset-swapper/src/quote_consumers/quote_consumer_utils.ts @@ -32,10 +32,6 @@ export function isMultiplexBatchFillCompatible(quote: SwapQuote, opts: ExchangeP if (quote.isTwoHop) { return false; } - // batchFill does not support WETH wrapping/unwrapping at the moment - if (opts.isFromETH || opts.isToETH) { - return false; - } if (quote.orders.map(o => o.type).includes(FillQuoteTransformerOrderType.Limit)) { return false; } @@ -49,6 +45,7 @@ const MULTIPLEX_MULTIHOP_FILL_SOURCES = [ ERC20BridgeSource.UniswapV2, ERC20BridgeSource.SushiSwap, ERC20BridgeSource.LiquidityProvider, + ERC20BridgeSource.UniswapV3, ]; /** diff --git a/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts b/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts index b91a123efd..f3abe2389e 100644 --- a/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts +++ b/packages/asset-swapper/test/exchange_proxy_swap_quote_consumer_test.ts @@ -186,7 +186,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { ); } - const transformERC20Encoder = AbiEncoder.createMethod('transformERC20', [ + const transformERC20Encoder = AbiEncoder.createMethod('transformERC20Staging', [ { type: 'address', name: 'inputToken' }, { type: 'address', name: 'outputToken' }, { type: 'uint256', name: 'inputTokenAmount' }, @@ -261,7 +261,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data); expect(payTakerTransformerData.amounts).to.deep.eq([]); - expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]); + expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, ETH_TOKEN_ADDRESS]); }); it('can produce a buy quote', async () => { @@ -292,7 +292,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data); expect(payTakerTransformerData.amounts).to.deep.eq([]); - expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]); + expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, ETH_TOKEN_ADDRESS]); }); it('ERC20 -> ERC20 does not have a WETH transformer', async () => { @@ -437,12 +437,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { expect(secondHopFillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[2].data); expect(payTakerTransformerData.amounts).to.deep.eq([]); - expect(payTakerTransformerData.tokens).to.deep.eq([ - TAKER_TOKEN, - MAKER_TOKEN, - ETH_TOKEN_ADDRESS, - INTERMEDIATE_TOKEN, - ]); + expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, INTERMEDIATE_TOKEN, ETH_TOKEN_ADDRESS]); }); // it.skip('Uses the `LiquidityProviderFeature` if given a single LiquidityProvider order', async () => { // const quote = { @@ -504,7 +499,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => { expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data); expect(payTakerTransformerData.amounts).to.deep.eq([]); - expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]); + expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, ETH_TOKEN_ADDRESS]); }); }); }); diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json index e9e186abfc..230fa5fca5 100644 --- a/packages/contract-artifacts/CHANGELOG.json +++ b/packages/contract-artifacts/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "3.16.0", + "changes": [ + { + "note": "Update IZeroEx and ITransformERC20 artifacts", + "pr": 282 + } + ] + }, { "timestamp": 1631710679, "version": "3.15.1", diff --git a/packages/contract-artifacts/artifacts/ITransformERC20.json b/packages/contract-artifacts/artifacts/ITransformERC20.json index 204065ffde..ef509f6d64 100644 --- a/packages/contract-artifacts/artifacts/ITransformERC20.json +++ b/packages/contract-artifacts/artifacts/ITransformERC20.json @@ -1,6 +1,6 @@ { "schemaVersion": "2.0.0", - "contractName": "ITransformERC20", + "contractName": "ITransformERC20Feature", "compilerOutput": { "abi": [ { @@ -43,14 +43,14 @@ { "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" }, { "internalType": "bytes", "name": "data", "type": "bytes" } ], - "internalType": "struct ITransformERC20.Transformation[]", + "internalType": "struct ITransformERC20Feature.Transformation[]", "name": "transformations", "type": "tuple[]" }, - { "internalType": "bytes32", "name": "callDataHash", "type": "bytes32" }, - { "internalType": "bytes", "name": "callDataSignature", "type": "bytes" } + { "internalType": "bool", "name": "useSelfBalance", "type": "bool" }, + { "internalType": "address payable", "name": "recipient", "type": "address" } ], - "internalType": "struct ITransformERC20.TransformERC20Args", + "internalType": "struct ITransformERC20Feature.TransformERC20Args", "name": "args", "type": "tuple" } @@ -113,7 +113,7 @@ { "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" }, { "internalType": "bytes", "name": "data", "type": "bytes" } ], - "internalType": "struct ITransformERC20.Transformation[]", + "internalType": "struct ITransformERC20Feature.Transformation[]", "name": "transformations", "type": "tuple[]" } @@ -148,7 +148,7 @@ }, "kind": "dev", "methods": { - "_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bytes32,bytes))": { + "_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))": { "details": "Internal version of `transformERC20()`. Only callable from within.", "params": { "args": "A `TransformERC20Args` struct." }, "returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." } @@ -212,7 +212,8 @@ "evm.bytecode.object", "evm.bytecode.sourceMap", "evm.deployedBytecode.object", - "evm.deployedBytecode.sourceMap" + "evm.deployedBytecode.sourceMap", + "evm.methodIdentifiers" ] } }, diff --git a/packages/contract-artifacts/artifacts/IZeroEx.json b/packages/contract-artifacts/artifacts/IZeroEx.json index ce5d97b0e5..08382371f6 100644 --- a/packages/contract-artifacts/artifacts/IZeroEx.json +++ b/packages/contract-artifacts/artifacts/IZeroEx.json @@ -3,16 +3,6 @@ "contractName": "IZeroEx", "compilerOutput": { "abi": [ - { - "anonymous": false, - "inputs": [ - { "indexed": false, "internalType": "bytes32", "name": "orderHash", "type": "bytes32" }, - { "indexed": false, "internalType": "address", "name": "maker", "type": "address" }, - { "indexed": false, "internalType": "uint64", "name": "expiry", "type": "uint64" } - ], - "name": "ExpiredRfqOrder", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -49,11 +39,26 @@ { "anonymous": false, "inputs": [ - { "indexed": false, "internalType": "address", "name": "inputToken", "type": "address" }, - { "indexed": false, "internalType": "address", "name": "outputToken", "type": "address" }, + { + "indexed": false, + "internalType": "contract IERC20TokenV06", + "name": "inputToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IERC20TokenV06", + "name": "outputToken", + "type": "address" + }, { "indexed": false, "internalType": "uint256", "name": "inputTokenAmount", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }, - { "indexed": false, "internalType": "address", "name": "provider", "type": "address" }, + { + "indexed": false, + "internalType": "contract ILiquidityProvider", + "name": "provider", + "type": "address" + }, { "indexed": false, "internalType": "address", "name": "recipient", "type": "address" } ], "name": "LiquidityProviderSwap", @@ -110,10 +115,10 @@ { "indexed": false, "internalType": "uint128", - "name": "takerTokenFilledAmount", + "name": "makerTokenFilledAmount", "type": "uint128" }, - { "indexed": false, "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" } + { "indexed": false, "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" } ], "name": "OtcOrderFilled", "type": "event" @@ -268,6 +273,51 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" }, + { "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" }, + { "internalType": "uint128", "name": "makerAmount", "type": "uint128" }, + { "internalType": "uint128", "name": "takerAmount", "type": "uint128" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "address", "name": "txOrigin", "type": "address" }, + { "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" } + ], + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", + "type": "tuple" + }, + { "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "bool", "name": "useSelfBalance", "type": "bool" }, + { "internalType": "address", "name": "recipient", "type": "address" } + ], + "name": "_fillOtcOrder", + "outputs": [ + { "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" }, + { "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -303,7 +353,9 @@ "type": "tuple" }, { "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }, - { "internalType": "address", "name": "taker", "type": "address" } + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "bool", "name": "useSelfBalance", "type": "bool" }, + { "internalType": "address", "name": "recipient", "type": "address" } ], "name": "_fillRfqOrder", "outputs": [ @@ -313,6 +365,18 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "bytes", "name": "encodedPath", "type": "bytes" }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }, + { "internalType": "address", "name": "recipient", "type": "address" } + ], + "name": "_sellHeldTokenForTokenToUniswapV3", + "outputs": [{ "internalType": "uint256", "name": "buyAmount", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -330,7 +394,9 @@ "internalType": "struct ITransformERC20Feature.Transformation[]", "name": "transformations", "type": "tuple[]" - } + }, + { "internalType": "bool", "name": "useSelfBalance", "type": "bool" }, + { "internalType": "address payable", "name": "recipient", "type": "address" } ], "internalType": "struct ITransformERC20Feature.TransformERC20Args", "name": "args", @@ -480,35 +546,6 @@ "stateMutability": "payable", "type": "function" }, - { - "inputs": [ - { - "components": [ - { "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" }, - { "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" }, - { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, - { - "components": [ - { "internalType": "bytes4", "name": "selector", "type": "bytes4" }, - { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "internalType": "struct IMultiplexFeature.WrappedBatchCall[]", - "name": "calls", - "type": "tuple[]" - } - ], - "internalType": "struct IMultiplexFeature.BatchFillData", - "name": "fillData", - "type": "tuple" - }, - { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } - ], - "name": "batchFill", - "outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -601,6 +638,60 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" }, + { "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" }, + { "internalType": "uint128", "name": "makerAmount", "type": "uint128" }, + { "internalType": "uint128", "name": "takerAmount", "type": "uint128" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "address", "name": "txOrigin", "type": "address" }, + { "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" } + ], + "internalType": "struct LibNativeOrder.OtcOrder[]", + "name": "orders", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "internalType": "struct LibSignature.Signature[]", + "name": "makerSignatures", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "internalType": "struct LibSignature.Signature[]", + "name": "takerSignatures", + "type": "tuple[]" + }, + { "internalType": "bool[]", "name": "unwrapWeth", "type": "bool[]" } + ], + "name": "batchFillTakerSignedOtcOrders", + "outputs": [{ "internalType": "bool[]", "name": "successes", "type": "bool[]" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1026,8 +1117,7 @@ "name": "makerSignature", "type": "tuple" }, - { "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }, - { "internalType": "bool", "name": "unwrapWeth", "type": "bool" } + { "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" } ], "name": "fillOtcOrder", "outputs": [ @@ -1037,6 +1127,48 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" }, + { "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" }, + { "internalType": "uint128", "name": "makerAmount", "type": "uint128" }, + { "internalType": "uint128", "name": "takerAmount", "type": "uint128" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "address", "name": "txOrigin", "type": "address" }, + { "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" } + ], + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", + "type": "tuple" + }, + { "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" } + ], + "name": "fillOtcOrderForEth", + "outputs": [ + { "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" }, + { "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -1168,14 +1300,63 @@ "internalType": "struct LibSignature.Signature", "name": "takerSignature", "type": "tuple" - }, - { "internalType": "bool", "name": "unwrapWeth", "type": "bool" } + } ], "name": "fillTakerSignedOtcOrder", - "outputs": [ - { "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" }, - { "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" } + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" }, + { "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" }, + { "internalType": "uint128", "name": "makerAmount", "type": "uint128" }, + { "internalType": "uint128", "name": "takerAmount", "type": "uint128" }, + { "internalType": "address", "name": "maker", "type": "address" }, + { "internalType": "address", "name": "taker", "type": "address" }, + { "internalType": "address", "name": "txOrigin", "type": "address" }, + { "internalType": "uint256", "name": "expiryAndNonce", "type": "uint256" } + ], + "internalType": "struct LibNativeOrder.OtcOrder", + "name": "order", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "internalType": "struct LibSignature.Signature", + "name": "makerSignature", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "enum LibSignature.SignatureType", + "name": "signatureType", + "type": "uint8" + }, + { "internalType": "uint8", "name": "v", "type": "uint8" }, + { "internalType": "bytes32", "name": "r", "type": "bytes32" }, + { "internalType": "bytes32", "name": "s", "type": "bytes32" } + ], + "internalType": "struct LibSignature.Signature", + "name": "takerSignature", + "type": "tuple" + } ], + "name": "fillTakerSignedOtcOrderForEth", + "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -1604,31 +1785,150 @@ }, { "inputs": [ + { "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" }, { "components": [ - { "internalType": "address[]", "name": "tokens", "type": "address[]" }, - { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, { - "components": [ - { "internalType": "bytes4", "name": "selector", "type": "bytes4" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "internalType": "struct IMultiplexFeature.WrappedMultiHopCall[]", - "name": "calls", - "type": "tuple[]" - } + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } ], - "internalType": "struct IMultiplexFeature.MultiHopFillData", - "name": "fillData", - "type": "tuple" + "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", + "name": "calls", + "type": "tuple[]" }, { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } ], - "name": "multiHopFill", - "outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }], + "name": "multiplexBatchSellEthForToken", + "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } + ], + "name": "multiplexBatchSellTokenForEth", + "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" }, + { "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "internalType": "struct IMultiplexFeature.BatchSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } + ], + "name": "multiplexBatchSellTokenForToken", + "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address[]", "name": "tokens", "type": "address[]" }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } + ], + "name": "multiplexMultiHopSellEthForToken", + "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address[]", "name": "tokens", "type": "address[]" }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } + ], + "name": "multiplexMultiHopSellTokenForEth", + "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address[]", "name": "tokens", "type": "address[]" }, + { + "components": [ + { + "internalType": "enum IMultiplexFeature.MultiplexSubcall", + "name": "id", + "type": "uint8" + }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "internalType": "struct IMultiplexFeature.MultiHopSellSubcall[]", + "name": "calls", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "sellAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } + ], + "name": "multiplexMultiHopSellTokenForToken", + "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "owner", @@ -1819,20 +2119,47 @@ "takerTokenFilledAmount": "How much maker token was filled." } }, - "_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address)": { + "_fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": { + "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Internal variant.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "recipient": "The recipient of the bought maker tokens.", + "taker": "The address to fill the order in the context of.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with.", + "useSelfBalance": "Whether to use the Exchange Proxy's balance of input tokens." + }, + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much taker token was filled." + } + }, + "_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": { "details": "Fill an RFQ order. Internal variant.", "params": { "order": "The RFQ order.", + "recipient": "The recipient of the maker tokens.", "signature": "The order signature.", "taker": "The order taker.", - "takerTokenFillAmount": "Maximum taker token to fill this order with." + "takerTokenFillAmount": "Maximum taker token to fill this order with.", + "useSelfBalance": "Whether to use the ExchangeProxy's transient balance of taker tokens to fill the order." }, "returns": { "makerTokenFilledAmount": "How much maker token was filled.", "takerTokenFilledAmount": "How much maker token was filled." } }, - "_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[]))": { + "_sellHeldTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": { + "details": "Sell a token for another token directly against uniswap v3. Private variant, uses tokens held by `address(this)`.", + "params": { + "encodedPath": "Uniswap-encoded path.", + "minBuyAmount": "Minimum amount of the last token in the path to buy.", + "recipient": "The recipient of the bought tokens. Can be zero for sender.", + "sellAmount": "amount of the first token in the path to sell." + }, + "returns": { "buyAmount": "Amount of the last token in the path bought." } + }, + "_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))": { "details": "Internal version of `transformERC20()`. Only callable from within.", "params": { "args": "A `TransformERC20Args` struct." }, "returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." } @@ -1887,14 +2214,6 @@ }, "returns": { "returnResults": "The ABI-encoded results of the underlying calls." } }, - "batchFill((address,address,uint256,(bytes4,uint256,bytes)[]),uint256)": { - "details": "Executes a batch of fills selling `fillData.inputToken` for `fillData.outputToken` in sequence. Refer to the internal variant `_batchFill` for the allowed nested operations.", - "params": { - "fillData": "Encodes the input/output tokens, the sell amount, and the nested operations for this batch fill.", - "minBuyAmount": "The minimum amount of `fillData.outputToken` to buy. Reverts if this amount is not met." - }, - "returns": { "outputTokenAmount": "The amount of the output token bought." } - }, "batchFillLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": { "details": "Fills multiple limit orders.", "params": { @@ -1921,6 +2240,18 @@ "takerTokenFilledAmounts": "Array of amounts filled, in taker token." } }, + "batchFillTakerSignedOtcOrders((address,address,uint128,uint128,address,address,address,uint256)[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[],bool[])": { + "details": "Fills multiple taker-signed OTC orders.", + "params": { + "makerSignatures": "Array of maker signatures for each order.", + "orders": "Array of OTC orders.", + "takerSignatures": "Array of taker signatures for each order.", + "unwrapWeth": "Array of booleans representing whether or not to unwrap bought WETH into ETH for each order. Should be set to false if the maker token is not WETH." + }, + "returns": { + "successes": "Array of booleans representing whether or not each order in `orders` was filled successfully." + } + }, "batchGetLimitOrderRelevantStates((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { "details": "Batch version of `getLimitOrderRelevantState()`, without reverting. Orders that would normally cause `getLimitOrderRelevantState()` to revert will have empty results.", "params": { "orders": "The limit orders.", "signatures": "The order signatures." }, @@ -2027,13 +2358,24 @@ }, "returns": { "makerTokenFilledAmount": "How much maker token was filled." } }, - "fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,bool)": { + "fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens.", "params": { "makerSignature": "The order signature from the maker.", "order": "The OTC order.", - "takerTokenFillAmount": "Maximum taker token amount to fill this order with.", - "unwrapWeth": "Whether or not to unwrap bought WETH into ETH before transferring it to the taker. Should be set to false" + "takerTokenFillAmount": "Maximum taker token amount to fill this order with." + }, + "returns": { + "makerTokenFilledAmount": "How much maker token was filled.", + "takerTokenFilledAmount": "How much taker token was filled." + } + }, + "fillOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)": { + "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens. Unwraps bought WETH into ETH before sending it to the taker.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "takerTokenFillAmount": "Maximum taker token amount to fill this order with." }, "returns": { "makerTokenFilledAmount": "How much maker token was filled.", @@ -2060,17 +2402,20 @@ "takerTokenFilledAmount": "How much maker token was filled." } }, - "fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32),bool)": { + "fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker.", "params": { "makerSignature": "The order signature from the maker.", "order": "The OTC order.", - "takerSignature": "The order signature from the taker.", - "unwrapWeth": "Whether or not to unwrap bought WETH into ETH before transferring it to the taker. Should be set to false if the maker token is not WETH." - }, - "returns": { - "makerTokenFilledAmount": "How much maker token was filled.", - "takerTokenFilledAmount": "How much taker token was filled." + "takerSignature": "The order signature from the taker." + } + }, + "fillTakerSignedOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": { + "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker. Unwraps bought WETH into ETH before sending it to the taker.", + "params": { + "makerSignature": "The order signature from the maker.", + "order": "The OTC order.", + "takerSignature": "The order signature from the taker." } }, "getLimitOrderHash((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { @@ -2184,13 +2529,62 @@ "target": "The migrator contract address." } }, - "multiHopFill((address[],uint256,(bytes4,bytes)[]),uint256)": { - "details": "Executes a sequence of fills \"hopping\" through the path of tokens given by `fillData.tokens`. Refer to the internal variant `_multiHopFill` for the allowed nested operations.", + "multiplexBatchSellEthForToken(address,(uint8,uint256,bytes)[],uint256)": { + "details": "Sells attached ETH for `outputToken` using the provided calls.", "params": { - "fillData": "Encodes the path of tokens, the sell amount, and the nested operations for this multi-hop fill.", - "minBuyAmount": "The minimum amount of the output token to buy. Reverts if this amount is not met." + "calls": "The calls to use to sell the attached ETH.", + "minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.", + "outputToken": "The token to buy." }, - "returns": { "outputTokenAmount": "The amount of the output token bought." } + "returns": { "boughtAmount": "The amount of `outputToken` bought." } + }, + "multiplexBatchSellTokenForEth(address,(uint8,uint256,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the given `inputToken` for ETH using the provided calls.", + "params": { + "calls": "The calls to use to sell the input tokens.", + "inputToken": "The token to sell.", + "minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.", + "sellAmount": "The amount of `inputToken` to sell." + }, + "returns": { "boughtAmount": "The amount of ETH bought." } + }, + "multiplexBatchSellTokenForToken(address,address,(uint8,uint256,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the given `inputToken` for `outputToken` using the provided calls.", + "params": { + "calls": "The calls to use to sell the input tokens.", + "inputToken": "The token to sell.", + "minBuyAmount": "The minimum amount of `outputToken` that must be bought for this function to not revert.", + "outputToken": "The token to buy.", + "sellAmount": "The amount of `inputToken` to sell." + }, + "returns": { "boughtAmount": "The amount of `outputToken` bought." } + }, + "multiplexMultiHopSellEthForToken(address[],(uint8,bytes)[],uint256)": { + "details": "Sells attached ETH via the given sequence of tokens and calls. `tokens[0]` must be WETH. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`", + "params": { + "calls": "The sequence of calls to use for the sell.", + "minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.", + "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + }, + "returns": { "boughtAmount": "The amount of output tokens bought." } + }, + "multiplexMultiHopSellTokenForEth(address[],(uint8,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the input token (`tokens[0]`) for ETH via the given sequence of tokens and calls. The last token in `tokens` must be WETH.", + "params": { + "calls": "The sequence of calls to use for the sell.", + "minBuyAmount": "The minimum amount of ETH that must be bought for this function to not revert.", + "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + }, + "returns": { "boughtAmount": "The amount of ETH bought." } + }, + "multiplexMultiHopSellTokenForToken(address[],(uint8,bytes)[],uint256,uint256)": { + "details": "Sells `sellAmount` of the input token (`tokens[0]`) via the given sequence of tokens and calls. The last token in `tokens` is the output token that will ultimately be sent to `msg.sender`", + "params": { + "calls": "The sequence of calls to use for the sell.", + "minBuyAmount": "The minimum amount of output tokens that must be bought for this function to not revert.", + "tokens": "The sequence of tokens to use for the sell, i.e. `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`." + }, + "returns": { "boughtAmount": "The amount of output tokens bought." } }, "owner()": { "details": "The owner of this contract.", diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index e6d7a950c1..d44e8cea64 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "13.18.0", + "changes": [ + { + "note": "Update IZeroEx and ITransformERC20 wrappers", + "pr": 282 + } + ] + }, { "timestamp": 1631710679, "version": "13.17.7", diff --git a/packages/contract-wrappers/src/generated-wrappers/i_transform_erc20.ts b/packages/contract-wrappers/src/generated-wrappers/i_transform_erc20.ts index fb439f3be8..4acb53c396 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_transform_erc20.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_transform_erc20.ts @@ -269,12 +269,12 @@ export class ITransformERC20Contract extends BaseContract { ], }, { - name: 'callDataHash', - type: 'bytes32', + name: 'useSelfBalance', + type: 'bool', }, { - name: 'callDataSignature', - type: 'bytes', + name: 'recipient', + type: 'address', }, ], }, @@ -497,13 +497,13 @@ export class ITransformERC20Contract extends BaseContract { inputTokenAmount: BigNumber; minOutputTokenAmount: BigNumber; transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>; - callDataHash: string; - callDataSignature: string; + useSelfBalance: boolean; + recipient: string; }): ContractTxFunctionObj { const self = (this as any) as ITransformERC20Contract; const functionSignature = - '_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bytes32,bytes))'; + '_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))'; return { async sendTransactionAsync( diff --git a/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts b/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts index 891aa16ae2..7525199c92 100644 --- a/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts +++ b/packages/contract-wrappers/src/generated-wrappers/i_zero_ex.ts @@ -38,7 +38,6 @@ import * as ethers from 'ethers'; // tslint:enable:no-unused-variable export type IZeroExEventArgs = - | IZeroExExpiredRfqOrderEventArgs | IZeroExLimitOrderFilledEventArgs | IZeroExLiquidityProviderSwapEventArgs | IZeroExMetaTransactionExecutedEventArgs @@ -57,7 +56,6 @@ export type IZeroExEventArgs = | IZeroExTransformerDeployerUpdatedEventArgs; export enum IZeroExEvents { - ExpiredRfqOrder = 'ExpiredRfqOrder', LimitOrderFilled = 'LimitOrderFilled', LiquidityProviderSwap = 'LiquidityProviderSwap', MetaTransactionExecuted = 'MetaTransactionExecuted', @@ -76,12 +74,6 @@ export enum IZeroExEvents { TransformerDeployerUpdated = 'TransformerDeployerUpdated', } -export interface IZeroExExpiredRfqOrderEventArgs extends DecodedLogArgs { - orderHash: string; - maker: string; - expiry: BigNumber; -} - export interface IZeroExLimitOrderFilledEventArgs extends DecodedLogArgs { orderHash: string; maker: string; @@ -135,8 +127,8 @@ export interface IZeroExOtcOrderFilledEventArgs extends DecodedLogArgs { taker: string; makerToken: string; takerToken: string; - takerTokenFilledAmount: BigNumber; makerTokenFilledAmount: BigNumber; + takerTokenFilledAmount: BigNumber; } export interface IZeroExOwnershipTransferredEventArgs extends DecodedLogArgs { @@ -302,29 +294,6 @@ export class IZeroExContract extends BaseContract { */ public static ABI(): ContractAbi { const abi = [ - { - anonymous: false, - inputs: [ - { - name: 'orderHash', - type: 'bytes32', - indexed: false, - }, - { - name: 'maker', - type: 'address', - indexed: false, - }, - { - name: 'expiry', - type: 'uint64', - indexed: false, - }, - ], - name: 'ExpiredRfqOrder', - outputs: [], - type: 'event', - }, { anonymous: false, inputs: [ @@ -547,12 +516,12 @@ export class IZeroExContract extends BaseContract { indexed: false, }, { - name: 'takerTokenFilledAmount', + name: 'makerTokenFilledAmount', type: 'uint128', indexed: false, }, { - name: 'makerTokenFilledAmount', + name: 'takerTokenFilledAmount', type: 'uint128', indexed: false, }, @@ -893,6 +862,99 @@ export class IZeroExContract extends BaseContract { stateMutability: 'payable', type: 'function', }, + { + inputs: [ + { + name: 'order', + type: 'tuple', + components: [ + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerAmount', + type: 'uint128', + }, + { + name: 'takerAmount', + type: 'uint128', + }, + { + name: 'maker', + type: 'address', + }, + { + name: 'taker', + type: 'address', + }, + { + name: 'txOrigin', + type: 'address', + }, + { + name: 'expiryAndNonce', + type: 'uint256', + }, + ], + }, + { + name: 'makerSignature', + type: 'tuple', + components: [ + { + name: 'signatureType', + type: 'uint8', + }, + { + name: 'v', + type: 'uint8', + }, + { + name: 'r', + type: 'bytes32', + }, + { + name: 's', + type: 'bytes32', + }, + ], + }, + { + name: 'takerTokenFillAmount', + type: 'uint128', + }, + { + name: 'taker', + type: 'address', + }, + { + name: 'useSelfBalance', + type: 'bool', + }, + { + name: 'recipient', + type: 'address', + }, + ], + name: '_fillOtcOrder', + outputs: [ + { + name: 'takerTokenFilledAmount', + type: 'uint128', + }, + { + name: 'makerTokenFilledAmount', + type: 'uint128', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, { inputs: [ { @@ -971,6 +1033,14 @@ export class IZeroExContract extends BaseContract { name: 'taker', type: 'address', }, + { + name: 'useSelfBalance', + type: 'bool', + }, + { + name: 'recipient', + type: 'address', + }, ], name: '_fillRfqOrder', outputs: [ @@ -986,6 +1056,35 @@ export class IZeroExContract extends BaseContract { stateMutability: 'nonpayable', type: 'function', }, + { + inputs: [ + { + name: 'encodedPath', + type: 'bytes', + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'minBuyAmount', + type: 'uint256', + }, + { + name: 'recipient', + type: 'address', + }, + ], + name: '_sellHeldTokenForTokenToUniswapV3', + outputs: [ + { + name: 'buyAmount', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, { inputs: [ { @@ -1026,6 +1125,14 @@ export class IZeroExContract extends BaseContract { }, ], }, + { + name: 'useSelfBalance', + type: 'bool', + }, + { + name: 'recipient', + type: 'address', + }, ], }, ], @@ -1324,59 +1431,6 @@ export class IZeroExContract extends BaseContract { stateMutability: 'payable', type: 'function', }, - { - inputs: [ - { - name: 'fillData', - type: 'tuple', - components: [ - { - name: 'inputToken', - type: 'address', - }, - { - name: 'outputToken', - type: 'address', - }, - { - name: 'sellAmount', - type: 'uint256', - }, - { - name: 'calls', - type: 'tuple[]', - components: [ - { - name: 'selector', - type: 'bytes4', - }, - { - name: 'sellAmount', - type: 'uint256', - }, - { - name: 'data', - type: 'bytes', - }, - ], - }, - ], - }, - { - name: 'minBuyAmount', - type: 'uint256', - }, - ], - name: 'batchFill', - outputs: [ - { - name: 'outputTokenAmount', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, { inputs: [ { @@ -1571,6 +1625,105 @@ export class IZeroExContract extends BaseContract { stateMutability: 'nonpayable', type: 'function', }, + { + inputs: [ + { + name: 'orders', + type: 'tuple[]', + components: [ + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerAmount', + type: 'uint128', + }, + { + name: 'takerAmount', + type: 'uint128', + }, + { + name: 'maker', + type: 'address', + }, + { + name: 'taker', + type: 'address', + }, + { + name: 'txOrigin', + type: 'address', + }, + { + name: 'expiryAndNonce', + type: 'uint256', + }, + ], + }, + { + name: 'makerSignatures', + type: 'tuple[]', + components: [ + { + name: 'signatureType', + type: 'uint8', + }, + { + name: 'v', + type: 'uint8', + }, + { + name: 'r', + type: 'bytes32', + }, + { + name: 's', + type: 'bytes32', + }, + ], + }, + { + name: 'takerSignatures', + type: 'tuple[]', + components: [ + { + name: 'signatureType', + type: 'uint8', + }, + { + name: 'v', + type: 'uint8', + }, + { + name: 'r', + type: 'bytes32', + }, + { + name: 's', + type: 'bytes32', + }, + ], + }, + { + name: 'unwrapWeth', + type: 'bool[]', + }, + ], + name: 'batchFillTakerSignedOtcOrders', + outputs: [ + { + name: 'successes', + type: 'bool[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, { inputs: [ { @@ -2439,10 +2592,6 @@ export class IZeroExContract extends BaseContract { name: 'takerTokenFillAmount', type: 'uint128', }, - { - name: 'unwrapWeth', - type: 'bool', - }, ], name: 'fillOtcOrder', outputs: [ @@ -2458,6 +2607,87 @@ export class IZeroExContract extends BaseContract { stateMutability: 'nonpayable', type: 'function', }, + { + inputs: [ + { + name: 'order', + type: 'tuple', + components: [ + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerAmount', + type: 'uint128', + }, + { + name: 'takerAmount', + type: 'uint128', + }, + { + name: 'maker', + type: 'address', + }, + { + name: 'taker', + type: 'address', + }, + { + name: 'txOrigin', + type: 'address', + }, + { + name: 'expiryAndNonce', + type: 'uint256', + }, + ], + }, + { + name: 'makerSignature', + type: 'tuple', + components: [ + { + name: 'signatureType', + type: 'uint8', + }, + { + name: 'v', + type: 'uint8', + }, + { + name: 'r', + type: 'bytes32', + }, + { + name: 's', + type: 'bytes32', + }, + ], + }, + { + name: 'takerTokenFillAmount', + type: 'uint128', + }, + ], + name: 'fillOtcOrderForEth', + outputs: [ + { + name: 'takerTokenFilledAmount', + type: 'uint128', + }, + { + name: 'makerTokenFilledAmount', + type: 'uint128', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, { inputs: [ { @@ -2708,22 +2938,99 @@ export class IZeroExContract extends BaseContract { }, ], }, - { - name: 'unwrapWeth', - type: 'bool', - }, ], name: 'fillTakerSignedOtcOrder', - outputs: [ + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ { - name: 'takerTokenFilledAmount', - type: 'uint128', + name: 'order', + type: 'tuple', + components: [ + { + name: 'makerToken', + type: 'address', + }, + { + name: 'takerToken', + type: 'address', + }, + { + name: 'makerAmount', + type: 'uint128', + }, + { + name: 'takerAmount', + type: 'uint128', + }, + { + name: 'maker', + type: 'address', + }, + { + name: 'taker', + type: 'address', + }, + { + name: 'txOrigin', + type: 'address', + }, + { + name: 'expiryAndNonce', + type: 'uint256', + }, + ], }, { - name: 'makerTokenFilledAmount', - type: 'uint128', + name: 'makerSignature', + type: 'tuple', + components: [ + { + name: 'signatureType', + type: 'uint8', + }, + { + name: 'v', + type: 'uint8', + }, + { + name: 'r', + type: 'bytes32', + }, + { + name: 's', + type: 'bytes32', + }, + ], + }, + { + name: 'takerSignature', + type: 'tuple', + components: [ + { + name: 'signatureType', + type: 'uint8', + }, + { + name: 'v', + type: 'uint8', + }, + { + name: 'r', + type: 'bytes32', + }, + { + name: 's', + type: 'bytes32', + }, + ], }, ], + name: 'fillTakerSignedOtcOrderForEth', + outputs: [], stateMutability: 'nonpayable', type: 'function', }, @@ -3619,30 +3926,24 @@ export class IZeroExContract extends BaseContract { { inputs: [ { - name: 'fillData', - type: 'tuple', + name: 'outputToken', + type: 'address', + }, + { + name: 'calls', + type: 'tuple[]', components: [ { - name: 'tokens', - type: 'address[]', + name: 'id', + type: 'uint8', }, { name: 'sellAmount', type: 'uint256', }, { - name: 'calls', - type: 'tuple[]', - components: [ - { - name: 'selector', - type: 'bytes4', - }, - { - name: 'data', - type: 'bytes', - }, - ], + name: 'data', + type: 'bytes', }, ], }, @@ -3651,16 +3952,219 @@ export class IZeroExContract extends BaseContract { type: 'uint256', }, ], - name: 'multiHopFill', + name: 'multiplexBatchSellEthForToken', outputs: [ { - name: 'outputTokenAmount', + name: 'boughtAmount', type: 'uint256', }, ], stateMutability: 'payable', type: 'function', }, + { + inputs: [ + { + name: 'inputToken', + type: 'address', + }, + { + name: 'calls', + type: 'tuple[]', + components: [ + { + name: 'id', + type: 'uint8', + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'data', + type: 'bytes', + }, + ], + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'minBuyAmount', + type: 'uint256', + }, + ], + name: 'multiplexBatchSellTokenForEth', + outputs: [ + { + name: 'boughtAmount', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + name: 'inputToken', + type: 'address', + }, + { + name: 'outputToken', + type: 'address', + }, + { + name: 'calls', + type: 'tuple[]', + components: [ + { + name: 'id', + type: 'uint8', + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'data', + type: 'bytes', + }, + ], + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'minBuyAmount', + type: 'uint256', + }, + ], + name: 'multiplexBatchSellTokenForToken', + outputs: [ + { + name: 'boughtAmount', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + name: 'tokens', + type: 'address[]', + }, + { + name: 'calls', + type: 'tuple[]', + components: [ + { + name: 'id', + type: 'uint8', + }, + { + name: 'data', + type: 'bytes', + }, + ], + }, + { + name: 'minBuyAmount', + type: 'uint256', + }, + ], + name: 'multiplexMultiHopSellEthForToken', + outputs: [ + { + name: 'boughtAmount', + type: 'uint256', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + name: 'tokens', + type: 'address[]', + }, + { + name: 'calls', + type: 'tuple[]', + components: [ + { + name: 'id', + type: 'uint8', + }, + { + name: 'data', + type: 'bytes', + }, + ], + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'minBuyAmount', + type: 'uint256', + }, + ], + name: 'multiplexMultiHopSellTokenForEth', + outputs: [ + { + name: 'boughtAmount', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + name: 'tokens', + type: 'address[]', + }, + { + name: 'calls', + type: 'tuple[]', + components: [ + { + name: 'id', + type: 'uint8', + }, + { + name: 'data', + type: 'bytes', + }, + ], + }, + { + name: 'sellAmount', + type: 'uint256', + }, + { + name: 'minBuyAmount', + type: 'uint256', + }, + ], + name: 'multiplexMultiHopSellTokenForToken', + outputs: [ + { + name: 'boughtAmount', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, { inputs: [], name: 'owner', @@ -4195,12 +4699,115 @@ export class IZeroExContract extends BaseContract { }, }; } + /** + * Fill an OTC order for up to `takerTokenFillAmount` taker tokens. + * Internal variant. + * @param order The OTC order. + * @param makerSignature The order signature from the maker. + * @param takerTokenFillAmount Maximum taker token amount to fill this + * order with. + * @param taker The address to fill the order in the context of. + * @param useSelfBalance Whether to use the Exchange Proxy's balance of + * input tokens. + * @param recipient The recipient of the bought maker tokens. + */ + public _fillOtcOrder( + order: { + makerToken: string; + takerToken: string; + makerAmount: BigNumber; + takerAmount: BigNumber; + maker: string; + taker: string; + txOrigin: string; + expiryAndNonce: BigNumber; + }, + makerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, + takerTokenFillAmount: BigNumber, + taker: string, + useSelfBalance: boolean, + recipient: string, + ): ContractTxFunctionObj<[BigNumber, BigNumber]> { + const self = (this as any) as IZeroExContract; + + assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); + assert.isString('taker', taker); + assert.isBoolean('useSelfBalance', useSelfBalance); + assert.isString('recipient', recipient); + const functionSignature = + '_fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync( + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[BigNumber, BigNumber]> { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue<[BigNumber, BigNumber]>(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + order, + makerSignature, + takerTokenFillAmount, + taker.toLowerCase(), + useSelfBalance, + recipient.toLowerCase(), + ]); + }, + }; + } /** * Fill an RFQ order. Internal variant. * @param order The RFQ order. * @param signature The order signature. * @param takerTokenFillAmount Maximum taker token to fill this order with. * @param taker The order taker. + * @param useSelfBalance Whether to use the ExchangeProxy's transient + * balance of taker tokens to fill the order. + * @param recipient The recipient of the maker tokens. */ public _fillRfqOrder( order: { @@ -4218,13 +4825,17 @@ export class IZeroExContract extends BaseContract { signature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, takerTokenFillAmount: BigNumber, taker: string, + useSelfBalance: boolean, + recipient: string, ): ContractTxFunctionObj<[BigNumber, BigNumber]> { const self = (this as any) as IZeroExContract; assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); assert.isString('taker', taker); + assert.isBoolean('useSelfBalance', useSelfBalance); + assert.isString('recipient', recipient); const functionSignature = - '_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address)'; + '_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)'; return { async sendTransactionAsync( @@ -4282,6 +4893,86 @@ export class IZeroExContract extends BaseContract { signature, takerTokenFillAmount, taker.toLowerCase(), + useSelfBalance, + recipient.toLowerCase(), + ]); + }, + }; + } + /** + * Sell a token for another token directly against uniswap v3. + * Private variant, uses tokens held by `address(this)`. + * @param encodedPath Uniswap-encoded path. + * @param sellAmount amount of the first token in the path to sell. + * @param minBuyAmount Minimum amount of the last token in the path to buy. + * @param recipient The recipient of the bought tokens. Can be zero for sender. + */ + public _sellHeldTokenForTokenToUniswapV3( + encodedPath: string, + sellAmount: BigNumber, + minBuyAmount: BigNumber, + recipient: string, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isString('encodedPath', encodedPath); + assert.isBigNumber('sellAmount', sellAmount); + assert.isBigNumber('minBuyAmount', minBuyAmount); + assert.isString('recipient', recipient); + const functionSignature = '_sellHeldTokenForTokenToUniswapV3(bytes,uint256,uint256,address)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + encodedPath, + sellAmount, + minBuyAmount, + recipient.toLowerCase(), ]); }, }; @@ -4297,10 +4988,13 @@ export class IZeroExContract extends BaseContract { inputTokenAmount: BigNumber; minOutputTokenAmount: BigNumber; transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>; + useSelfBalance: boolean; + recipient: string; }): ContractTxFunctionObj { const self = (this as any) as IZeroExContract; - const functionSignature = '_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[]))'; + const functionSignature = + '_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))'; return { async sendTransactionAsync( @@ -4890,82 +5584,6 @@ export class IZeroExContract extends BaseContract { }, }; } - /** - * Executes a batch of fills selling `fillData.inputToken` - * for `fillData.outputToken` in sequence. Refer to the - * internal variant `_batchFill` for the allowed nested - * operations. - * @param fillData Encodes the input/output tokens, the sell amount, and - * the nested operations for this batch fill. - * @param minBuyAmount The minimum amount of `fillData.outputToken` to - * buy. Reverts if this amount is not met. - */ - public batchFill( - fillData: { - inputToken: string; - outputToken: string; - sellAmount: BigNumber; - calls: Array<{ selector: string; sellAmount: BigNumber; data: string }>; - }, - minBuyAmount: BigNumber, - ): ContractTxFunctionObj { - const self = (this as any) as IZeroExContract; - - assert.isBigNumber('minBuyAmount', minBuyAmount); - const functionSignature = 'batchFill((address,address,uint256,(bytes4,uint256,bytes)[]),uint256)'; - - return { - async sendTransactionAsync( - txData?: Partial | undefined, - opts: SendTransactionOpts = { shouldValidate: true }, - ): Promise { - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( - { data: this.getABIEncodedTransactionData(), ...txData }, - 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({ - data: this.getABIEncodedTransactionData(), - ...txData, - }); - return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); - }, - async createAccessListAsync( - txData?: Partial | undefined, - defaultBlock?: BlockParam, - ): Promise { - const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ - data: this.getABIEncodedTransactionData(), - ...txData, - }); - return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); - }, - async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { - BaseContract._assertCallParams(callData, defaultBlock); - const rawCallResult = await self._performCallAsync( - { data: this.getABIEncodedTransactionData(), ...callData }, - defaultBlock, - ); - const abiEncoder = self._lookupAbiEncoder(functionSignature); - BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue(rawCallResult); - }, - getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [fillData, minBuyAmount]); - }, - }; - } /** * Fills multiple limit orders. * @param orders Array of limit orders. @@ -5154,6 +5772,95 @@ export class IZeroExContract extends BaseContract { }, }; } + /** + * Fills multiple taker-signed OTC orders. + * @param orders Array of OTC orders. + * @param makerSignatures Array of maker signatures for each order. + * @param takerSignatures Array of taker signatures for each order. + * @param unwrapWeth Array of booleans representing whether or not to + * unwrap bought WETH into ETH for each order. Should be set to + * false if the maker token is not WETH. + */ + public batchFillTakerSignedOtcOrders( + orders: Array<{ + makerToken: string; + takerToken: string; + makerAmount: BigNumber; + takerAmount: BigNumber; + maker: string; + taker: string; + txOrigin: string; + expiryAndNonce: BigNumber; + }>, + makerSignatures: Array<{ signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }>, + takerSignatures: Array<{ signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }>, + unwrapWeth: boolean[], + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isArray('orders', orders); + assert.isArray('makerSignatures', makerSignatures); + assert.isArray('takerSignatures', takerSignatures); + assert.isArray('unwrapWeth', unwrapWeth); + const functionSignature = + 'batchFillTakerSignedOtcOrders((address,address,uint128,uint128,address,address,address,uint256)[],(uint8,uint8,bytes32,bytes32)[],(uint8,uint8,bytes32,bytes32)[],bool[])'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + orders, + makerSignatures, + takerSignatures, + unwrapWeth, + ]); + }, + }; + } /** * Batch version of `getLimitOrderRelevantState()`, without reverting. * Orders that would normally cause `getLimitOrderRelevantState()` @@ -6272,8 +6979,6 @@ export class IZeroExContract extends BaseContract { * @param makerSignature The order signature from the maker. * @param takerTokenFillAmount Maximum taker token amount to fill this * order with. - * @param unwrapWeth Whether or not to unwrap bought WETH into ETH - * before transferring it to the taker. Should be set to false */ public fillOtcOrder( order: { @@ -6288,14 +6993,12 @@ export class IZeroExContract extends BaseContract { }, makerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, takerTokenFillAmount: BigNumber, - unwrapWeth: boolean, ): ContractTxFunctionObj<[BigNumber, BigNumber]> { const self = (this as any) as IZeroExContract; assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); - assert.isBoolean('unwrapWeth', unwrapWeth); const functionSignature = - 'fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128,bool)'; + 'fillOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)'; return { async sendTransactionAsync( @@ -6348,12 +7051,91 @@ export class IZeroExContract extends BaseContract { return abiEncoder.strictDecodeReturnValue<[BigNumber, BigNumber]>(rawCallResult); }, getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - order, - makerSignature, - takerTokenFillAmount, - unwrapWeth, - ]); + return self._strictEncodeArguments(functionSignature, [order, makerSignature, takerTokenFillAmount]); + }, + }; + } + /** + * Fill an OTC order for up to `takerTokenFillAmount` taker tokens. + * Unwraps bought WETH into ETH before sending it to + * the taker. + * @param order The OTC order. + * @param makerSignature The order signature from the maker. + * @param takerTokenFillAmount Maximum taker token amount to fill this + * order with. + */ + public fillOtcOrderForEth( + order: { + makerToken: string; + takerToken: string; + makerAmount: BigNumber; + takerAmount: BigNumber; + maker: string; + taker: string; + txOrigin: string; + expiryAndNonce: BigNumber; + }, + makerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, + takerTokenFillAmount: BigNumber, + ): ContractTxFunctionObj<[BigNumber, BigNumber]> { + const self = (this as any) as IZeroExContract; + + assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); + const functionSignature = + 'fillOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),uint128)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync( + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[BigNumber, BigNumber]> { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue<[BigNumber, BigNumber]>(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [order, makerSignature, takerTokenFillAmount]); }, }; } @@ -6527,9 +7309,6 @@ export class IZeroExContract extends BaseContract { * @param order The OTC order. * @param makerSignature The order signature from the maker. * @param takerSignature The order signature from the taker. - * @param unwrapWeth Whether or not to unwrap bought WETH into ETH - * before transferring it to the taker. Should be set to false if - * the maker token is not WETH. */ public fillTakerSignedOtcOrder( order: { @@ -6544,13 +7323,11 @@ export class IZeroExContract extends BaseContract { }, makerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, takerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, - unwrapWeth: boolean, - ): ContractTxFunctionObj<[BigNumber, BigNumber]> { + ): ContractTxFunctionObj { const self = (this as any) as IZeroExContract; - assert.isBoolean('unwrapWeth', unwrapWeth); const functionSignature = - 'fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32),bool)'; + 'fillTakerSignedOtcOrder((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))'; return { async sendTransactionAsync( @@ -6589,10 +7366,7 @@ export class IZeroExContract extends BaseContract { }); return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); }, - async callAsync( - callData: Partial = {}, - defaultBlock?: BlockParam, - ): Promise<[BigNumber, BigNumber]> { + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { BaseContract._assertCallParams(callData, defaultBlock); const rawCallResult = await self._performCallAsync( { data: this.getABIEncodedTransactionData(), ...callData }, @@ -6600,15 +7374,90 @@ export class IZeroExContract extends BaseContract { ); const abiEncoder = self._lookupAbiEncoder(functionSignature); BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); - return abiEncoder.strictDecodeReturnValue<[BigNumber, BigNumber]>(rawCallResult); + return abiEncoder.strictDecodeReturnValue(rawCallResult); }, getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [ - order, - makerSignature, - takerSignature, - unwrapWeth, - ]); + return self._strictEncodeArguments(functionSignature, [order, makerSignature, takerSignature]); + }, + }; + } + /** + * Fully fill an OTC order. "Meta-transaction" variant, + * requires order to be signed by both maker and taker. + * Unwraps bought WETH into ETH before sending it to + * the taker. + * @param order The OTC order. + * @param makerSignature The order signature from the maker. + * @param takerSignature The order signature from the taker. + */ + public fillTakerSignedOtcOrderForEth( + order: { + makerToken: string; + takerToken: string; + makerAmount: BigNumber; + takerAmount: BigNumber; + maker: string; + taker: string; + txOrigin: string; + expiryAndNonce: BigNumber; + }, + makerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, + takerSignature: { signatureType: number | BigNumber; v: number | BigNumber; r: string; s: string }, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + + const functionSignature = + 'fillTakerSignedOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [order, makerSignature, takerSignature]); }, }; } @@ -8007,23 +8856,23 @@ export class IZeroExContract extends BaseContract { }; } /** - * Executes a sequence of fills "hopping" through the - * path of tokens given by `fillData.tokens`. Refer to the - * internal variant `_multiHopFill` for the allowed nested - * operations. - * @param fillData Encodes the path of tokens, the sell amount, and the - * nested operations for this multi-hop fill. - * @param minBuyAmount The minimum amount of the output token to buy. - * Reverts if this amount is not met. + * Sells attached ETH for `outputToken` using the provided + * calls. + * @param outputToken The token to buy. + * @param calls The calls to use to sell the attached ETH. + * @param minBuyAmount The minimum amount of `outputToken` that must be + * bought for this function to not revert. */ - public multiHopFill( - fillData: { tokens: string[]; sellAmount: BigNumber; calls: Array<{ selector: string; data: string }> }, + public multiplexBatchSellEthForToken( + outputToken: string, + calls: Array<{ id: number | BigNumber; sellAmount: BigNumber; data: string }>, minBuyAmount: BigNumber, ): ContractTxFunctionObj { const self = (this as any) as IZeroExContract; - + assert.isString('outputToken', outputToken); + assert.isArray('calls', calls); assert.isBigNumber('minBuyAmount', minBuyAmount); - const functionSignature = 'multiHopFill((address[],uint256,(bytes4,bytes)[]),uint256)'; + const functionSignature = 'multiplexBatchSellEthForToken(address,(uint8,uint256,bytes)[],uint256)'; return { async sendTransactionAsync( @@ -8073,7 +8922,395 @@ export class IZeroExContract extends BaseContract { return abiEncoder.strictDecodeReturnValue(rawCallResult); }, getABIEncodedTransactionData(): string { - return self._strictEncodeArguments(functionSignature, [fillData, minBuyAmount]); + return self._strictEncodeArguments(functionSignature, [outputToken.toLowerCase(), calls, minBuyAmount]); + }, + }; + } + /** + * Sells `sellAmount` of the given `inputToken` for ETH + * using the provided calls. + * @param inputToken The token to sell. + * @param calls The calls to use to sell the input tokens. + * @param sellAmount The amount of `inputToken` to sell. + * @param minBuyAmount The minimum amount of ETH that must be bought for + * this function to not revert. + */ + public multiplexBatchSellTokenForEth( + inputToken: string, + calls: Array<{ id: number | BigNumber; sellAmount: BigNumber; data: string }>, + sellAmount: BigNumber, + minBuyAmount: BigNumber, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isString('inputToken', inputToken); + assert.isArray('calls', calls); + assert.isBigNumber('sellAmount', sellAmount); + assert.isBigNumber('minBuyAmount', minBuyAmount); + const functionSignature = 'multiplexBatchSellTokenForEth(address,(uint8,uint256,bytes)[],uint256,uint256)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + inputToken.toLowerCase(), + calls, + sellAmount, + minBuyAmount, + ]); + }, + }; + } + /** + * Sells `sellAmount` of the given `inputToken` for + * `outputToken` using the provided calls. + * @param inputToken The token to sell. + * @param outputToken The token to buy. + * @param calls The calls to use to sell the input tokens. + * @param sellAmount The amount of `inputToken` to sell. + * @param minBuyAmount The minimum amount of `outputToken` that must be + * bought for this function to not revert. + */ + public multiplexBatchSellTokenForToken( + inputToken: string, + outputToken: string, + calls: Array<{ id: number | BigNumber; sellAmount: BigNumber; data: string }>, + sellAmount: BigNumber, + minBuyAmount: BigNumber, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isString('inputToken', inputToken); + assert.isString('outputToken', outputToken); + assert.isArray('calls', calls); + assert.isBigNumber('sellAmount', sellAmount); + assert.isBigNumber('minBuyAmount', minBuyAmount); + const functionSignature = + 'multiplexBatchSellTokenForToken(address,address,(uint8,uint256,bytes)[],uint256,uint256)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [ + inputToken.toLowerCase(), + outputToken.toLowerCase(), + calls, + sellAmount, + minBuyAmount, + ]); + }, + }; + } + /** + * Sells attached ETH via the given sequence of tokens + * and calls. `tokens[0]` must be WETH. + * The last token in `tokens` is the output token that + * will ultimately be sent to `msg.sender` + * @param tokens The sequence of tokens to use for the sell, i.e. + * `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`. + * @param calls The sequence of calls to use for the sell. + * @param minBuyAmount The minimum amount of output tokens that must be + * bought for this function to not revert. + */ + public multiplexMultiHopSellEthForToken( + tokens: string[], + calls: Array<{ id: number | BigNumber; data: string }>, + minBuyAmount: BigNumber, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isArray('tokens', tokens); + assert.isArray('calls', calls); + assert.isBigNumber('minBuyAmount', minBuyAmount); + const functionSignature = 'multiplexMultiHopSellEthForToken(address[],(uint8,bytes)[],uint256)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [tokens, calls, minBuyAmount]); + }, + }; + } + /** + * Sells `sellAmount` of the input token (`tokens[0]`) + * for ETH via the given sequence of tokens and calls. + * The last token in `tokens` must be WETH. + * @param tokens The sequence of tokens to use for the sell, i.e. + * `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`. + * @param calls The sequence of calls to use for the sell. + * @param minBuyAmount The minimum amount of ETH that must be bought for + * this function to not revert. + */ + public multiplexMultiHopSellTokenForEth( + tokens: string[], + calls: Array<{ id: number | BigNumber; data: string }>, + sellAmount: BigNumber, + minBuyAmount: BigNumber, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isArray('tokens', tokens); + assert.isArray('calls', calls); + assert.isBigNumber('sellAmount', sellAmount); + assert.isBigNumber('minBuyAmount', minBuyAmount); + const functionSignature = 'multiplexMultiHopSellTokenForEth(address[],(uint8,bytes)[],uint256,uint256)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [tokens, calls, sellAmount, minBuyAmount]); + }, + }; + } + /** + * Sells `sellAmount` of the input token (`tokens[0]`) + * via the given sequence of tokens and calls. + * The last token in `tokens` is the output token that + * will ultimately be sent to `msg.sender` + * @param tokens The sequence of tokens to use for the sell, i.e. + * `tokens[i]` will be sold for `tokens[i+1]` via `calls[i]`. + * @param calls The sequence of calls to use for the sell. + * @param minBuyAmount The minimum amount of output tokens that must be + * bought for this function to not revert. + */ + public multiplexMultiHopSellTokenForToken( + tokens: string[], + calls: Array<{ id: number | BigNumber; data: string }>, + sellAmount: BigNumber, + minBuyAmount: BigNumber, + ): ContractTxFunctionObj { + const self = (this as any) as IZeroExContract; + assert.isArray('tokens', tokens); + assert.isArray('calls', calls); + assert.isBigNumber('sellAmount', sellAmount); + assert.isBigNumber('minBuyAmount', minBuyAmount); + const functionSignature = 'multiplexMultiHopSellTokenForToken(address[],(uint8,bytes)[],uint256,uint256)'; + + return { + async sendTransactionAsync( + txData?: Partial | undefined, + opts: SendTransactionOpts = { shouldValidate: true }, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync( + { data: this.getABIEncodedTransactionData(), ...txData }, + 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({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + }, + async createAccessListAsync( + txData?: Partial | undefined, + defaultBlock?: BlockParam, + ): Promise { + const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({ + data: this.getABIEncodedTransactionData(), + ...txData, + }); + return self._web3Wrapper.createAccessListAsync(txDataWithDefaults, defaultBlock); + }, + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + BaseContract._assertCallParams(callData, defaultBlock); + const rawCallResult = await self._performCallAsync( + { data: this.getABIEncodedTransactionData(), ...callData }, + defaultBlock, + ); + const abiEncoder = self._lookupAbiEncoder(functionSignature); + BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder); + return abiEncoder.strictDecodeReturnValue(rawCallResult); + }, + getABIEncodedTransactionData(): string { + return self._strictEncodeArguments(functionSignature, [tokens, calls, sellAmount, minBuyAmount]); }, }; } diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 5ad93d8bcc..4535ffffb1 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -126,7 +126,6 @@ export { IZeroExContract, IZeroExEventArgs, IZeroExEvents, - IZeroExExpiredRfqOrderEventArgs, IZeroExLiquidityProviderSwapEventArgs, IZeroExMetaTransactionExecutedEventArgs, IZeroExMigratedEventArgs, diff --git a/yarn.lock b/yarn.lock index 7230b23c5c..150efebfc1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -871,21 +871,6 @@ ethereum-types "^3.5.0" ethereumjs-util "^7.0.10" -"@0x/contracts-zero-ex@^0.27.1": - version "0.27.1" - resolved "https://registry.yarnpkg.com/@0x/contracts-zero-ex/-/contracts-zero-ex-0.27.1.tgz#968fe9d8134972cb464f7c4a33c4e4089ba9218e" - integrity sha512-IDc0pmMtl/92hkhOqlu+dDyIvLtGtwjjE/kdS6x+jwOyNG8sn5sbkwZ3u3PbHk72dND7E0I7BBY9VEXTB1PY/Q== - dependencies: - "@0x/base-contract" "^6.4.0" - "@0x/protocol-utils" "^1.8.1" - "@0x/subproviders" "^6.5.3" - "@0x/types" "^3.3.3" - "@0x/typescript-typings" "^5.2.0" - "@0x/utils" "^6.4.3" - "@0x/web3-wrapper" "^7.5.3" - ethereum-types "^3.5.0" - ethereumjs-util "^7.0.10" - "@0x/dev-utils@^4.2.9": version "4.2.9" resolved "https://registry.yarnpkg.com/@0x/dev-utils/-/dev-utils-4.2.9.tgz#b048b139b0055ef3702682c42ccc2a3788a49f5d" @@ -1115,35 +1100,6 @@ solc "^0.5.5" solidity-parser-antlr "^0.4.2" -"@0x/subproviders@^6.5.3": - version "6.5.3" - resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.5.3.tgz#aec86903527c8f972beec1bc2fbda5fdba361235" - dependencies: - "@0x/assert" "^3.0.27" - "@0x/types" "^3.3.3" - "@0x/typescript-typings" "^5.2.0" - "@0x/utils" "^6.4.3" - "@0x/web3-wrapper" "^7.5.3" - "@ethereumjs/common" "^2.2.0" - "@ethereumjs/tx" "^3.1.3" - "@ledgerhq/hw-app-eth" "^4.3.0" - "@ledgerhq/hw-transport-u2f" "4.24.0" - "@types/hdkey" "^0.7.0" - "@types/node" "12.12.54" - "@types/web3-provider-engine" "^14.0.0" - bip39 "^2.5.0" - bn.js "^4.11.8" - ethereum-types "^3.5.0" - ethereumjs-util "^7.0.10" - ganache-core "^2.13.2" - hdkey "^0.7.1" - json-rpc-error "2.0.0" - lodash "^4.17.11" - semaphore-async-await "^1.5.1" - web3-provider-engine "14.0.6" - optionalDependencies: - "@ledgerhq/hw-transport-node-hid" "^4.3.0" - "@0x/subproviders@^6.6.0": version "6.6.0" resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.6.0.tgz#1743d44ae5e2be9ec48caddbf0f1a580f1672d32" @@ -1442,13 +1398,6 @@ web3 "1.2.1" web3-typescript-typings "^0.10.2" -"@ethereumjs/common@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.2.0.tgz#850a3e3e594ee707ad8d44a11e8152fb62450535" - dependencies: - crc-32 "^1.2.0" - ethereumjs-util "^7.0.9" - "@ethereumjs/common@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.4.0.tgz#2d67f6e6ba22246c5c89104e6b9a119fb3039766" @@ -1457,13 +1406,6 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.0" -"@ethereumjs/tx@^3.1.3": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.1.4.tgz#04cf9e9406da5f04a1a26c458744641f4b4b8dd0" - dependencies: - "@ethereumjs/common" "^2.2.0" - ethereumjs-util "^7.0.10" - "@ethereumjs/tx@^3.3.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.0.tgz#14ed1b7fa0f28e1cd61e3ecbdab824205f6a4378" @@ -6108,7 +6050,7 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum rlp "^2.0.0" safe-buffer "^5.1.1" -ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.9: +ethereumjs-util@^7.0.10: version "7.0.10" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f" dependencies: