Update ExchangeProxySwapQuoteConsumer for MultiplexV2 (#282)

* Update ExchangeProxySwapQuoteConsumer for MultiplexV2

* Move TransformERC20FeatureContract instance into private readonly
This commit is contained in:
mzhu25 2021-09-29 16:02:13 -07:00 committed by GitHub
parent a883139220
commit 1849b1bb9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2130 additions and 490 deletions

View File

@ -1,4 +1,13 @@
[ [
{
"version": "0.29.0",
"changes": [
{
"note": "Export TransformERC20FeatureContract",
"pr": 282
}
]
},
{ {
"timestamp": 1631710679, "timestamp": 1631710679,
"version": "0.28.5", "version": "0.28.5",

View File

@ -47,6 +47,7 @@ export {
MultiplexFeatureContract, MultiplexFeatureContract,
PayTakerTransformerContract, PayTakerTransformerContract,
PositiveSlippageFeeTransformerContract, PositiveSlippageFeeTransformerContract,
TransformERC20FeatureContract,
WethTransformerContract, WethTransformerContract,
ZeroExContract, ZeroExContract,
} from './wrappers'; } from './wrappers';

View File

@ -1,4 +1,13 @@
[ [
{
"version": "16.28.0",
"changes": [
{
"note": "Update ExchangeProxySwapQuoteConsumer for Multiplex V2 and friends",
"pr": 282
}
]
},
{ {
"version": "16.27.5", "version": "16.27.5",
"changes": [ "changes": [

View File

@ -63,7 +63,7 @@
"@0x/contract-addresses": "^6.7.0", "@0x/contract-addresses": "^6.7.0",
"@0x/contract-wrappers": "^13.17.7", "@0x/contract-wrappers": "^13.17.7",
"@0x/contracts-erc20": "^3.3.20", "@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/dev-utils": "^4.2.9",
"@0x/json-schemas": "^6.3.0", "@0x/json-schemas": "^6.3.0",
"@0x/protocol-utils": "^1.9.0", "@0x/protocol-utils": "^1.9.0",

View File

@ -1,6 +1,6 @@
import { ChainId, ContractAddresses } from '@0x/contract-addresses'; import { ChainId, ContractAddresses } from '@0x/contract-addresses';
import { IZeroExContract, WETH9Contract } from '@0x/contract-wrappers'; import { IZeroExContract } from '@0x/contract-wrappers';
import { MultiplexFeatureContract } from '@0x/contracts-zero-ex'; import { TransformERC20FeatureContract } from '@0x/contracts-zero-ex';
import { import {
encodeAffiliateFeeTransformerData, encodeAffiliateFeeTransformerData,
encodeCurveLiquidityProviderData, encodeCurveLiquidityProviderData,
@ -51,6 +51,7 @@ import {
import { import {
multiplexPlpEncoder, multiplexPlpEncoder,
multiplexRfqEncoder, multiplexRfqEncoder,
MultiplexSubcall,
multiplexTransformERC20Encoder, multiplexTransformERC20Encoder,
multiplexUniswapEncoder, multiplexUniswapEncoder,
} from './multiplex_encoders'; } from './multiplex_encoders';
@ -82,7 +83,6 @@ const FAKE_PROVIDER: any = {
return; return;
}, },
}; };
const DUMMY_WETH_CONTRACT = new WETH9Contract(NULL_ADDRESS, FAKE_PROVIDER);
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
public readonly chainId: ChainId; public readonly chainId: ChainId;
@ -95,7 +95,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}; };
private readonly _exchangeProxy: IZeroExContract; private readonly _exchangeProxy: IZeroExContract;
private readonly _multiplex: MultiplexFeatureContract; private readonly _transformERC20Feature: TransformERC20FeatureContract;
constructor(public readonly contractAddresses: ContractAddresses, options: Partial<SwapQuoteConsumerOpts> = {}) { constructor(public readonly contractAddresses: ContractAddresses, options: Partial<SwapQuoteConsumerOpts> = {}) {
const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
@ -103,7 +103,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
this.chainId = chainId; this.chainId = chainId;
this.contractAddresses = contractAddresses; this.contractAddresses = contractAddresses;
this._exchangeProxy = new IZeroExContract(contractAddresses.exchangeProxy, FAKE_PROVIDER); 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 = { this.transformerNonces = {
wethTransformer: findTransformerNonce( wethTransformer: findTransformerNonce(
contractAddresses.transformers.wethTransformer, contractAddresses.transformers.wethTransformer,
@ -338,7 +338,10 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) { if (this.chainId === ChainId.Mainnet && isMultiplexBatchFillCompatible(quote, optsWithDefaults)) {
return { return {
calldataHexString: this._encodeMultiplexBatchFillCalldata({ ...quote, orders: slippedOrders }), calldataHexString: this._encodeMultiplexBatchFillCalldata(
{ ...quote, orders: slippedOrders },
optsWithDefaults,
),
ethAmount, ethAmount,
toAddress: this._exchangeProxy.address, toAddress: this._exchangeProxy.address,
allowanceTarget: 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. // The final transformer will send all funds to the taker.
transforms.push({ transforms.push({
deploymentNonce: this.transformerNonces.payTakerTransformer, deploymentNonce: this.transformerNonces.payTakerTransformer,
data: encodePayTakerTransformerData({ data: encodePayTakerTransformerData({
tokens: [sellToken, buyToken, ETH_TOKEN_ADDRESS].concat(quote.isTwoHop ? intermediateToken : []), tokens: payTakerTokens,
amounts: [], amounts: [],
}), }),
}); });
const calldataHexString = this._transformERC20Feature
const calldataHexString = this._exchangeProxy .transformERC20Staging(
.transformERC20(
isFromETH ? ETH_TOKEN_ADDRESS : sellToken, isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
isToETH ? ETH_TOKEN_ADDRESS : buyToken, isToETH ? ETH_TOKEN_ADDRESS : buyToken,
shouldSellEntireBalance ? MAX_UINT256 : sellAmount, shouldSellEntireBalance ? MAX_UINT256 : sellAmount,
@ -509,8 +522,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
throw new Error('Execution not supported for Exchange Proxy quotes'); throw new Error('Execution not supported for Exchange Proxy quotes');
} }
private _encodeMultiplexBatchFillCalldata(quote: SwapQuote): string { private _encodeMultiplexBatchFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string {
const wrappedBatchCalls = []; const subcalls = [];
for_loop: for (const [i, order] of quote.orders.entries()) { for_loop: for (const [i, order] of quote.orders.entries()) {
switch_statement: switch (order.source) { switch_statement: switch (order.source) {
case ERC20BridgeSource.Native: case ERC20BridgeSource.Native:
@ -519,8 +532,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
// before calling this function. // before calling this function.
throw new Error('Multiplex batch fill only supported for RFQ native orders'); throw new Error('Multiplex batch fill only supported for RFQ native orders');
} }
wrappedBatchCalls.push({ subcalls.push({
selector: this._exchangeProxy.getSelector('_fillRfqOrder'), id: MultiplexSubcall.Rfq,
sellAmount: order.takerAmount, sellAmount: order.takerAmount,
data: multiplexRfqEncoder.encode({ data: multiplexRfqEncoder.encode({
order: order.fillData.order, order: order.fillData.order,
@ -530,8 +543,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
break switch_statement; break switch_statement;
case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.UniswapV2:
case ERC20BridgeSource.SushiSwap: case ERC20BridgeSource.SushiSwap:
wrappedBatchCalls.push({ subcalls.push({
selector: this._multiplex.getSelector('_sellToUniswap'), id: MultiplexSubcall.UniswapV2,
sellAmount: order.takerAmount, sellAmount: order.takerAmount,
data: multiplexUniswapEncoder.encode({ data: multiplexUniswapEncoder.encode({
tokens: (order.fillData as UniswapV2FillData).tokenAddressPath, tokens: (order.fillData as UniswapV2FillData).tokenAddressPath,
@ -540,8 +553,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}); });
break switch_statement; break switch_statement;
case ERC20BridgeSource.LiquidityProvider: case ERC20BridgeSource.LiquidityProvider:
wrappedBatchCalls.push({ subcalls.push({
selector: this._multiplex.getSelector('_sellToLiquidityProvider'), id: MultiplexSubcall.LiquidityProvider,
sellAmount: order.takerAmount, sellAmount: order.takerAmount,
data: multiplexPlpEncoder.encode({ data: multiplexPlpEncoder.encode({
provider: (order.fillData as LiquidityProviderFillData).poolAddress, provider: (order.fillData as LiquidityProviderFillData).poolAddress,
@ -551,8 +564,8 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
break switch_statement; break switch_statement;
case ERC20BridgeSource.UniswapV3: case ERC20BridgeSource.UniswapV3:
const fillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData; const fillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
wrappedBatchCalls.push({ subcalls.push({
selector: this._exchangeProxy.getSelector('sellTokenForTokenToUniswapV3'), id: MultiplexSubcall.UniswapV3,
sellAmount: order.takerAmount, sellAmount: order.takerAmount,
data: fillData.uniswapPath, data: fillData.uniswapPath,
}); });
@ -571,54 +584,59 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
{ {
deploymentNonce: this.transformerNonces.payTakerTransformer, deploymentNonce: this.transformerNonces.payTakerTransformer,
data: encodePayTakerTransformerData({ data: encodePayTakerTransformerData({
tokens: [quote.takerToken, quote.makerToken], tokens: [quote.takerToken],
amounts: [], amounts: [],
}), }),
}, },
]; ];
wrappedBatchCalls.push({ subcalls.push({
selector: this._exchangeProxy.getSelector('_transformERC20'), id: MultiplexSubcall.TransformERC20,
sellAmount: BigNumber.sum(...quote.orders.slice(i).map(o => o.takerAmount)), sellAmount: BigNumber.sum(...quote.orders.slice(i).map(o => o.takerAmount)),
data: multiplexTransformERC20Encoder.encode({ data: multiplexTransformERC20Encoder.encode({
transformations, transformations,
ethValue: constants.ZERO_AMOUNT,
}), }),
}); });
break for_loop; break for_loop;
} }
} }
return this._exchangeProxy if (opts.isFromETH) {
.batchFill( return this._exchangeProxy
{ .multiplexBatchSellEthForToken(quote.makerToken, subcalls, quote.worstCaseQuoteInfo.makerAmount)
inputToken: quote.takerToken, .getABIEncodedTransactionData();
outputToken: quote.makerToken, } else if (opts.isToETH) {
sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount, return this._exchangeProxy
calls: wrappedBatchCalls, .multiplexBatchSellTokenForEth(
}, quote.takerToken,
quote.worstCaseQuoteInfo.makerAmount, subcalls,
) quote.worstCaseQuoteInfo.totalTakerAmount,
.getABIEncodedTransactionData(); 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 { private _encodeMultiplexMultiHopFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string {
const wrappedMultiHopCalls = []; const subcalls = [];
const tokens: string[] = [];
if (opts.isFromETH) {
wrappedMultiHopCalls.push({
selector: DUMMY_WETH_CONTRACT.getSelector('deposit'),
data: NULL_BYTES,
});
tokens.push(ETH_TOKEN_ADDRESS);
}
const [firstHopOrder, secondHopOrder] = quote.orders; const [firstHopOrder, secondHopOrder] = quote.orders;
const intermediateToken = firstHopOrder.makerToken; const intermediateToken = firstHopOrder.makerToken;
tokens.push(quote.takerToken, intermediateToken, quote.makerToken); const tokens = [quote.takerToken, intermediateToken, quote.makerToken];
for (const order of [firstHopOrder, secondHopOrder]) { for (const order of [firstHopOrder, secondHopOrder]) {
switch (order.source) { switch (order.source) {
case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.UniswapV2:
case ERC20BridgeSource.SushiSwap: case ERC20BridgeSource.SushiSwap:
wrappedMultiHopCalls.push({ subcalls.push({
selector: this._multiplex.getSelector('_sellToUniswap'), id: MultiplexSubcall.UniswapV2,
data: multiplexUniswapEncoder.encode({ data: multiplexUniswapEncoder.encode({
tokens: (order.fillData as UniswapV2FillData).tokenAddressPath, tokens: (order.fillData as UniswapV2FillData).tokenAddressPath,
isSushi: order.source === ERC20BridgeSource.SushiSwap, isSushi: order.source === ERC20BridgeSource.SushiSwap,
@ -626,39 +644,49 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}); });
break; break;
case ERC20BridgeSource.LiquidityProvider: case ERC20BridgeSource.LiquidityProvider:
wrappedMultiHopCalls.push({ subcalls.push({
selector: this._multiplex.getSelector('_sellToLiquidityProvider'), id: MultiplexSubcall.LiquidityProvider,
data: multiplexPlpEncoder.encode({ data: multiplexPlpEncoder.encode({
provider: (order.fillData as LiquidityProviderFillData).poolAddress, provider: (order.fillData as LiquidityProviderFillData).poolAddress,
auxiliaryData: NULL_BYTES, auxiliaryData: NULL_BYTES,
}), }),
}); });
break; break;
case ERC20BridgeSource.UniswapV3:
subcalls.push({
id: MultiplexSubcall.UniswapV3,
data: (order.fillData as FinalUniswapV3FillData).uniswapPath,
});
break;
default: default:
// Note: we'll need to redeploy TransformERC20Feature before we can
// use other sources
// Should never happen because we check `isMultiplexMultiHopFillCompatible` // Should never happen because we check `isMultiplexMultiHopFillCompatible`
// before calling this function. // before calling this function.
throw new Error(`Multiplex multi-hop unsupported source: ${order.source}`); throw new Error(`Multiplex multi-hop unsupported source: ${order.source}`);
} }
} }
if (opts.isToETH) { if (opts.isFromETH) {
wrappedMultiHopCalls.push({ return this._exchangeProxy
selector: DUMMY_WETH_CONTRACT.getSelector('withdraw'), .multiplexMultiHopSellEthForToken(tokens, subcalls, quote.worstCaseQuoteInfo.makerAmount)
data: NULL_BYTES, .getABIEncodedTransactionData();
}); } else if (opts.isToETH) {
tokens.push(ETH_TOKEN_ADDRESS); return this._exchangeProxy
} .multiplexMultiHopSellTokenForEth(
return this._exchangeProxy
.multiHopFill(
{
tokens, tokens,
sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount, subcalls,
calls: wrappedMultiHopCalls, quote.worstCaseQuoteInfo.totalTakerAmount,
}, quote.worstCaseQuoteInfo.makerAmount,
quote.worstCaseQuoteInfo.makerAmount, )
) .getABIEncodedTransactionData();
.getABIEncodedTransactionData(); } else {
return this._exchangeProxy
.multiplexMultiHopSellTokenForToken(
tokens,
subcalls,
quote.worstCaseQuoteInfo.totalTakerAmount,
quote.worstCaseQuoteInfo.makerAmount,
)
.getABIEncodedTransactionData();
}
} }
} }

View File

@ -1,6 +1,17 @@
import { RfqOrder, SIGNATURE_ABI } from '@0x/protocol-utils'; import { RfqOrder, SIGNATURE_ABI } from '@0x/protocol-utils';
import { AbiEncoder } from '@0x/utils'; import { AbiEncoder } from '@0x/utils';
export enum MultiplexSubcall {
Invalid,
Rfq,
Otc,
UniswapV2,
UniswapV3,
LiquidityProvider,
TransformERC20,
BatchSell,
MultiHopSell,
}
export const multiplexTransformERC20Encoder = AbiEncoder.create([ export const multiplexTransformERC20Encoder = AbiEncoder.create([
{ {
name: 'transformations', name: 'transformations',
@ -10,7 +21,6 @@ export const multiplexTransformERC20Encoder = AbiEncoder.create([
{ name: 'data', type: 'bytes' }, { name: 'data', type: 'bytes' },
], ],
}, },
{ name: 'ethValue', type: 'uint256' },
]); ]);
export const multiplexRfqEncoder = AbiEncoder.create([ export const multiplexRfqEncoder = AbiEncoder.create([
{ name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI }, { name: 'order', type: 'tuple', components: RfqOrder.STRUCT_ABI },

View File

@ -32,10 +32,6 @@ export function isMultiplexBatchFillCompatible(quote: SwapQuote, opts: ExchangeP
if (quote.isTwoHop) { if (quote.isTwoHop) {
return false; 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)) { if (quote.orders.map(o => o.type).includes(FillQuoteTransformerOrderType.Limit)) {
return false; return false;
} }
@ -49,6 +45,7 @@ const MULTIPLEX_MULTIHOP_FILL_SOURCES = [
ERC20BridgeSource.UniswapV2, ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.LiquidityProvider, ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.UniswapV3,
]; ];
/** /**

View File

@ -186,7 +186,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
); );
} }
const transformERC20Encoder = AbiEncoder.createMethod('transformERC20', [ const transformERC20Encoder = AbiEncoder.createMethod('transformERC20Staging', [
{ type: 'address', name: 'inputToken' }, { type: 'address', name: 'inputToken' },
{ type: 'address', name: 'outputToken' }, { type: 'address', name: 'outputToken' },
{ type: 'uint256', name: 'inputTokenAmount' }, { type: 'uint256', name: 'inputTokenAmount' },
@ -261,7 +261,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
expect(payTakerTransformerData.amounts).to.deep.eq([]); 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 () => { it('can produce a buy quote', async () => {
@ -292,7 +292,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
expect(payTakerTransformerData.amounts).to.deep.eq([]); 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 () => { it('ERC20 -> ERC20 does not have a WETH transformer', async () => {
@ -437,12 +437,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
expect(secondHopFillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); expect(secondHopFillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[2].data); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[2].data);
expect(payTakerTransformerData.amounts).to.deep.eq([]); expect(payTakerTransformerData.amounts).to.deep.eq([]);
expect(payTakerTransformerData.tokens).to.deep.eq([ expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, INTERMEDIATE_TOKEN, ETH_TOKEN_ADDRESS]);
TAKER_TOKEN,
MAKER_TOKEN,
ETH_TOKEN_ADDRESS,
INTERMEDIATE_TOKEN,
]);
}); });
// it.skip('Uses the `LiquidityProviderFeature` if given a single LiquidityProvider order', async () => { // it.skip('Uses the `LiquidityProviderFeature` if given a single LiquidityProvider order', async () => {
// const quote = { // const quote = {
@ -504,7 +499,7 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN); expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data); const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
expect(payTakerTransformerData.amounts).to.deep.eq([]); 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]);
}); });
}); });
}); });

View File

@ -1,4 +1,13 @@
[ [
{
"version": "3.16.0",
"changes": [
{
"note": "Update IZeroEx and ITransformERC20 artifacts",
"pr": 282
}
]
},
{ {
"timestamp": 1631710679, "timestamp": 1631710679,
"version": "3.15.1", "version": "3.15.1",

View File

@ -1,6 +1,6 @@
{ {
"schemaVersion": "2.0.0", "schemaVersion": "2.0.0",
"contractName": "ITransformERC20", "contractName": "ITransformERC20Feature",
"compilerOutput": { "compilerOutput": {
"abi": [ "abi": [
{ {
@ -43,14 +43,14 @@
{ "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" }, { "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" },
{ "internalType": "bytes", "name": "data", "type": "bytes" } { "internalType": "bytes", "name": "data", "type": "bytes" }
], ],
"internalType": "struct ITransformERC20.Transformation[]", "internalType": "struct ITransformERC20Feature.Transformation[]",
"name": "transformations", "name": "transformations",
"type": "tuple[]" "type": "tuple[]"
}, },
{ "internalType": "bytes32", "name": "callDataHash", "type": "bytes32" }, { "internalType": "bool", "name": "useSelfBalance", "type": "bool" },
{ "internalType": "bytes", "name": "callDataSignature", "type": "bytes" } { "internalType": "address payable", "name": "recipient", "type": "address" }
], ],
"internalType": "struct ITransformERC20.TransformERC20Args", "internalType": "struct ITransformERC20Feature.TransformERC20Args",
"name": "args", "name": "args",
"type": "tuple" "type": "tuple"
} }
@ -113,7 +113,7 @@
{ "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" }, { "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" },
{ "internalType": "bytes", "name": "data", "type": "bytes" } { "internalType": "bytes", "name": "data", "type": "bytes" }
], ],
"internalType": "struct ITransformERC20.Transformation[]", "internalType": "struct ITransformERC20Feature.Transformation[]",
"name": "transformations", "name": "transformations",
"type": "tuple[]" "type": "tuple[]"
} }
@ -148,7 +148,7 @@
}, },
"kind": "dev", "kind": "dev",
"methods": { "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.", "details": "Internal version of `transformERC20()`. Only callable from within.",
"params": { "args": "A `TransformERC20Args` struct." }, "params": { "args": "A `TransformERC20Args` struct." },
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." } "returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." }
@ -212,7 +212,8 @@
"evm.bytecode.object", "evm.bytecode.object",
"evm.bytecode.sourceMap", "evm.bytecode.sourceMap",
"evm.deployedBytecode.object", "evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap" "evm.deployedBytecode.sourceMap",
"evm.methodIdentifiers"
] ]
} }
}, },

View File

@ -3,16 +3,6 @@
"contractName": "IZeroEx", "contractName": "IZeroEx",
"compilerOutput": { "compilerOutput": {
"abi": [ "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, "anonymous": false,
"inputs": [ "inputs": [
@ -49,11 +39,26 @@
{ {
"anonymous": false, "anonymous": false,
"inputs": [ "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": "inputTokenAmount", "type": "uint256" },
{ "indexed": false, "internalType": "uint256", "name": "outputTokenAmount", "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" } { "indexed": false, "internalType": "address", "name": "recipient", "type": "address" }
], ],
"name": "LiquidityProviderSwap", "name": "LiquidityProviderSwap",
@ -110,10 +115,10 @@
{ {
"indexed": false, "indexed": false,
"internalType": "uint128", "internalType": "uint128",
"name": "takerTokenFilledAmount", "name": "makerTokenFilledAmount",
"type": "uint128" "type": "uint128"
}, },
{ "indexed": false, "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" } { "indexed": false, "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" }
], ],
"name": "OtcOrderFilled", "name": "OtcOrderFilled",
"type": "event" "type": "event"
@ -268,6 +273,51 @@
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "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": [ "inputs": [
{ {
@ -303,7 +353,9 @@
"type": "tuple" "type": "tuple"
}, },
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }, { "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", "name": "_fillRfqOrder",
"outputs": [ "outputs": [
@ -313,6 +365,18 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "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": [ "inputs": [
{ {
@ -330,7 +394,9 @@
"internalType": "struct ITransformERC20Feature.Transformation[]", "internalType": "struct ITransformERC20Feature.Transformation[]",
"name": "transformations", "name": "transformations",
"type": "tuple[]" "type": "tuple[]"
} },
{ "internalType": "bool", "name": "useSelfBalance", "type": "bool" },
{ "internalType": "address payable", "name": "recipient", "type": "address" }
], ],
"internalType": "struct ITransformERC20Feature.TransformERC20Args", "internalType": "struct ITransformERC20Feature.TransformERC20Args",
"name": "args", "name": "args",
@ -480,35 +546,6 @@
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "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": [ "inputs": [
{ {
@ -601,6 +638,60 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "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": [ "inputs": [
{ {
@ -1026,8 +1117,7 @@
"name": "makerSignature", "name": "makerSignature",
"type": "tuple" "type": "tuple"
}, },
{ "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }, { "internalType": "uint128", "name": "takerTokenFillAmount", "type": "uint128" }
{ "internalType": "bool", "name": "unwrapWeth", "type": "bool" }
], ],
"name": "fillOtcOrder", "name": "fillOtcOrder",
"outputs": [ "outputs": [
@ -1037,6 +1127,48 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "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": [ "inputs": [
{ {
@ -1168,14 +1300,63 @@
"internalType": "struct LibSignature.Signature", "internalType": "struct LibSignature.Signature",
"name": "takerSignature", "name": "takerSignature",
"type": "tuple" "type": "tuple"
}, }
{ "internalType": "bool", "name": "unwrapWeth", "type": "bool" }
], ],
"name": "fillTakerSignedOtcOrder", "name": "fillTakerSignedOtcOrder",
"outputs": [ "outputs": [],
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" }, "stateMutability": "nonpayable",
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" } "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", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
@ -1604,31 +1785,150 @@
}, },
{ {
"inputs": [ "inputs": [
{ "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" },
{ {
"components": [ "components": [
{ "internalType": "address[]", "name": "tokens", "type": "address[]" },
{ "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
{ {
"components": [ "internalType": "enum IMultiplexFeature.MultiplexSubcall",
{ "internalType": "bytes4", "name": "selector", "type": "bytes4" }, "name": "id",
{ "internalType": "bytes", "name": "data", "type": "bytes" } "type": "uint8"
], },
"internalType": "struct IMultiplexFeature.WrappedMultiHopCall[]", { "internalType": "uint256", "name": "sellAmount", "type": "uint256" },
"name": "calls", { "internalType": "bytes", "name": "data", "type": "bytes" }
"type": "tuple[]"
}
], ],
"internalType": "struct IMultiplexFeature.MultiHopFillData", "internalType": "struct IMultiplexFeature.BatchSellSubcall[]",
"name": "fillData", "name": "calls",
"type": "tuple" "type": "tuple[]"
}, },
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" } { "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" }
], ],
"name": "multiHopFill", "name": "multiplexBatchSellEthForToken",
"outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }], "outputs": [{ "internalType": "uint256", "name": "boughtAmount", "type": "uint256" }],
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "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": [], "inputs": [],
"name": "owner", "name": "owner",
@ -1819,20 +2119,47 @@
"takerTokenFilledAmount": "How much maker token was filled." "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.", "details": "Fill an RFQ order. Internal variant.",
"params": { "params": {
"order": "The RFQ order.", "order": "The RFQ order.",
"recipient": "The recipient of the maker tokens.",
"signature": "The order signature.", "signature": "The order signature.",
"taker": "The order taker.", "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": { "returns": {
"makerTokenFilledAmount": "How much maker token was filled.", "makerTokenFilledAmount": "How much maker token was filled.",
"takerTokenFilledAmount": "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.", "details": "Internal version of `transformERC20()`. Only callable from within.",
"params": { "args": "A `TransformERC20Args` struct." }, "params": { "args": "A `TransformERC20Args` struct." },
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." } "returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." }
@ -1887,14 +2214,6 @@
}, },
"returns": { "returnResults": "The ABI-encoded results of the underlying calls." } "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)": { "batchFillLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[],(uint8,uint8,bytes32,bytes32)[],uint128[],bool)": {
"details": "Fills multiple limit orders.", "details": "Fills multiple limit orders.",
"params": { "params": {
@ -1921,6 +2240,18 @@
"takerTokenFilledAmounts": "Array of amounts filled, in taker token." "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)[])": { "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.", "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." }, "params": { "orders": "The limit orders.", "signatures": "The order signatures." },
@ -2027,13 +2358,24 @@
}, },
"returns": { "makerTokenFilledAmount": "How much maker token was filled." } "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.", "details": "Fill an OTC order for up to `takerTokenFillAmount` taker tokens.",
"params": { "params": {
"makerSignature": "The order signature from the maker.", "makerSignature": "The order signature from the maker.",
"order": "The OTC order.", "order": "The OTC order.",
"takerTokenFillAmount": "Maximum taker token amount to fill this order with.", "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" },
"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": { "returns": {
"makerTokenFilledAmount": "How much maker token was filled.", "makerTokenFilledAmount": "How much maker token was filled.",
@ -2060,17 +2402,20 @@
"takerTokenFilledAmount": "How much maker token was filled." "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.", "details": "Fully fill an OTC order. \"Meta-transaction\" variant, requires order to be signed by both maker and taker.",
"params": { "params": {
"makerSignature": "The order signature from the maker.", "makerSignature": "The order signature from the maker.",
"order": "The OTC order.", "order": "The OTC order.",
"takerSignature": "The order signature from the taker.", "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": { "fillTakerSignedOtcOrderForEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32),(uint8,uint8,bytes32,bytes32))": {
"makerTokenFilledAmount": "How much maker token was filled.", "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.",
"takerTokenFilledAmount": "How much taker token was filled." "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))": { "getLimitOrderHash((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": {
@ -2184,13 +2529,62 @@
"target": "The migrator contract address." "target": "The migrator contract address."
} }
}, },
"multiHopFill((address[],uint256,(bytes4,bytes)[]),uint256)": { "multiplexBatchSellEthForToken(address,(uint8,uint256,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.", "details": "Sells attached ETH for `outputToken` using the provided calls.",
"params": { "params": {
"fillData": "Encodes the path of tokens, the sell amount, and the nested operations for this multi-hop fill.", "calls": "The calls to use to sell the attached ETH.",
"minBuyAmount": "The minimum amount of the output token to buy. Reverts if this amount is not met." "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()": { "owner()": {
"details": "The owner of this contract.", "details": "The owner of this contract.",

View File

@ -1,4 +1,13 @@
[ [
{
"version": "13.18.0",
"changes": [
{
"note": "Update IZeroEx and ITransformERC20 wrappers",
"pr": 282
}
]
},
{ {
"timestamp": 1631710679, "timestamp": 1631710679,
"version": "13.17.7", "version": "13.17.7",

View File

@ -269,12 +269,12 @@ export class ITransformERC20Contract extends BaseContract {
], ],
}, },
{ {
name: 'callDataHash', name: 'useSelfBalance',
type: 'bytes32', type: 'bool',
}, },
{ {
name: 'callDataSignature', name: 'recipient',
type: 'bytes', type: 'address',
}, },
], ],
}, },
@ -497,13 +497,13 @@ export class ITransformERC20Contract extends BaseContract {
inputTokenAmount: BigNumber; inputTokenAmount: BigNumber;
minOutputTokenAmount: BigNumber; minOutputTokenAmount: BigNumber;
transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>; transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>;
callDataHash: string; useSelfBalance: boolean;
callDataSignature: string; recipient: string;
}): ContractTxFunctionObj<BigNumber> { }): ContractTxFunctionObj<BigNumber> {
const self = (this as any) as ITransformERC20Contract; const self = (this as any) as ITransformERC20Contract;
const functionSignature = const functionSignature =
'_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bytes32,bytes))'; '_transformERC20((address,address,address,uint256,uint256,(uint32,bytes)[],bool,address))';
return { return {
async sendTransactionAsync( async sendTransactionAsync(

File diff suppressed because it is too large Load Diff

View File

@ -126,7 +126,6 @@ export {
IZeroExContract, IZeroExContract,
IZeroExEventArgs, IZeroExEventArgs,
IZeroExEvents, IZeroExEvents,
IZeroExExpiredRfqOrderEventArgs,
IZeroExLiquidityProviderSwapEventArgs, IZeroExLiquidityProviderSwapEventArgs,
IZeroExMetaTransactionExecutedEventArgs, IZeroExMetaTransactionExecutedEventArgs,
IZeroExMigratedEventArgs, IZeroExMigratedEventArgs,

View File

@ -871,21 +871,6 @@
ethereum-types "^3.5.0" ethereum-types "^3.5.0"
ethereumjs-util "^7.0.10" 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": "@0x/dev-utils@^4.2.9":
version "4.2.9" version "4.2.9"
resolved "https://registry.yarnpkg.com/@0x/dev-utils/-/dev-utils-4.2.9.tgz#b048b139b0055ef3702682c42ccc2a3788a49f5d" resolved "https://registry.yarnpkg.com/@0x/dev-utils/-/dev-utils-4.2.9.tgz#b048b139b0055ef3702682c42ccc2a3788a49f5d"
@ -1115,35 +1100,6 @@
solc "^0.5.5" solc "^0.5.5"
solidity-parser-antlr "^0.4.2" 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": "@0x/subproviders@^6.6.0":
version "6.6.0" version "6.6.0"
resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.6.0.tgz#1743d44ae5e2be9ec48caddbf0f1a580f1672d32" resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-6.6.0.tgz#1743d44ae5e2be9ec48caddbf0f1a580f1672d32"
@ -1442,13 +1398,6 @@
web3 "1.2.1" web3 "1.2.1"
web3-typescript-typings "^0.10.2" 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": "@ethereumjs/common@^2.4.0":
version "2.4.0" version "2.4.0"
resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.4.0.tgz#2d67f6e6ba22246c5c89104e6b9a119fb3039766" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.4.0.tgz#2d67f6e6ba22246c5c89104e6b9a119fb3039766"
@ -1457,13 +1406,6 @@
crc-32 "^1.2.0" crc-32 "^1.2.0"
ethereumjs-util "^7.1.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": "@ethereumjs/tx@^3.3.0":
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.0.tgz#14ed1b7fa0f28e1cd61e3ecbdab824205f6a4378" 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" rlp "^2.0.0"
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
ethereumjs-util@^7.0.10, ethereumjs-util@^7.0.9: ethereumjs-util@^7.0.10:
version "7.0.10" version "7.0.10"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz#5fb7b69fa1fda0acc59634cf39d6b0291180fc1f"
dependencies: dependencies: