Address spot check feedback (#251)

* UniswapV3 VIP (#237)

* `@0x/contracts-zero-ex`: Add UniswapV3Feature

* `@0x/contracts-zero-ex`: Add UniswapV3 VIP
`@0x/contract-artifacts`: Regenerate.
`@0x/contract-wrappers`: Regenerate.
`@0x/asset-swapper`: Add UniswapV3 VIP support.

* address review comments and appease linter

* `@0x/contracts-zero-ex`: Add UniswapV3Feature tests

* Multiplex UniswapV3 (#241)

* Add UniswapV3 support to Multiplex batchFill

* Add AssetSwapper support for Multiplex UniswapV3

* fix repo scripts that use PKG= env var (#242)

Co-authored-by: Lawrence Forman <me@merklejerk.com>

* `@0x/asset-swapper`: Adjust uniswap gas overhead

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>

* OTC orders feature (#244)

* Add OTC orders feature contracts

* Address PR feedback

* Remove partial fills for takerSigned variant

* Add function to query the min valid nonce

* Add ETH support

* Tightly pack expiry, nonceBucket, and nonce

* Address PR feedback

* OTC orders unit tests

* Bump prettier version

* Skip unnecessary math if takerTokenFillAmount == order.takerAmount

* appease CI

* Update contract-artifacts and contract-wrappers and CHANGELOGs

* `@0x/contracts-zero-ex`: Address spot check feedback

* `regen wrappers

* prettier

* `@0x/asset-swapper`: prettier and tweak gas schedule slightly for uni3

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
This commit is contained in:
Lawrence Forman 2021-06-02 00:21:14 -04:00 committed by GitHub
parent 289474e2ce
commit 901d400d62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
112 changed files with 6392 additions and 794 deletions

View File

@ -18,8 +18,8 @@ jobs:
name: yarn name: yarn
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
- setup_remote_docker - setup_remote_docker
- run: yarn build:ci || yarn build:ci || yarn build:ci - run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
- run: yarn build:ts || yarn build:ts || yarn build:ts - run: yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts || yarn build:ts
- save_cache: - save_cache:
key: repo-{{ .Environment.CIRCLE_SHA1 }} key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths: paths:

View File

@ -3,5 +3,6 @@
"tabWidth": 4, "tabWidth": 4,
"singleQuote": true, "singleQuote": true,
"trailingComma": "all", "trailingComma": "all",
"bracketSpacing": true "bracketSpacing": true,
"arrowParens": "avoid"
} }

View File

@ -49,7 +49,6 @@
| Package | Version | | Package | Version |
| ------: | :------ | | ------: | :------ |
<!-- For example: <!-- For example:
| `0x.js` | 2.0.4 | | `0x.js` | 2.0.4 |
| `Exchange Contract` | v2 | | `Exchange Contract` | v2 |

View File

@ -43,7 +43,7 @@ These packages are all under development. See [/contracts/README.md](/contracts/
#### 0x-specific packages #### 0x-specific packages
| Package | Version | Description | | Package | Version | Description |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. | | [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts | | [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
| [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders | | [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |

View File

@ -7,7 +7,10 @@ export interface GodsUnchainedProperties {
quality: BigNumber | number; quality: BigNumber | number;
} }
const propertyDataEncoder = AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]); const propertyDataEncoder = AbiEncoder.create([
{ name: 'proto', type: 'uint16' },
{ name: 'quality', type: 'uint8' },
]);
const brokerDataEncoder = AbiEncoder.create([ const brokerDataEncoder = AbiEncoder.create([
{ name: 'godsUnchainedAddress', type: 'address' }, { name: 'godsUnchainedAddress', type: 'address' },
{ name: 'validatorAddress', type: 'address' }, { name: 'validatorAddress', type: 'address' },

View File

@ -13,7 +13,11 @@ export const exchangeDataEncoder = {
.getABIEncodedTransactionData(); .getABIEncodedTransactionData();
} else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) { } else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) {
data = (exchangeInstance as any) data = (exchangeInstance as any)
[fnName](orders, orders.map(order => order.takerAssetAmount), orders.map(order => order.signature)) [fnName](
orders,
orders.map(order => order.takerAssetAmount),
orders.map(order => order.signature),
)
.getABIEncodedTransactionData(); .getABIEncodedTransactionData();
} else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) { } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) {
const fillAsset = /Buy/.test(fnName) ? 'makerAssetAmount' : 'takerAssetAmount'; const fillAsset = /Buy/.test(fnName) ? 'makerAssetAmount' : 'takerAssetAmount';

View File

@ -39,7 +39,10 @@ blockchainTests.resets('Reentrancy Tests', env => {
// Handle tuples. // Handle tuples.
if (item.type === 'tuple') { if (item.type === 'tuple') {
const tuple = item as TupleDataItem; const tuple = item as TupleDataItem;
return _.zipObject(tuple.components.map(c => c.name), tuple.components.map(createFunctionInputs)); return _.zipObject(
tuple.components.map(c => c.name),
tuple.components.map(createFunctionInputs),
);
} }
// Handle strings. // Handle strings.
if (item.type === 'string') { if (item.type === 'string') {

View File

@ -109,7 +109,11 @@ export class ExchangeWrapper {
opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber }, opts: { makerAssetFillAmount: BigNumber; gas?: number; gasPrice?: BigNumber },
): Promise<TransactionReceiptWithDecodedLogs> { ): Promise<TransactionReceiptWithDecodedLogs> {
return this.exchangeContract return this.exchangeContract
.marketBuyOrdersNoThrow(orders, opts.makerAssetFillAmount, orders.map(signedOrder => signedOrder.signature)) .marketBuyOrdersNoThrow(
orders,
opts.makerAssetFillAmount,
orders.map(signedOrder => signedOrder.signature),
)
.awaitTransactionSuccessAsync({ from, gas: opts.gas }); .awaitTransactionSuccessAsync({ from, gas: opts.gas });
} }
public async marketSellOrdersFillOrKillAsync( public async marketSellOrdersFillOrKillAsync(

View File

@ -534,9 +534,14 @@ blockchainTests.skip('Coordinator Client', env => {
const signedOrders = [signedOrder, signedOrderWithDifferentFeeRecipient]; const signedOrders = [signedOrder, signedOrderWithDifferentFeeRecipient];
const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount];
await coordinatorClient await coordinatorClient
.batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, signedOrders.map(o => o.signature), { .batchFillOrdersAsync(
signedOrders,
takerAssetFillAmounts,
signedOrders.map(o => o.signature),
{
from: takerAddress, from: takerAddress,
}) },
)
.then(res => { .then(res => {
expect(res).to.be.undefined(); expect(res).to.be.undefined();
}) })
@ -570,9 +575,14 @@ blockchainTests.skip('Coordinator Client', env => {
const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator];
const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount];
await coordinatorClient await coordinatorClient
.batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, signedOrders.map(o => o.signature), { .batchFillOrdersAsync(
signedOrders,
takerAssetFillAmounts,
signedOrders.map(o => o.signature),
{
from: takerAddress, from: takerAddress,
}) },
)
.then(res => { .then(res => {
expect(res).to.be.undefined(); expect(res).to.be.undefined();
}) })
@ -600,9 +610,14 @@ blockchainTests.skip('Coordinator Client', env => {
const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator]; const signedOrders = [signedOrder, signedOrderWithDifferentCoordinatorOperator];
const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount, takerTokenFillAmount];
await coordinatorClient await coordinatorClient
.batchFillOrdersAsync(signedOrders, takerAssetFillAmounts, signedOrders.map(o => o.signature), { .batchFillOrdersAsync(
signedOrders,
takerAssetFillAmounts,
signedOrders.map(o => o.signature),
{
from: takerAddress, from: takerAddress,
}) },
)
.then(res => { .then(res => {
expect(res).to.be.undefined(); expect(res).to.be.undefined();
}) })

View File

@ -267,7 +267,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value); expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
await balanceStore.updateBalancesAsync(); await balanceStore.updateBalancesAsync();
balanceStore.assertEquals(expectedBalances); balanceStore.assertEquals(expectedBalances);
verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill); verifyEvents(
txReceipt,
orders.map(order => expectedFillEvent(order)),
ExchangeEvents.Fill,
);
}); });
it(`${fnName} should fill the orders if called by approver (eth fee, no refund)`, async () => { it(`${fnName} should fill the orders if called by approver (eth fee, no refund)`, async () => {
await balanceStore.updateBalancesAsync(); await balanceStore.updateBalancesAsync();
@ -280,7 +284,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value); expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
await balanceStore.updateBalancesAsync(); await balanceStore.updateBalancesAsync();
balanceStore.assertEquals(expectedBalances); balanceStore.assertEquals(expectedBalances);
verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill); verifyEvents(
txReceipt,
orders.map(order => expectedFillEvent(order)),
ExchangeEvents.Fill,
);
}); });
it(`${fnName} should fill the orders if called by approver (mixed fees, refund)`, async () => { it(`${fnName} should fill the orders if called by approver (mixed fees, refund)`, async () => {
await balanceStore.updateBalancesAsync(); await balanceStore.updateBalancesAsync();
@ -293,7 +301,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value); expectedBalances.simulateFills(orders, taker.address, txReceipt, deployment, value);
await balanceStore.updateBalancesAsync(); await balanceStore.updateBalancesAsync();
balanceStore.assertEquals(expectedBalances); balanceStore.assertEquals(expectedBalances);
verifyEvents(txReceipt, orders.map(order => expectedFillEvent(order)), ExchangeEvents.Fill); verifyEvents(
txReceipt,
orders.map(order => expectedFillEvent(order)),
ExchangeEvents.Fill,
);
}); });
it(`${fnName} should revert with an invalid approval signature`, async () => { it(`${fnName} should revert with an invalid approval signature`, async () => {
const approvalSignature = hexUtils.concat( const approvalSignature = hexUtils.concat(
@ -360,7 +372,11 @@ blockchainTests.resets('Coordinator integration tests', env => {
.executeTransaction(transaction, maker.address, transaction.signature, []) .executeTransaction(transaction, maker.address, transaction.signature, [])
.awaitTransactionSuccessAsync({ from: maker.address }); .awaitTransactionSuccessAsync({ from: maker.address });
verifyEvents(txReceipt, orders.map(order => expectedCancelEvent(order)), ExchangeEvents.Cancel); verifyEvents(
txReceipt,
orders.map(order => expectedCancelEvent(order)),
ExchangeEvents.Cancel,
);
}); });
it('cancelOrdersUpTo call should be successful without an approval', async () => { it('cancelOrdersUpTo call should be successful without an approval', async () => {
const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo, []); const data = exchangeDataEncoder.encodeOrdersToExchangeData(ExchangeFunctionName.CancelOrdersUpTo, []);

View File

@ -186,13 +186,13 @@ blockchainTests.resets('LibAssetData', env => {
}); });
it('should decode multiasset data', async () => { it('should decode multiasset data', async () => {
expect(await devUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync()).to.deep.equal( expect(
[ await devUtils.decodeMultiAssetData(KNOWN_MULTI_ASSET_ENCODING.assetData).callAsync(),
).to.deep.equal([
AssetProxyId.MultiAsset, AssetProxyId.MultiAsset,
KNOWN_MULTI_ASSET_ENCODING.amounts, KNOWN_MULTI_ASSET_ENCODING.amounts,
KNOWN_MULTI_ASSET_ENCODING.nestedAssetData, KNOWN_MULTI_ASSET_ENCODING.nestedAssetData,
], ]);
);
}); });
it('should encode StaticCall data', async () => { it('should encode StaticCall data', async () => {

View File

@ -278,15 +278,21 @@ blockchainTests.resets('matchOrders integration tests', env => {
ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthRightSignatures, ExchangeRevertErrors.BatchMatchOrdersErrorCodes.InvalidLengthRightSignatures,
); );
let tx = deployment.exchange let tx = deployment.exchange
.batchMatchOrders(leftOrders, rightOrders, leftOrders.map(order => order.signature), [ .batchMatchOrders(
rightOrders[0].signature, leftOrders,
]) rightOrders,
leftOrders.map(order => order.signature),
[rightOrders[0].signature],
)
.awaitTransactionSuccessAsync({ from: matcher.address }); .awaitTransactionSuccessAsync({ from: matcher.address });
await expect(tx).to.revertWith(expectedError); await expect(tx).to.revertWith(expectedError);
tx = deployment.exchange tx = deployment.exchange
.batchMatchOrdersWithMaximalFill(leftOrders, rightOrders, leftOrders.map(order => order.signature), [ .batchMatchOrdersWithMaximalFill(
rightOrders[0].signature, leftOrders,
]) rightOrders,
leftOrders.map(order => order.signature),
[rightOrders[0].signature],
)
.awaitTransactionSuccessAsync({ from: matcher.address }); .awaitTransactionSuccessAsync({ from: matcher.address });
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -475,7 +481,10 @@ blockchainTests.resets('matchOrders integration tests', env => {
], ],
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
matchIndices: [[0, 0], [1, 0]], matchIndices: [
[0, 0],
[1, 0],
],
shouldMaximallyFill: false, shouldMaximallyFill: false,
}); });
}); });
@ -524,7 +533,10 @@ blockchainTests.resets('matchOrders integration tests', env => {
], ],
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
matchIndices: [[0, 0], [0, 1]], matchIndices: [
[0, 0],
[0, 1],
],
shouldMaximallyFill: false, shouldMaximallyFill: false,
}); });
}); });
@ -626,7 +638,11 @@ blockchainTests.resets('matchOrders integration tests', env => {
], ],
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
matchIndices: [[0, 0], [0, 1], [1, 1]], matchIndices: [
[0, 0],
[0, 1],
[1, 1],
],
shouldMaximallyFill: false, shouldMaximallyFill: false,
}); });
}); });
@ -801,7 +817,11 @@ blockchainTests.resets('matchOrders integration tests', env => {
], ],
leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], leftOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT], rightOrdersTakerAssetFilledAmounts: [constants.ZERO_AMOUNT, constants.ZERO_AMOUNT],
matchIndices: [[0, 0], [1, 0], [1, 1]], matchIndices: [
[0, 0],
[1, 0],
[1, 1],
],
shouldMaximallyFill: true, shouldMaximallyFill: true,
}); });
}); });

View File

@ -106,7 +106,12 @@ blockchainTests.fork.resets('Forwarder mainnet tests', env => {
orders[1].takerAssetAmount.dividedToIntegerBy(2), orders[1].takerAssetAmount.dividedToIntegerBy(2),
); );
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
.marketSellOrdersWithEth(orders, orders.map(o => o.signature), [], []) .marketSellOrdersWithEth(
orders,
orders.map(o => o.signature),
[],
[],
)
.callAsync({ .callAsync({
from: takerAddress, from: takerAddress,
value: ethSellAmount, value: ethSellAmount,
@ -161,7 +166,13 @@ blockchainTests.fork.resets('Forwarder mainnet tests', env => {
orders[1].makerAssetAmount.dividedToIntegerBy(2), orders[1].makerAssetAmount.dividedToIntegerBy(2),
); );
const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder const [wethSpentAmount, makerAssetAcquiredAmount] = await forwarder
.marketBuyOrdersWithEth(orders, makerAssetBuyAmount, orders.map(o => o.signature), [], []) .marketBuyOrdersWithEth(
orders,
makerAssetBuyAmount,
orders.map(o => o.signature),
[],
[],
)
.callAsync({ .callAsync({
from: takerAddress, from: takerAddress,
value: ethSellAmount, value: ethSellAmount,

View File

@ -190,9 +190,14 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
rightTakerAssetData, rightTakerAssetData,
makerFeeAssetData, makerFeeAssetData,
takerFeeAssetData, takerFeeAssetData,
] = [leftMakerToken, leftTakerToken, rightMakerToken, rightTakerToken, makerFeeToken, takerFeeToken].map( ] = [
token => encodeERC20AssetData(token.address), leftMakerToken,
); leftTakerToken,
rightMakerToken,
rightTakerToken,
makerFeeToken,
takerFeeToken,
].map(token => encodeERC20AssetData(token.address));
// Construct and sign the left order // Construct and sign the left order
const leftOrder = await this.signOrderAsync({ const leftOrder = await this.signOrderAsync({

View File

@ -8,7 +8,10 @@ import { Actor, Constructor } from './base';
* Useful for BalanceStore. * Useful for BalanceStore.
*/ */
export function actorAddressesByName(actors: Actor[]): ObjectMap<string> { export function actorAddressesByName(actors: Actor[]): ObjectMap<string> {
return _.zipObject(actors.map(actor => actor.name), actors.map(actor => actor.address)); return _.zipObject(
actors.map(actor => actor.name),
actors.map(actor => actor.address),
);
} }
/** /**

View File

@ -77,19 +77,24 @@ tests('Exchange signature validation fuzz tests', env => {
before(async () => { before(async () => {
chainId = await env.web3Wrapper.getChainIdAsync(); chainId = await env.web3Wrapper.getChainIdAsync();
accounts = await env.getAccountAddressesAsync(); accounts = await env.getAccountAddressesAsync();
privateKeys = _.zipObject(accounts, accounts.map((a, i) => constants.TESTRPC_PRIVATE_KEYS[i])); privateKeys = _.zipObject(
accounts,
accounts.map((a, i) => constants.TESTRPC_PRIVATE_KEYS[i]),
);
deployment = await DeploymentManager.deployAsync(env, { deployment = await DeploymentManager.deployAsync(env, {
numErc20TokensToDeploy: 0, numErc20TokensToDeploy: 0,
numErc721TokensToDeploy: 0, numErc721TokensToDeploy: 0,
numErc1155TokensToDeploy: 0, numErc1155TokensToDeploy: 0,
}); });
exchange = deployment.exchange; exchange = deployment.exchange;
walletContractAddress = (await TestSignatureValidationWalletContract.deployFrom0xArtifactAsync( walletContractAddress = (
await TestSignatureValidationWalletContract.deployFrom0xArtifactAsync(
artifacts.TestSignatureValidationWallet, artifacts.TestSignatureValidationWallet,
env.provider, env.provider,
env.txDefaults, env.txDefaults,
{}, {},
)).address; )
).address;
// This just has to be a contract address that doesn't implement the // This just has to be a contract address that doesn't implement the
// wallet spec. // wallet spec.
notWalletContractAddress = exchange.address; notWalletContractAddress = exchange.address;
@ -715,7 +720,7 @@ tests('Exchange signature validation fuzz tests', env => {
invalidTestTransactionMangledSignature(), invalidTestTransactionMangledSignature(),
]; ];
const simulationEnvironment = new SimulationEnvironment(deployment, new BlockchainBalanceStore({}, {}), []); const simulationEnvironment = new SimulationEnvironment(deployment, new BlockchainBalanceStore({}, {}), []);
const simulation = new class extends Simulation { const simulation = new (class extends Simulation {
// tslint:disable-next-line: prefer-function-over-method // tslint:disable-next-line: prefer-function-over-method
protected async *_assertionGenerator(): AsyncIterableIterator<AssertionResult | void> { protected async *_assertionGenerator(): AsyncIterableIterator<AssertionResult | void> {
while (true) { while (true) {
@ -723,7 +728,7 @@ tests('Exchange signature validation fuzz tests', env => {
yield (await action!.next()).value; yield (await action!.next()).value;
} }
} }
}(simulationEnvironment); })(simulationEnvironment);
simulation.resets = true; simulation.resets = true;
return simulation.fuzzAsync(); return simulation.fuzzAsync();
}); });

View File

@ -157,11 +157,11 @@ export class FinalizerActor extends BaseActor {
const delegators = delegatorsByPoolId[poolId]; const delegators = delegatorsByPoolId[poolId];
delegatorBalancesByPoolId[poolId] = {}; delegatorBalancesByPoolId[poolId] = {};
for (const delegator of delegators) { for (const delegator of delegators) {
delegatorBalancesByPoolId[poolId][ delegatorBalancesByPoolId[poolId][delegator] = (
delegator await this._stakingApiWrapper.stakingContract
] = (await this._stakingApiWrapper.stakingContract
.getStakeDelegatedToPoolByOwner(delegator, poolId) .getStakeDelegatedToPoolByOwner(delegator, poolId)
.callAsync()).currentEpochBalance; .callAsync()
).currentEpochBalance;
} }
} }
return delegatorBalancesByPoolId; return delegatorBalancesByPoolId;
@ -253,7 +253,10 @@ export class FinalizerActor extends BaseActor {
const totalFeesCollected = BigNumber.sum(...activePools.map(p => p.feesCollected)); const totalFeesCollected = BigNumber.sum(...activePools.map(p => p.feesCollected));
const totalWeightedStake = BigNumber.sum(...activePools.map(p => p.weightedStake)); const totalWeightedStake = BigNumber.sum(...activePools.map(p => p.weightedStake));
if (totalRewards.eq(0) || totalFeesCollected.eq(0) || totalWeightedStake.eq(0)) { if (totalRewards.eq(0) || totalFeesCollected.eq(0) || totalWeightedStake.eq(0)) {
return _.zipObject(poolIds, _.times(poolIds.length, () => new BigNumber(0))); return _.zipObject(
poolIds,
_.times(poolIds.length, () => new BigNumber(0)),
);
} }
const rewards = await Promise.all( const rewards = await Promise.all(
activePools.map(async pool => activePools.map(async pool =>

View File

@ -102,13 +102,15 @@ blockchainTests('Migration tests', env => {
}); });
it('should set the correct initial params', async () => { it('should set the correct initial params', async () => {
const stakingProxyContractAddress = (await StakingProxyContract.deployFrom0xArtifactAsync( const stakingProxyContractAddress = (
await StakingProxyContract.deployFrom0xArtifactAsync(
artifacts.StakingProxy, artifacts.StakingProxy,
env.provider, env.provider,
env.txDefaults, env.txDefaults,
artifacts, artifacts,
stakingContract.address, stakingContract.address,
)).address; )
).address;
const stakingProxyContract = new StakingContract( const stakingProxyContract = new StakingContract(
stakingProxyContractAddress, stakingProxyContractAddress,

View File

@ -108,9 +108,7 @@ export async function testWithReferenceFuncAsync(
return expect.fail( return expect.fail(
actualError, actualError,
expectedError, expectedError,
`${testCaseString}: expected error message '${actualError.message}' to equal '${ `${testCaseString}: expected error message '${actualError.message}' to equal '${expectedError.message}'`,
expectedError.message
}'`,
); );
} }
} }

View File

@ -536,7 +536,11 @@ blockchainTests('LibBytes', env => {
])); ]));
describe('copies forward within one word and one byte overlap', () => describe('copies forward within one word and one byte overlap', () =>
test([[0, 0, 1, 'one byte'], [10, 0, 11, 'eleven bytes'], [15, 0, 16, 'sixteen bytes']])); test([
[0, 0, 1, 'one byte'],
[10, 0, 11, 'eleven bytes'],
[15, 0, 16, 'sixteen bytes'],
]));
describe('copies backward', () => describe('copies backward', () =>
test([ test([
@ -603,7 +607,11 @@ blockchainTests('LibBytes', env => {
])); ]));
describe('copies forward within one word and one byte overlap', () => describe('copies forward within one word and one byte overlap', () =>
test([[0, 0, 1, 'one byte'], [0, 10, 11, 'eleven bytes'], [0, 15, 16, 'sixteen bytes']])); test([
[0, 0, 1, 'one byte'],
[0, 10, 11, 'eleven bytes'],
[0, 15, 16, 'sixteen bytes'],
]));
}); });
describe('slice', () => { describe('slice', () => {

View File

@ -1,4 +1,17 @@
[ [
{
"version": "0.25.0",
"changes": [
{
"note": "Add OtcOrdersFeature",
"pr": 244
},
{
"note": "Add UniswapV3 VIP feature",
"pr": 237
}
]
},
{ {
"timestamp": 1621944788, "timestamp": 1621944788,
"version": "0.24.1", "version": "0.24.1",

View File

@ -26,11 +26,13 @@ import "./features/interfaces/ITokenSpenderFeature.sol";
import "./features/interfaces/ITransformERC20Feature.sol"; import "./features/interfaces/ITransformERC20Feature.sol";
import "./features/interfaces/IMetaTransactionsFeature.sol"; import "./features/interfaces/IMetaTransactionsFeature.sol";
import "./features/interfaces/IUniswapFeature.sol"; import "./features/interfaces/IUniswapFeature.sol";
import "./features/interfaces/IUniswapV3Feature.sol";
import "./features/interfaces/IPancakeSwapFeature.sol"; import "./features/interfaces/IPancakeSwapFeature.sol";
import "./features/interfaces/ILiquidityProviderFeature.sol"; import "./features/interfaces/ILiquidityProviderFeature.sol";
import "./features/interfaces/INativeOrdersFeature.sol"; import "./features/interfaces/INativeOrdersFeature.sol";
import "./features/interfaces/IBatchFillNativeOrdersFeature.sol"; import "./features/interfaces/IBatchFillNativeOrdersFeature.sol";
import "./features/interfaces/IMultiplexFeature.sol"; import "./features/interfaces/IMultiplexFeature.sol";
import "./features/interfaces/IOtcOrdersFeature.sol";
/// @dev Interface for a fully featured Exchange Proxy. /// @dev Interface for a fully featured Exchange Proxy.
@ -40,11 +42,13 @@ interface IZeroEx is
ITransformERC20Feature, ITransformERC20Feature,
IMetaTransactionsFeature, IMetaTransactionsFeature,
IUniswapFeature, IUniswapFeature,
IUniswapV3Feature,
IPancakeSwapFeature, IPancakeSwapFeature,
ILiquidityProviderFeature, ILiquidityProviderFeature,
INativeOrdersFeature, INativeOrdersFeature,
IBatchFillNativeOrdersFeature, IBatchFillNativeOrdersFeature,
IMultiplexFeature IMultiplexFeature,
IOtcOrdersFeature
{ {
// solhint-disable state-visibility // solhint-disable state-visibility

View File

@ -88,6 +88,23 @@ library LibNativeOrdersRichErrors {
); );
} }
function OrderNotSignedByTakerError(
bytes32 orderHash,
address signer,
address taker
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("OrderNotSignedByTakerError(bytes32,address,address)")),
orderHash,
signer,
taker
);
}
function InvalidSignerError( function InvalidSignerError(
address maker, address maker,
address signer address signer

View File

@ -108,7 +108,7 @@ contract LiquidityProviderFeature is
if (!LibERC20Transformer.isTokenETH(inputToken)) { if (!LibERC20Transformer.isTokenETH(inputToken)) {
// Transfer input ERC20 tokens to the provider. // Transfer input ERC20 tokens to the provider.
_transferERC20Tokens( _transferERC20TokensFrom(
inputToken, inputToken,
msg.sender, msg.sender,
address(provider), address(provider),

View File

@ -251,7 +251,7 @@ contract MetaTransactionsFeature is
// Pay the fee to the sender. // Pay the fee to the sender.
if (state.mtx.feeAmount > 0) { if (state.mtx.feeAmount > 0) {
_transferERC20Tokens( _transferERC20TokensFrom(
state.mtx.feeToken, state.mtx.feeToken,
state.mtx.signer, state.mtx.signer,
state.sender, state.sender,

View File

@ -36,6 +36,7 @@ import "./interfaces/IFeature.sol";
import "./interfaces/IMultiplexFeature.sol"; import "./interfaces/IMultiplexFeature.sol";
import "./interfaces/INativeOrdersFeature.sol"; import "./interfaces/INativeOrdersFeature.sol";
import "./interfaces/ITransformERC20Feature.sol"; import "./interfaces/ITransformERC20Feature.sol";
import "./interfaces/IUniswapV3Feature.sol";
import "./libs/LibNativeOrder.sol"; import "./libs/LibNativeOrder.sol";
@ -55,7 +56,7 @@ contract MultiplexFeature is
/// @dev Name of this feature. /// @dev Name of this feature.
string public constant override FEATURE_NAME = "MultiplexFeature"; string public constant override FEATURE_NAME = "MultiplexFeature";
/// @dev Version of this feature. /// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1); uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
/// @dev The WETH token contract. /// @dev The WETH token contract.
IEtherTokenV06 private immutable weth; IEtherTokenV06 private immutable weth;
@ -273,6 +274,22 @@ contract MultiplexFeature is
// Increment the sold and bought amounts. // Increment the sold and bought amounts.
soldAmount = soldAmount.safeAdd(inputTokenAmount); soldAmount = soldAmount.safeAdd(inputTokenAmount);
outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_); outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
} else if (wrappedCall.selector == IUniswapV3Feature.sellTokenForTokenToUniswapV3.selector) {
(bool success, bytes memory resultData) = address(this).delegatecall(
abi.encodeWithSelector(
IUniswapV3Feature.sellTokenForTokenToUniswapV3.selector,
wrappedCall.data,
inputTokenAmount,
0,
msg.sender
)
);
if (success) {
uint256 outputTokenAmount_ = abi.decode(resultData, (uint256));
// Increment the sold and bought amounts.
soldAmount = soldAmount.safeAdd(inputTokenAmount);
outputTokenAmount = outputTokenAmount.safeAdd(outputTokenAmount_);
}
} else if (wrappedCall.selector == this._sellToLiquidityProvider.selector) { } else if (wrappedCall.selector == this._sellToLiquidityProvider.selector) {
(address provider, bytes memory auxiliaryData) = abi.decode( (address provider, bytes memory auxiliaryData) = abi.decode(
wrappedCall.data, wrappedCall.data,
@ -289,7 +306,7 @@ contract MultiplexFeature is
remainingEth -= inputTokenAmount; remainingEth -= inputTokenAmount;
} else { } else {
// Transfer input ERC20 tokens to the provider. // Transfer input ERC20 tokens to the provider.
_transferERC20Tokens( _transferERC20TokensFrom(
fillData.inputToken, fillData.inputToken,
msg.sender, msg.sender,
provider, provider,
@ -453,7 +470,7 @@ contract MultiplexFeature is
_transferEth(payable(provider), outputTokenAmount); _transferEth(payable(provider), outputTokenAmount);
remainingEth -= outputTokenAmount; remainingEth -= outputTokenAmount;
} else { } else {
_transferERC20Tokens( _transferERC20TokensFrom(
IERC20TokenV06(fillData.tokens[i]), IERC20TokenV06(fillData.tokens[i]),
msg.sender, msg.sender,
provider, provider,
@ -512,7 +529,7 @@ contract MultiplexFeature is
// send the output token to some address other than // send the output token to some address other than
// msg.sender, so we must transfer the input token // msg.sender, so we must transfer the input token
// to the FlashWallet here. // to the FlashWallet here.
_transferERC20Tokens( _transferERC20TokensFrom(
args.inputToken, args.inputToken,
msg.sender, msg.sender,
flashWallet, flashWallet,
@ -598,7 +615,7 @@ contract MultiplexFeature is
if (pairAddress == address(0)) { if (pairAddress == address(0)) {
pairAddress = _computeUniswapPairAddress(tokens[0], tokens[1], isSushi); pairAddress = _computeUniswapPairAddress(tokens[0], tokens[1], isSushi);
_transferERC20Tokens( _transferERC20TokensFrom(
IERC20TokenV06(tokens[0]), IERC20TokenV06(tokens[0]),
msg.sender, msg.sender,
pairAddress, pairAddress,

View File

@ -0,0 +1,472 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibNativeOrdersRichErrors.sol";
import "../fixins/FixinCommon.sol";
import "../fixins/FixinEIP712.sol";
import "../fixins/FixinTokenSpender.sol";
import "../migrations/LibMigrate.sol";
import "../storage/LibNativeOrdersStorage.sol";
import "../storage/LibOtcOrdersStorage.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IOtcOrdersFeature.sol";
import "./libs/LibNativeOrder.sol";
import "./libs/LibSignature.sol";
/// @dev Feature for interacting with OTC orders.
contract OtcOrdersFeature is
IFeature,
IOtcOrdersFeature,
FixinCommon,
FixinEIP712,
FixinTokenSpender
{
using LibSafeMathV06 for uint256;
using LibSafeMathV06 for uint128;
/// @dev Options for handling ETH/WETH conversion
/// @param LeaveAsWeth Neither unwrap nor wrap.
/// @param WrapEth Wrap attached ETH.
/// @param UnwrapWeth Unwrap WETH before transferring
/// to taker.
enum WethOptions {
LeaveAsWeth,
WrapEth,
UnwrapWeth
}
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "OtcOrders";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The WETH token contract.
IEtherTokenV06 private immutable WETH;
constructor(address zeroExAddress, IEtherTokenV06 weth)
public
FixinEIP712(zeroExAddress)
{
WETH = weth;
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
/// @return success `LibMigrate.SUCCESS` on success.
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.fillOtcOrder.selector);
_registerFeatureFunction(this.fillOtcOrderWithEth.selector);
_registerFeatureFunction(this.fillTakerSignedOtcOrder.selector);
_registerFeatureFunction(this.getOtcOrderInfo.selector);
_registerFeatureFunction(this.getOtcOrderHash.selector);
_registerFeatureFunction(this.lastOtcTxOriginNonce.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
/// @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 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.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function fillOtcOrder(
LibNativeOrder.OtcOrder memory order,
LibSignature.Signature memory makerSignature,
uint128 takerTokenFillAmount,
bool unwrapWeth
)
public
override
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
if (!_isSenderValidTaker(order.taker)) {
bytes32 orderHash = getOtcOrderHash(order);
LibNativeOrdersRichErrors.OrderNotFillableByTakerError(
orderHash,
msg.sender,
order.taker
).rrevert();
}
LibSignature.Signature memory nullSignature;
return _fillOtcOrderPrivate(
order,
makerSignature,
nullSignature,
takerTokenFillAmount,
unwrapWeth ? WethOptions.UnwrapWeth : WethOptions.LeaveAsWeth
);
}
/// @dev Fill an OTC order whose taker token is WETH for up
/// to `msg.value`.
/// @param order The OTC order.
/// @param makerSignature The order signature from the maker.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function fillOtcOrderWithEth(
LibNativeOrder.OtcOrder memory order,
LibSignature.Signature memory makerSignature
)
public
override
payable
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
if (!_isSenderValidTaker(order.taker)) {
bytes32 orderHash = getOtcOrderHash(order);
LibNativeOrdersRichErrors.OrderNotFillableByTakerError(
orderHash,
msg.sender,
order.taker
).rrevert();
}
LibSignature.Signature memory nullSignature;
return _fillOtcOrderPrivate(
order,
makerSignature,
nullSignature,
msg.value.safeDowncastToUint128(),
WethOptions.WrapEth
);
}
/// @dev Fully fill an OTC order. "Meta-transaction" variant,
/// requires order to be signed by both maker and taker.
/// @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.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function fillTakerSignedOtcOrder(
LibNativeOrder.OtcOrder memory order,
LibSignature.Signature memory makerSignature,
LibSignature.Signature memory takerSignature,
bool unwrapWeth
)
public
override
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
return _fillOtcOrderPrivate(
order,
makerSignature,
takerSignature,
order.takerAmount,
unwrapWeth ? WethOptions.UnwrapWeth : WethOptions.LeaveAsWeth
);
}
/// @dev Fill an OTC order. Private variant.
/// @param order The OTC order.
/// @param makerSignature The order signature from the maker.
/// @param takerSignature The order signature from the taker.
/// Ignored if msg.sender == order.taker.
/// @param takerTokenFillAmount Maximum taker token amount to
/// fill this order with.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function _fillOtcOrderPrivate(
LibNativeOrder.OtcOrder memory order,
LibSignature.Signature memory makerSignature,
LibSignature.Signature memory takerSignature,
uint128 takerTokenFillAmount,
WethOptions wethOptions
)
private
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
LibNativeOrder.OtcOrderInfo memory orderInfo = getOtcOrderInfo(order);
// Must be fillable.
if (orderInfo.status != LibNativeOrder.OrderStatus.FILLABLE) {
LibNativeOrdersRichErrors.OrderNotFillableError(
orderInfo.orderHash,
uint8(orderInfo.status)
).rrevert();
}
address taker = msg.sender;
{
LibNativeOrdersStorage.Storage storage stor =
LibNativeOrdersStorage.getStorage();
// Must be fillable by the tx.origin.
if (
order.txOrigin != tx.origin &&
!stor.originRegistry[order.txOrigin][tx.origin]
) {
LibNativeOrdersRichErrors.OrderNotFillableByOriginError(
orderInfo.orderHash,
tx.origin,
order.txOrigin
).rrevert();
}
// Maker signature must be valid for the order.
address makerSigner = LibSignature.getSignerOfHash(orderInfo.orderHash, makerSignature);
if (
makerSigner != order.maker &&
!stor.orderSignerRegistry[order.maker][makerSigner]
) {
LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
orderInfo.orderHash,
makerSigner,
order.maker
).rrevert();
}
// If msg.sender is not the taker, validate the taker signature.
if (!_isSenderValidTaker(order.taker)) {
address takerSigner = LibSignature.getSignerOfHash(orderInfo.orderHash, takerSignature);
if (
takerSigner != order.taker &&
!stor.orderSignerRegistry[order.taker][takerSigner]
) {
LibNativeOrdersRichErrors.OrderNotSignedByTakerError(
orderInfo.orderHash,
takerSigner,
order.taker
).rrevert();
}
taker = order.taker;
}
}
// Settle between the maker and taker.
(takerTokenFilledAmount, makerTokenFilledAmount) = _settleOtcOrder(
order,
taker,
takerTokenFillAmount,
wethOptions
);
emit OtcOrderFilled(
orderInfo.orderHash,
order.maker,
taker,
address(order.makerToken),
address(order.takerToken),
takerTokenFilledAmount,
makerTokenFilledAmount
);
}
/// @dev Settle the trade between an OTC order's maker and taker.
/// @param order The OTC order.
/// @param takerTokenFillAmount Maximum taker token amount to fill this
/// order with.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function _settleOtcOrder(
LibNativeOrder.OtcOrder memory order,
address taker,
uint128 takerTokenFillAmount,
WethOptions wethOptions
)
private
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount)
{
{
// Unpack nonce fields
uint64 nonceBucket = uint64(order.expiryAndNonce >> 128);
uint128 nonce = uint128(order.expiryAndNonce);
// Update tx origin nonce for the order
LibOtcOrdersStorage.getStorage().txOriginNonces
[order.txOrigin][nonceBucket] = nonce;
}
if (takerTokenFillAmount == order.takerAmount) {
takerTokenFilledAmount = order.takerAmount;
makerTokenFilledAmount = order.makerAmount;
} else {
// Clamp the taker token fill amount to the fillable amount.
takerTokenFilledAmount = LibSafeMathV06.min128(
takerTokenFillAmount,
order.takerAmount
);
// Compute the maker token amount.
// This should never overflow because the values are all clamped to
// (2^128-1).
makerTokenFilledAmount = uint128(LibMathV06.getPartialAmountFloor(
uint256(takerTokenFilledAmount),
uint256(order.takerAmount),
uint256(order.makerAmount)
));
}
if (wethOptions == WethOptions.WrapEth) {
require(
order.takerToken == WETH,
"OtcOrdersFeature/INVALID_WRAP_ETH"
);
// Wrap ETH
WETH.deposit{value: takerTokenFilledAmount}();
// Transfer WETH to maker
WETH.transfer(order.maker, takerTokenFilledAmount);
if (takerTokenFilledAmount < msg.value) {
// Refund unused ETH
_transferEth(
msg.sender,
msg.value - uint256(takerTokenFilledAmount)
);
}
} else {
// Transfer taker -> maker
_transferERC20TokensFrom(
order.takerToken,
taker,
order.maker,
takerTokenFilledAmount
);
}
if (wethOptions == WethOptions.UnwrapWeth) {
require(
order.makerToken == WETH,
"OtcOrdersFeature/INVALID_UNWRAP_WETH"
);
// Transfer maker tokens in
_transferERC20TokensFrom(
order.makerToken,
order.maker,
address(this),
makerTokenFilledAmount
);
// Unwrap WETH
WETH.withdraw(makerTokenFilledAmount);
// Transfer ETH to taker
_transferEth(taker, makerTokenFilledAmount);
} else {
// Transfer maker -> taker.
_transferERC20TokensFrom(
order.makerToken,
order.maker,
taker,
makerTokenFilledAmount
);
}
}
/// @dev Get the order info for an OTC order.
/// @param order The OTC order.
/// @return orderInfo Info about the order.
function getOtcOrderInfo(LibNativeOrder.OtcOrder memory order)
public
override
view
returns (LibNativeOrder.OtcOrderInfo memory orderInfo)
{
// compute order hash.
orderInfo.orderHash = getOtcOrderHash(order);
LibOtcOrdersStorage.Storage storage stor =
LibOtcOrdersStorage.getStorage();
// Unpack expiry and nonce fields
uint64 expiry = uint64(order.expiryAndNonce >> 192);
uint64 nonceBucket = uint64(order.expiryAndNonce >> 128);
uint128 nonce = uint128(order.expiryAndNonce);
// check tx origin nonce
uint128 lastNonce = stor.txOriginNonces
[order.txOrigin]
[nonceBucket];
if (nonce <= lastNonce) {
orderInfo.status = LibNativeOrder.OrderStatus.INVALID;
return orderInfo;
}
// Check for expiration.
if (expiry <= uint64(block.timestamp)) {
orderInfo.status = LibNativeOrder.OrderStatus.EXPIRED;
return orderInfo;
}
orderInfo.status = LibNativeOrder.OrderStatus.FILLABLE;
return orderInfo;
}
/// @dev Get the canonical hash of an OTC order.
/// @param order The OTC order.
/// @return orderHash The order hash.
function getOtcOrderHash(LibNativeOrder.OtcOrder memory order)
public
override
view
returns (bytes32 orderHash)
{
return _getEIP712Hash(
LibNativeOrder.getOtcOrderStructHash(order)
);
}
/// @dev Get the last nonce used for a particular
/// tx.origin address and nonce bucket.
/// @param txOrigin The address.
/// @param nonceBucket The nonce bucket index.
/// @return lastNonce The last nonce value used.
function lastOtcTxOriginNonce(address txOrigin, uint64 nonceBucket)
public
override
view
returns (uint128 lastNonce)
{
LibOtcOrdersStorage.Storage storage stor =
LibOtcOrdersStorage.getStorage();
return stor.txOriginNonces
[txOrigin]
[nonceBucket];
}
function _transferEth(address recipient, uint256 amount)
private
{
// Transfer ETH to recipient
(bool success, bytes memory revertData) =
recipient.call{value: amount}("");
// Revert on failure
if (!success) {
revertData.rrevert();
}
}
function _isSenderValidTaker(address orderTaker)
private
view
returns (bool)
{
return orderTaker == address(0) || orderTaker == msg.sender;
}
}

View File

@ -312,7 +312,7 @@ contract TransformERC20Feature is
// Transfer input tokens. // Transfer input tokens.
if (!LibERC20Transformer.isTokenETH(inputToken) && amount != 0) { if (!LibERC20Transformer.isTokenETH(inputToken) && amount != 0) {
// Token is not ETH, so pull ERC20 tokens. // Token is not ETH, so pull ERC20 tokens.
_transferERC20Tokens( _transferERC20TokensFrom(
inputToken, inputToken,
from, from,
to, to,

View File

@ -0,0 +1,419 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../vendor/IUniswapV3Pool.sol";
import "../migrations/LibMigrate.sol";
import "../fixins/FixinCommon.sol";
import "../fixins/FixinTokenSpender.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IUniswapV3Feature.sol";
/// @dev VIP uniswap fill functions.
contract UniswapV3Feature is
IFeature,
IUniswapV3Feature,
FixinCommon,
FixinTokenSpender
{
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "UniswapV3Feature";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev WETH contract.
IEtherTokenV06 private immutable WETH;
/// @dev UniswapV3 Factory contract address prepended with '0xff' and left-aligned.
bytes32 private immutable UNI_FF_FACTORY_ADDRESS;
/// @dev UniswapV3 pool init code hash.
bytes32 private immutable UNI_POOL_INIT_CODE_HASH;
/// @dev Minimum size of an encoded swap path:
/// sizeof(address(inputToken) | uint24(fee) | address(outputToken))
uint256 private constant SINGLE_HOP_PATH_SIZE = 20 + 3 + 20;
/// @dev How many bytes to skip ahead in an encoded path to start at the next hop:
/// sizeof(address(inputToken) | uint24(fee))
uint256 private constant PATH_SKIP_HOP_SIZE = 20 + 3;
/// @dev The size of the swap callback data.
uint256 private constant SWAP_CALLBACK_DATA_SIZE = 128;
/// @dev Minimum tick price sqrt ratio.
uint160 internal constant MIN_PRICE_SQRT_RATIO = 4295128739;
/// @dev Minimum tick price sqrt ratio.
uint160 internal constant MAX_PRICE_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @dev Mask of lower 20 bytes.
uint256 private constant ADDRESS_MASK = 0x00ffffffffffffffffffffffffffffffffffffffff;
/// @dev Mask of lower 3 bytes.
uint256 private constant UINT24_MASK = 0xffffff;
/// @dev Construct this contract.
/// @param weth The WETH contract.
/// @param uniFactory The UniswapV3 factory contract.
/// @param poolInitCodeHash The UniswapV3 pool init code hash.
constructor(
IEtherTokenV06 weth,
address uniFactory,
bytes32 poolInitCodeHash
) public {
WETH = weth;
UNI_FF_FACTORY_ADDRESS = bytes32((uint256(0xff) << 248) | (uint256(uniFactory) << 88));
UNI_POOL_INIT_CODE_HASH = poolInitCodeHash;
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
/// @return success `LibMigrate.SUCCESS` on success.
function migrate()
external
returns (bytes4 success)
{
_registerFeatureFunction(this.sellEthForTokenToUniswapV3.selector);
_registerFeatureFunction(this.sellTokenForEthToUniswapV3.selector);
_registerFeatureFunction(this.sellTokenForTokenToUniswapV3.selector);
_registerFeatureFunction(this.uniswapV3SwapCallback.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Sell attached ETH directly against uniswap v3.
/// @param encodedPath Uniswap-encoded path, where the first token is WETH.
/// @param recipient The recipient of the bought tokens. Can be zero for sender.
/// @param minBuyAmount Minimum amount of the last token in the path to buy.
/// @return buyAmount Amount of the last token in the path bought.
function sellEthForTokenToUniswapV3(
bytes memory encodedPath,
uint256 minBuyAmount,
address recipient
)
public
payable
override
returns (uint256 buyAmount)
{
// Wrap ETH.
WETH.deposit{ value: msg.value }();
return _swap(
encodedPath,
msg.value,
minBuyAmount,
address(this), // we are payer because we hold the WETH
_normalizeRecipient(recipient)
);
}
/// @dev Sell a token for ETH directly against uniswap v3.
/// @param encodedPath Uniswap-encoded path, where the last token is WETH.
/// @param sellAmount amount of the first token in the path to sell.
/// @param minBuyAmount Minimum amount of ETH to buy.
/// @param recipient The recipient of the bought tokens. Can be zero for sender.
/// @return buyAmount Amount of ETH bought.
function sellTokenForEthToUniswapV3(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address payable recipient
)
public
override
returns (uint256 buyAmount)
{
buyAmount = _swap(
encodedPath,
sellAmount,
minBuyAmount,
msg.sender,
address(this) // we are recipient because we need to unwrap WETH
);
WETH.withdraw(buyAmount);
// Transfer ETH to recipient.
(bool success, bytes memory revertData) =
_normalizeRecipient(recipient).call{ value: buyAmount }("");
if (!success) {
revertData.rrevert();
}
}
/// @dev Sell a token for another token directly against uniswap v3.
/// @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.
/// @return buyAmount Amount of the last token in the path bought.
function sellTokenForTokenToUniswapV3(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address recipient
)
public
override
returns (uint256 buyAmount)
{
buyAmount = _swap(
encodedPath,
sellAmount,
minBuyAmount,
msg.sender,
_normalizeRecipient(recipient)
);
}
/// @dev The UniswapV3 pool swap callback which pays the funds requested
/// by the caller/pool to the pool. Can only be called by a valid
/// UniswapV3 pool.
/// @param amount0Delta Token0 amount owed.
/// @param amount1Delta Token1 amount owed.
/// @param data Arbitrary data forwarded from swap() caller. An ABI-encoded
/// struct of: inputToken, outputToken, fee, payer
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
)
external
override
{
IERC20TokenV06 token0;
IERC20TokenV06 token1;
address payer;
{
uint24 fee;
// Decode the data.
require(data.length == SWAP_CALLBACK_DATA_SIZE, "UniswapFeature/INVALID_SWAP_CALLBACK_DATA");
assembly {
let p := add(36, calldataload(68))
token0 := calldataload(p)
token1 := calldataload(add(p, 32))
fee := calldataload(add(p, 64))
payer := calldataload(add(p, 96))
}
(token0, token1) = token0 < token1
? (token0, token1)
: (token1, token0);
// Only a valid pool contract can call this function.
require(
msg.sender == address(_toPool(token0, fee, token1)),
"UniswapV3Feature/INVALID_SWAP_CALLBACK_CALLER"
);
}
// Pay the amount owed to the pool.
if (amount0Delta > 0) {
_pay(token0, payer, msg.sender, uint256(amount0Delta));
} else if (amount1Delta > 0) {
_pay(token1, payer, msg.sender, uint256(amount1Delta));
} else {
revert("UniswapV3Feature/INVALID_SWAP_AMOUNTS");
}
}
// Executes successive swaps along an encoded uniswap path.
function _swap(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address payer,
address recipient
)
private
returns (uint256 buyAmount)
{
if (sellAmount != 0) {
require(sellAmount <= uint256(type(int256).max), "UniswapV3Feature/SELL_AMOUNT_OVERFLOW");
// Perform a swap for each hop in the path.
bytes memory swapCallbackData = new bytes(SWAP_CALLBACK_DATA_SIZE);
while (true) {
bool isPathMultiHop = _isPathMultiHop(encodedPath);
bool zeroForOne;
IUniswapV3Pool pool;
{
(
IERC20TokenV06 inputToken,
uint24 fee,
IERC20TokenV06 outputToken
) = _decodeFirstPoolInfoFromPath(encodedPath);
pool = _toPool(inputToken, fee, outputToken);
zeroForOne = inputToken < outputToken;
_updateSwapCallbackData(
swapCallbackData,
inputToken,
outputToken,
fee,
payer
);
}
(int256 amount0, int256 amount1) = pool.swap(
// Intermediate tokens go to this contract.
isPathMultiHop ? address(this) : recipient,
zeroForOne,
int256(sellAmount),
zeroForOne
? MIN_PRICE_SQRT_RATIO + 1
: MAX_PRICE_SQRT_RATIO - 1,
swapCallbackData
);
{
int256 _buyAmount = -(zeroForOne ? amount1 : amount0);
require(_buyAmount >= 0, "UniswapV3Feature/INVALID_BUY_AMOUNT");
buyAmount = uint256(_buyAmount);
}
if (!isPathMultiHop) {
// Done.
break;
}
// Continue with next hop.
payer = address(this); // Subsequent hops are paid for by us.
sellAmount = buyAmount;
// Skip to next hop along path.
encodedPath = _shiftHopFromPathInPlace(encodedPath);
}
}
require(minBuyAmount <= buyAmount, "UniswapV3Feature/UNDERBOUGHT");
}
// Pay tokens from `payer` to `to`, using `transferFrom()` if
// `payer` != this contract.
function _pay(
IERC20TokenV06 token,
address payer,
address to,
uint256 amount
)
private
{
if (payer != address(this)) {
_transferERC20TokensFrom(token, payer, to, amount);
} else {
_transferERC20Tokens(token, to, amount);
}
}
// Update `swapCallbackData` in place with new values.
function _updateSwapCallbackData(
bytes memory swapCallbackData,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint24 fee,
address payer
)
private
pure
{
assembly {
let p := add(swapCallbackData, 32)
mstore(p, inputToken)
mstore(add(p, 32), outputToken)
mstore(add(p, 64), and(UINT24_MASK, fee))
mstore(add(p, 96), and(ADDRESS_MASK, payer))
}
}
// Compute the pool address given two tokens and a fee.
function _toPool(
IERC20TokenV06 inputToken,
uint24 fee,
IERC20TokenV06 outputToken
)
private
view
returns (IUniswapV3Pool pool)
{
// address(keccak256(abi.encodePacked(
// hex"ff",
// UNI_FACTORY_ADDRESS,
// keccak256(abi.encode(inputToken, outputToken, fee)),
// UNI_POOL_INIT_CODE_HASH
// )))
bytes32 ffFactoryAddress = UNI_FF_FACTORY_ADDRESS;
bytes32 poolInitCodeHash = UNI_POOL_INIT_CODE_HASH;
(IERC20TokenV06 token0, IERC20TokenV06 token1) = inputToken < outputToken
? (inputToken, outputToken)
: (outputToken, inputToken);
assembly {
let s := mload(0x40)
let p := s
mstore(p, ffFactoryAddress)
p := add(p, 21)
// Compute the inner hash in-place
mstore(p, token0)
mstore(add(p, 32), token1)
mstore(add(p, 64), and(UINT24_MASK, fee))
mstore(p, keccak256(p, 96))
p := add(p, 32)
mstore(p, poolInitCodeHash)
pool := and(ADDRESS_MASK, keccak256(s, 85))
}
}
// Return whether or not an encoded uniswap path contains more than one hop.
function _isPathMultiHop(bytes memory encodedPath)
private
pure
returns (bool isMultiHop)
{
return encodedPath.length > SINGLE_HOP_PATH_SIZE;
}
// Return the first input token, output token, and fee of an encoded uniswap path.
function _decodeFirstPoolInfoFromPath(bytes memory encodedPath)
private
pure
returns (
IERC20TokenV06 inputToken,
uint24 fee,
IERC20TokenV06 outputToken
)
{
require(encodedPath.length >= SINGLE_HOP_PATH_SIZE, "UniswapV3Feature/BAD_PATH_ENCODING");
assembly {
let p := add(encodedPath, 32)
inputToken := shr(96, mload(p))
p := add(p, 20)
fee := shr(232, mload(p))
p := add(p, 3)
outputToken := shr(96, mload(p))
}
}
// Skip past the first hop of an encoded uniswap path in-place.
function _shiftHopFromPathInPlace(bytes memory encodedPath)
private
pure
returns (bytes memory shiftedEncodedPath)
{
require(encodedPath.length >= PATH_SKIP_HOP_SIZE, "UniswapV3Feature/BAD_PATH_ENCODING");
uint256 shiftSize = PATH_SKIP_HOP_SIZE;
uint256 newSize = encodedPath.length - shiftSize;
assembly {
shiftedEncodedPath := add(encodedPath, shiftSize)
mstore(shiftedEncodedPath, newSize)
}
}
// Convert null address values to msg.sender.
function _normalizeRecipient(address recipient)
private
view
returns (address payable normalizedRecipient)
{
return recipient == address(0) ? msg.sender : payable(recipient);
}
}

View File

@ -0,0 +1,122 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "../libs/LibNativeOrder.sol";
import "../libs/LibSignature.sol";
/// @dev Feature for interacting with OTC orders.
interface IOtcOrdersFeature {
/// @dev Emitted whenever an `OtcOrder` is filled.
/// @param orderHash The canonical hash of the order.
/// @param maker The maker of the order.
/// @param taker The taker of the order.
/// @param takerTokenFilledAmount How much taker token was filled.
/// @param makerTokenFilledAmount How much maker token was filled.
event OtcOrderFilled(
bytes32 orderHash,
address maker,
address taker,
address makerToken,
address takerToken,
uint128 takerTokenFilledAmount,
uint128 makerTokenFilledAmount
);
/// @dev Fill an OTC order for up to `takerTokenFillAmount` taker tokens.
/// @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 unwrapWeth Whether or not to unwrap bought WETH into ETH
/// before transferring it to the taker. Should be set to false
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function fillOtcOrder(
LibNativeOrder.OtcOrder calldata order,
LibSignature.Signature calldata makerSignature,
uint128 takerTokenFillAmount,
bool unwrapWeth
)
external
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
/// @dev Fill an OTC order whose taker token is WETH for up
/// to `msg.value`.
/// @param order The OTC order.
/// @param makerSignature The order signature from the maker.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function fillOtcOrderWithEth(
LibNativeOrder.OtcOrder calldata order,
LibSignature.Signature calldata makerSignature
)
external
payable
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
/// @dev Fully fill an OTC order. "Meta-transaction" variant,
/// requires order to be signed by both maker and taker.
/// @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.
/// @return takerTokenFilledAmount How much taker token was filled.
/// @return makerTokenFilledAmount How much maker token was filled.
function fillTakerSignedOtcOrder(
LibNativeOrder.OtcOrder calldata order,
LibSignature.Signature calldata makerSignature,
LibSignature.Signature calldata takerSignature,
bool unwrapWeth
)
external
returns (uint128 takerTokenFilledAmount, uint128 makerTokenFilledAmount);
/// @dev Get the order info for an OTC order.
/// @param order The OTC order.
/// @return orderInfo Info about the order.
function getOtcOrderInfo(LibNativeOrder.OtcOrder calldata order)
external
view
returns (LibNativeOrder.OtcOrderInfo memory orderInfo);
/// @dev Get the canonical hash of an OTC order.
/// @param order The OTC order.
/// @return orderHash The order hash.
function getOtcOrderHash(LibNativeOrder.OtcOrder calldata order)
external
view
returns (bytes32 orderHash);
/// @dev Get the last nonce used for a particular
/// tx.origin address and nonce bucket.
/// @param txOrigin The address.
/// @param nonceBucket The nonce bucket index.
/// @return lastNonce The last nonce value used.
function lastOtcTxOriginNonce(address txOrigin, uint64 nonceBucket)
external
view
returns (uint128 lastNonce);
}

View File

@ -0,0 +1,86 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev VIP uniswap v3 fill functions.
interface IUniswapV3Feature {
/// @dev Sell attached ETH directly against uniswap v3.
/// @param encodedPath Uniswap-encoded path, where the first token is WETH.
/// @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.
/// @return buyAmount Amount of the last token in the path bought.
function sellEthForTokenToUniswapV3(
bytes memory encodedPath,
uint256 minBuyAmount,
address recipient
)
external
payable
returns (uint256 buyAmount);
/// @dev Sell a token for ETH directly against uniswap v3.
/// @param encodedPath Uniswap-encoded path, where the last token is WETH.
/// @param sellAmount amount of the first token in the path to sell.
/// @param minBuyAmount Minimum amount of ETH to buy.
/// @param recipient The recipient of the bought tokens. Can be zero for sender.
/// @return buyAmount Amount of ETH bought.
function sellTokenForEthToUniswapV3(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address payable recipient
)
external
returns (uint256 buyAmount);
/// @dev Sell a token for another token directly against uniswap v3.
/// @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.
/// @return buyAmount Amount of the last token in the path bought.
function sellTokenForTokenToUniswapV3(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address recipient
)
external
returns (uint256 buyAmount);
/// @dev The UniswapV3 pool swap callback which pays the funds requested
/// by the caller/pool to the pool. Can only be called by a valid
/// UniswapV3 pool.
/// @param amount0Delta Token0 amount owed.
/// @param amount1Delta Token1 amount owed.
/// @param data Arbitrary data forwarded from swap() caller. An ABI-encoded
/// struct of: inputToken, outputToken, fee, payer
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
)
external;
}

View File

@ -69,6 +69,18 @@ library LibNativeOrder {
uint256 salt; uint256 salt;
} }
/// @dev An OTC limit order.
struct OtcOrder {
IERC20TokenV06 makerToken;
IERC20TokenV06 takerToken;
uint128 makerAmount;
uint128 takerAmount;
address maker;
address taker;
address txOrigin;
uint256 expiryAndNonce; // [uint64 expiry, uint64 nonceBucket, uint128 nonce]
}
/// @dev Info on a limit or RFQ order. /// @dev Info on a limit or RFQ order.
struct OrderInfo { struct OrderInfo {
bytes32 orderHash; bytes32 orderHash;
@ -76,6 +88,12 @@ library LibNativeOrder {
uint128 takerTokenFilledAmount; uint128 takerTokenFilledAmount;
} }
/// @dev Info on an OTC order.
struct OtcOrderInfo {
bytes32 orderHash;
OrderStatus status;
}
uint256 private constant UINT_128_MASK = (1 << 128) - 1; uint256 private constant UINT_128_MASK = (1 << 128) - 1;
uint256 private constant UINT_64_MASK = (1 << 64) - 1; uint256 private constant UINT_64_MASK = (1 << 64) - 1;
uint256 private constant ADDRESS_MASK = (1 << 160) - 1; uint256 private constant ADDRESS_MASK = (1 << 160) - 1;
@ -118,6 +136,22 @@ library LibNativeOrder {
uint256 private constant _RFQ_ORDER_TYPEHASH = uint256 private constant _RFQ_ORDER_TYPEHASH =
0xe593d3fdfa8b60e5e17a1b2204662ecbe15c23f2084b9ad5bae40359540a7da9; 0xe593d3fdfa8b60e5e17a1b2204662ecbe15c23f2084b9ad5bae40359540a7da9;
// The type hash for OTC orders, which is:
// keccak256(abi.encodePacked(
// "OtcOrder(",
// "address makerToken,",
// "address takerToken,",
// "uint128 makerAmount,",
// "uint128 takerAmount,",
// "address maker,",
// "address taker,",
// "address txOrigin,",
// "uint256 expiryAndNonce"
// ")"
// ))
uint256 private constant _OTC_ORDER_TYPEHASH =
0x2f754524de756ae72459efbe1ec88c19a745639821de528ac3fb88f9e65e35c8;
/// @dev Get the struct hash of a limit order. /// @dev Get the struct hash of a limit order.
/// @param order The limit order. /// @param order The limit order.
/// @return structHash The struct hash of the order. /// @return structHash The struct hash of the order.
@ -222,6 +256,49 @@ library LibNativeOrder {
} }
} }
/// @dev Get the struct hash of an OTC order.
/// @param order The OTC order.
/// @return structHash The struct hash of the order.
function getOtcOrderStructHash(OtcOrder memory order)
internal
pure
returns (bytes32 structHash)
{
// The struct hash is:
// keccak256(abi.encode(
// TYPE_HASH,
// order.makerToken,
// order.takerToken,
// order.makerAmount,
// order.takerAmount,
// order.maker,
// order.taker,
// order.txOrigin,
// order.expiryAndNonce,
// ))
assembly {
let mem := mload(0x40)
mstore(mem, _OTC_ORDER_TYPEHASH)
// order.makerToken;
mstore(add(mem, 0x20), and(ADDRESS_MASK, mload(order)))
// order.takerToken;
mstore(add(mem, 0x40), and(ADDRESS_MASK, mload(add(order, 0x20))))
// order.makerAmount;
mstore(add(mem, 0x60), and(UINT_128_MASK, mload(add(order, 0x40))))
// order.takerAmount;
mstore(add(mem, 0x80), and(UINT_128_MASK, mload(add(order, 0x60))))
// order.maker;
mstore(add(mem, 0xA0), and(ADDRESS_MASK, mload(add(order, 0x80))))
// order.taker;
mstore(add(mem, 0xC0), and(ADDRESS_MASK, mload(add(order, 0xA0))))
// order.txOrigin;
mstore(add(mem, 0xE0), and(ADDRESS_MASK, mload(add(order, 0xC0))))
// order.expiryAndNonce;
mstore(add(mem, 0x100), mload(add(order, 0xE0)))
structHash := keccak256(mem, 0x120)
}
}
/// @dev Refund any leftover protocol fees in `msg.value` to `msg.sender`. /// @dev Refund any leftover protocol fees in `msg.value` to `msg.sender`.
/// @param ethProtocolFeePaid How much ETH was paid in protocol fees. /// @param ethProtocolFeePaid How much ETH was paid in protocol fees.
function refundExcessProtocolFeeToSender(uint256 ethProtocolFeePaid) function refundExcessProtocolFeeToSender(uint256 ethProtocolFeePaid)

View File

@ -404,7 +404,7 @@ abstract contract NativeOrdersSettlement is
params.order.takerAmount, params.order.takerAmount,
params.order.takerTokenFeeAmount params.order.takerTokenFeeAmount
)); ));
_transferERC20Tokens( _transferERC20TokensFrom(
params.order.takerToken, params.order.takerToken,
params.taker, params.taker,
params.order.feeRecipient, params.order.feeRecipient,
@ -550,7 +550,7 @@ abstract contract NativeOrdersSettlement is
settleInfo.takerTokenFilledAmount.safeAdd128(takerTokenFilledAmount); settleInfo.takerTokenFilledAmount.safeAdd128(takerTokenFilledAmount);
// Transfer taker -> maker. // Transfer taker -> maker.
_transferERC20Tokens( _transferERC20TokensFrom(
settleInfo.takerToken, settleInfo.takerToken,
settleInfo.taker, settleInfo.taker,
settleInfo.maker, settleInfo.maker,
@ -558,7 +558,7 @@ abstract contract NativeOrdersSettlement is
); );
// Transfer maker -> taker. // Transfer maker -> taker.
_transferERC20Tokens( _transferERC20TokensFrom(
settleInfo.makerToken, settleInfo.makerToken,
settleInfo.maker, settleInfo.maker,
settleInfo.taker, settleInfo.taker,

View File

@ -35,7 +35,7 @@ abstract contract FixinTokenSpender {
/// @param owner The owner of the tokens. /// @param owner The owner of the tokens.
/// @param to The recipient of the tokens. /// @param to The recipient of the tokens.
/// @param amount The amount of `token` to transfer. /// @param amount The amount of `token` to transfer.
function _transferERC20Tokens( function _transferERC20TokensFrom(
IERC20TokenV06 token, IERC20TokenV06 token,
address owner, address owner,
address to, address to,
@ -87,6 +87,60 @@ abstract contract FixinTokenSpender {
} }
} }
/// @dev Transfers ERC20 tokens from ourselves to `to`.
/// @param token The token to spend.
/// @param to The recipient of the tokens.
/// @param amount The amount of `token` to transfer.
function _transferERC20Tokens(
IERC20TokenV06 token,
address to,
uint256 amount
)
internal
{
require(address(token) != address(this), "FixinTokenSpender/CANNOT_INVOKE_SELF");
assembly {
let ptr := mload(0x40) // free memory pointer
// selector for transfer(address,uint256)
mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(ptr, 0x04), and(to, ADDRESS_MASK))
mstore(add(ptr, 0x24), amount)
let success := call(
gas(),
and(token, ADDRESS_MASK),
0,
ptr,
0x44,
ptr,
32
)
let rdsize := returndatasize()
// Check for ERC20 success. ERC20 tokens should return a boolean,
// but some don't. We accept 0-length return data as success, or at
// least 32 bytes that starts with a 32-byte boolean true.
success := and(
success, // call itself succeeded
or(
iszero(rdsize), // no return data, or
and(
iszero(lt(rdsize, 32)), // at least 32 bytes
eq(mload(ptr), 1) // starts with uint256(1)
)
)
)
if iszero(success) {
returndatacopy(ptr, 0, rdsize)
revert(ptr, rdsize)
}
}
}
/// @dev Gets the maximum amount of an ERC20 token `token` that can be /// @dev Gets the maximum amount of an ERC20 token `token` that can be
/// pulled from `owner` by this address. /// pulled from `owner` by this address.
/// @param token The token to spend. /// @param token The token to spend.

View File

@ -0,0 +1,45 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
/// @dev Storage helpers for `OtcOrdersFeature`.
library LibOtcOrdersStorage {
/// @dev Storage bucket for this feature.
struct Storage {
// tx origin => nonce buckets => min nonce
mapping(address => mapping(uint64 => uint128)) txOriginNonces;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.getStorageSlot(
LibStorage.StorageId.OtcOrders
);
// Dip into assembly to change the slot pointed to by the local
// variable `stor`.
// See https://solidity.readthedocs.io/en/v0.6.8/assembly.html?highlight=slot#access-to-external-variables-functions-and-libraries
assembly { stor_slot := storageSlot }
}
}

View File

@ -38,7 +38,8 @@ library LibStorage {
TransformERC20, TransformERC20,
MetaTransactions, MetaTransactions,
ReentrancyGuard, ReentrancyGuard,
NativeOrders NativeOrders,
OtcOrders
} }
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced /// @dev Get the storage slot given a storage ID. We assign unique, well-spaced

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2021 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.12;
interface IUniswapV3Pool {
/// @notice Swap token0 for token1, or token1 for token0
/// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
/// @param recipient The address to receive the output of the swap
/// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
/// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
/// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
/// value after the swap. If one for zero, the price cannot be greater than this value after the swap
/// @param data Any data to be passed through to the callback
/// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
/// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
)
external
returns (int256 amount0, int256 amount1);
}

View File

@ -28,7 +28,7 @@ contract TestFixinTokenSpender is
{ {
constructor() public {} constructor() public {}
function transferERC20Tokens( function transferERC20TokensFrom(
IERC20TokenV06 token, IERC20TokenV06 token,
address owner, address owner,
address to, address to,
@ -36,7 +36,7 @@ contract TestFixinTokenSpender is
) )
external external
{ {
_transferERC20Tokens( _transferERC20TokensFrom(
token, token,
owner, owner,
to, to,

View File

@ -0,0 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.6;
contract TestNoEthRecipient {}

View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./TestUniswapV3Pool.sol";
contract TestUniswapV3Factory {
struct CreationParameters {
IERC20TokenV06 token0;
IERC20TokenV06 token1;
uint24 fee;
}
event PoolCreated(TestUniswapV3Pool pool);
bytes32 public immutable POOL_INIT_CODE_HASH;
mapping (IERC20TokenV06 => mapping (IERC20TokenV06 => mapping (uint24 => TestUniswapV3Pool))) public getPool;
CreationParameters public creationParameters;
constructor() public {
POOL_INIT_CODE_HASH = keccak256(type(TestUniswapV3Pool).creationCode);
}
function createPool(IERC20TokenV06 tokenA, IERC20TokenV06 tokenB, uint24 fee)
external
returns (TestUniswapV3Pool pool)
{
(IERC20TokenV06 token0, IERC20TokenV06 token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
require(
getPool[token0][token1][fee] == TestUniswapV3Pool(0),
"TestUniswapV3Factory/POOL_ALREADY_EXISTS"
);
creationParameters = CreationParameters({
token0: token0,
token1: token1,
fee: fee
});
pool = new TestUniswapV3Pool
{ salt: keccak256(abi.encode(token0, token1, fee)) }();
getPool[token0][token1][fee] = pool;
getPool[token1][token0][fee] = pool;
emit PoolCreated(pool);
}
}

View File

@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "../src/features/UniswapV3Feature.sol";
contract TestUniswapV3Feature is UniswapV3Feature {
constructor(
IEtherTokenV06 weth,
address uniFactory,
bytes32 poolInitCodeHash
)
UniswapV3Feature(weth, uniFactory, poolInitCodeHash)
public
{}
receive() external payable {}
}

View File

@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../src/vendor/IUniswapV3Pool.sol";
interface IUniswapV3PoolDeployer {
struct CreationParameters {
IERC20TokenV06 token0;
IERC20TokenV06 token1;
uint24 fee;
}
function creationParameters() external view returns (CreationParameters memory);
}
interface IUniswapV3SwapCallback {
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
)
external;
}
contract TestUniswapV3Pool is IUniswapV3Pool {
IERC20TokenV06 public immutable token0;
IERC20TokenV06 public immutable token1;
uint24 public immutable fee;
constructor() public {
IUniswapV3PoolDeployer.CreationParameters memory params =
IUniswapV3PoolDeployer(msg.sender).creationParameters();
(token0, token1, fee) = (params.token0, params.token1, params.fee);
}
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160,
bytes calldata data
)
external
override
returns (int256 amount0, int256 amount1)
{
uint256 balance0Before = token0.balanceOf(address(this));
uint256 balance1Before = token1.balanceOf(address(this));
if (zeroForOne) {
amount0 = int256(amountSpecified);
// Always buy 100% of other token balance.
amount1 = -int256(balance1Before);
token1.transfer(recipient, balance1Before);
} else {
amount0 = -int256(balance0Before);
// Always buy 100% of other token balance.
amount1 = int256(amountSpecified);
token0.transfer(recipient, balance0Before);
}
IUniswapV3SwapCallback(msg.sender).uniswapV3SwapCallback(
amount0,
amount1,
data
);
int256 balance0Change = int256(token0.balanceOf(address(this))) -
int256(balance0Before);
int256 balance1Change = int256(token1.balanceOf(address(this))) -
int256(balance1Before);
require(
balance0Change >= amount0 && balance1Change >= amount1,
"TestUniswapV3Pool/SWAP_NOT_PAID"
);
}
}

View File

@ -33,6 +33,13 @@ contract TestWeth is
this.mint(msg.sender, msg.value); this.mint(msg.sender, msg.value);
} }
function depositTo(address owner)
external
payable
{
this.mint(owner, msg.value);
}
function withdraw(uint256 amount) function withdraw(uint256 amount)
external external
{ {

View File

@ -41,9 +41,9 @@
"rollback": "node ./lib/scripts/rollback.js" "rollback": "node ./lib/scripts/rollback.js"
}, },
"config": { "config": {
"publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature", "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature,OtcOrdersFeature,IOtcOrdersFeature",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json" "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOtcOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IUniswapV3Feature|IUniswapV3Pool|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOtcOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinKyberDmm|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OtcOrdersFeature|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestNoEthRecipient|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestUniswapV3Factory|TestUniswapV3Feature|TestUniswapV3Pool|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|UniswapV3Feature|WethTransformer|ZeroEx|ZeroExOptimized).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -215,9 +215,7 @@ async function deploymentHistoryAsync(deployments: Deployment[], proxyFunctions:
logUtils.log(`\t[${update.selector}] ${update.signature || '(function signature not found)'}`); logUtils.log(`\t[${update.selector}] ${update.signature || '(function signature not found)'}`);
logUtils.log(`\t${update.previousImpl} => ${update.newImpl}`); logUtils.log(`\t${update.previousImpl} => ${update.newImpl}`);
logUtils.log( logUtils.log(
`Cannot find ${ `Cannot find ${update.previousImpl} in the selector's rollback history. It itself may have been previously rolled back.`,
update.previousImpl
} in the selector's rollback history. It itself may have been previously rolled back.`,
); );
return; return;
} }
@ -283,7 +281,9 @@ async function generateRollbackAsync(proxyFunctions: ProxyFunctionEntity[]): Pro
type: 'autocompleteMultiselect', type: 'autocompleteMultiselect',
name: 'selected', name: 'selected',
message: 'Select the functions to rollback:', message: 'Select the functions to rollback:',
choices: _.flatMap(proxyFunctions.filter(fn => fn.currentImpl !== constants.NULL_ADDRESS), fn => [ choices: _.flatMap(
proxyFunctions.filter(fn => fn.currentImpl !== constants.NULL_ADDRESS),
fn => [
{ {
title: [ title: [
`[${fn.id}]`, `[${fn.id}]`,
@ -292,7 +292,8 @@ async function generateRollbackAsync(proxyFunctions: ProxyFunctionEntity[]): Pro
].join('\n\t\t\t\t'), ].join('\n\t\t\t\t'),
value: fn.id, value: fn.id,
}, },
]), ],
),
}); });
const rollbackTargets: { [selector: string]: string } = {}; const rollbackTargets: { [selector: string]: string } = {};
for (const selector of selected) { for (const selector of selected) {

View File

@ -20,6 +20,7 @@ import * as ILiquidityProviderFeature from '../generated-artifacts/ILiquidityPro
import * as IMultiplexFeature from '../generated-artifacts/IMultiplexFeature.json'; import * as IMultiplexFeature from '../generated-artifacts/IMultiplexFeature.json';
import * as INativeOrdersFeature from '../generated-artifacts/INativeOrdersFeature.json'; import * as INativeOrdersFeature from '../generated-artifacts/INativeOrdersFeature.json';
import * as InitialMigration from '../generated-artifacts/InitialMigration.json'; import * as InitialMigration from '../generated-artifacts/InitialMigration.json';
import * as IOtcOrdersFeature from '../generated-artifacts/IOtcOrdersFeature.json';
import * as IOwnableFeature from '../generated-artifacts/IOwnableFeature.json'; import * as IOwnableFeature from '../generated-artifacts/IOwnableFeature.json';
import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json'; import * as ISimpleFunctionRegistryFeature from '../generated-artifacts/ISimpleFunctionRegistryFeature.json';
import * as ITransformERC20Feature from '../generated-artifacts/ITransformERC20Feature.json'; import * as ITransformERC20Feature from '../generated-artifacts/ITransformERC20Feature.json';
@ -29,6 +30,7 @@ import * as LogMetadataTransformer from '../generated-artifacts/LogMetadataTrans
import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransactionsFeature.json'; import * as MetaTransactionsFeature from '../generated-artifacts/MetaTransactionsFeature.json';
import * as MultiplexFeature from '../generated-artifacts/MultiplexFeature.json'; import * as MultiplexFeature from '../generated-artifacts/MultiplexFeature.json';
import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json'; import * as NativeOrdersFeature from '../generated-artifacts/NativeOrdersFeature.json';
import * as OtcOrdersFeature from '../generated-artifacts/OtcOrdersFeature.json';
import * as OwnableFeature from '../generated-artifacts/OwnableFeature.json'; import * as OwnableFeature from '../generated-artifacts/OwnableFeature.json';
import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json'; import * as PayTakerTransformer from '../generated-artifacts/PayTakerTransformer.json';
import * as PositiveSlippageFeeTransformer from '../generated-artifacts/PositiveSlippageFeeTransformer.json'; import * as PositiveSlippageFeeTransformer from '../generated-artifacts/PositiveSlippageFeeTransformer.json';
@ -68,4 +70,6 @@ export const artifacts = {
IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact, IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact,
MultiplexFeature: MultiplexFeature as ContractArtifact, MultiplexFeature: MultiplexFeature as ContractArtifact,
IMultiplexFeature: IMultiplexFeature as ContractArtifact, IMultiplexFeature: IMultiplexFeature as ContractArtifact,
OtcOrdersFeature: OtcOrdersFeature as ContractArtifact,
IOtcOrdersFeature: IOtcOrdersFeature as ContractArtifact,
}; };

View File

@ -57,20 +57,24 @@ export async function deployBootstrapFeaturesAsync(
return { return {
registry: registry:
features.registry || features.registry ||
(await SimpleFunctionRegistryFeatureContract.deployFrom0xArtifactAsync( (
await SimpleFunctionRegistryFeatureContract.deployFrom0xArtifactAsync(
_featureArtifacts.registry, _featureArtifacts.registry,
provider, provider,
txDefaults, txDefaults,
artifacts, artifacts,
)).address, )
).address,
ownable: ownable:
features.ownable || features.ownable ||
(await OwnableFeatureContract.deployFrom0xArtifactAsync( (
await OwnableFeatureContract.deployFrom0xArtifactAsync(
_featureArtifacts.ownable, _featureArtifacts.ownable,
provider, provider,
txDefaults, txDefaults,
artifacts, artifacts,
)).address, )
).address,
}; };
} }
@ -169,37 +173,44 @@ export async function deployFullFeaturesAsync(
...featureArtifacts, ...featureArtifacts,
}; };
if (_config.feeCollectorController === NULL_ADDRESS) { if (_config.feeCollectorController === NULL_ADDRESS) {
_config.feeCollectorController = (await FeeCollectorControllerContract.deployFrom0xArtifactAsync( _config.feeCollectorController = (
await FeeCollectorControllerContract.deployFrom0xArtifactAsync(
_featureArtifacts.feeCollectorController, _featureArtifacts.feeCollectorController,
provider, provider,
txDefaults, txDefaults,
artifacts, artifacts,
_config.wethAddress, _config.wethAddress,
_config.stakingAddress, _config.stakingAddress,
)).address; )
).address;
} }
return { return {
...(await deployBootstrapFeaturesAsync(provider, txDefaults)), ...(await deployBootstrapFeaturesAsync(provider, txDefaults)),
transformERC20: transformERC20:
features.transformERC20 || features.transformERC20 ||
(await TransformERC20FeatureContract.deployFrom0xArtifactAsync( (
await TransformERC20FeatureContract.deployFrom0xArtifactAsync(
_featureArtifacts.transformERC20, _featureArtifacts.transformERC20,
provider, provider,
txDefaults, txDefaults,
artifacts, artifacts,
)).address, )
).address,
metaTransactions: metaTransactions:
features.metaTransactions || features.metaTransactions ||
(await MetaTransactionsFeatureContract.deployFrom0xArtifactAsync( (
await MetaTransactionsFeatureContract.deployFrom0xArtifactAsync(
_featureArtifacts.metaTransactions, _featureArtifacts.metaTransactions,
provider, provider,
txDefaults, txDefaults,
artifacts, artifacts,
_config.zeroExAddress, _config.zeroExAddress,
)).address, )
).address,
nativeOrders: nativeOrders:
features.nativeOrders || features.nativeOrders ||
(await NativeOrdersFeatureContract.deployFrom0xArtifactAsync( (
await NativeOrdersFeatureContract.deployFrom0xArtifactAsync(
_featureArtifacts.nativeOrders, _featureArtifacts.nativeOrders,
provider, provider,
txDefaults, txDefaults,
@ -209,7 +220,8 @@ export async function deployFullFeaturesAsync(
_config.stakingAddress, _config.stakingAddress,
_config.feeCollectorController, _config.feeCollectorController,
_config.protocolFeeMultiplier, _config.protocolFeeMultiplier,
)).address, )
).address,
}; };
} }

View File

@ -17,6 +17,7 @@ export * from '../generated-wrappers/i_flash_wallet';
export * from '../generated-wrappers/i_liquidity_provider_feature'; export * from '../generated-wrappers/i_liquidity_provider_feature';
export * from '../generated-wrappers/i_multiplex_feature'; export * from '../generated-wrappers/i_multiplex_feature';
export * from '../generated-wrappers/i_native_orders_feature'; export * from '../generated-wrappers/i_native_orders_feature';
export * from '../generated-wrappers/i_otc_orders_feature';
export * from '../generated-wrappers/i_ownable_feature'; export * from '../generated-wrappers/i_ownable_feature';
export * from '../generated-wrappers/i_simple_function_registry_feature'; export * from '../generated-wrappers/i_simple_function_registry_feature';
export * from '../generated-wrappers/i_transform_erc20_feature'; export * from '../generated-wrappers/i_transform_erc20_feature';
@ -27,6 +28,7 @@ export * from '../generated-wrappers/log_metadata_transformer';
export * from '../generated-wrappers/meta_transactions_feature'; export * from '../generated-wrappers/meta_transactions_feature';
export * from '../generated-wrappers/multiplex_feature'; export * from '../generated-wrappers/multiplex_feature';
export * from '../generated-wrappers/native_orders_feature'; export * from '../generated-wrappers/native_orders_feature';
export * from '../generated-wrappers/otc_orders_feature';
export * from '../generated-wrappers/ownable_feature'; export * from '../generated-wrappers/ownable_feature';
export * from '../generated-wrappers/pay_taker_transformer'; export * from '../generated-wrappers/pay_taker_transformer';
export * from '../generated-wrappers/positive_slippage_fee_transformer'; export * from '../generated-wrappers/positive_slippage_fee_transformer';

View File

@ -37,6 +37,7 @@ import * as IMultiplexFeature from '../test/generated-artifacts/IMultiplexFeatur
import * as INativeOrdersEvents from '../test/generated-artifacts/INativeOrdersEvents.json'; import * as INativeOrdersEvents from '../test/generated-artifacts/INativeOrdersEvents.json';
import * as INativeOrdersFeature from '../test/generated-artifacts/INativeOrdersFeature.json'; import * as INativeOrdersFeature from '../test/generated-artifacts/INativeOrdersFeature.json';
import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json'; import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json';
import * as IOtcOrdersFeature from '../test/generated-artifacts/IOtcOrdersFeature.json';
import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json'; import * as IOwnableFeature from '../test/generated-artifacts/IOwnableFeature.json';
import * as IPancakeSwapFeature from '../test/generated-artifacts/IPancakeSwapFeature.json'; import * as IPancakeSwapFeature from '../test/generated-artifacts/IPancakeSwapFeature.json';
import * as ISimpleFunctionRegistryFeature from '../test/generated-artifacts/ISimpleFunctionRegistryFeature.json'; import * as ISimpleFunctionRegistryFeature from '../test/generated-artifacts/ISimpleFunctionRegistryFeature.json';
@ -46,6 +47,8 @@ import * as ITokenSpenderFeature from '../test/generated-artifacts/ITokenSpender
import * as ITransformERC20Feature from '../test/generated-artifacts/ITransformERC20Feature.json'; import * as ITransformERC20Feature from '../test/generated-artifacts/ITransformERC20Feature.json';
import * as IUniswapFeature from '../test/generated-artifacts/IUniswapFeature.json'; import * as IUniswapFeature from '../test/generated-artifacts/IUniswapFeature.json';
import * as IUniswapV2Pair from '../test/generated-artifacts/IUniswapV2Pair.json'; import * as IUniswapV2Pair from '../test/generated-artifacts/IUniswapV2Pair.json';
import * as IUniswapV3Feature from '../test/generated-artifacts/IUniswapV3Feature.json';
import * as IUniswapV3Pool from '../test/generated-artifacts/IUniswapV3Pool.json';
import * as IZeroEx from '../test/generated-artifacts/IZeroEx.json'; import * as IZeroEx from '../test/generated-artifacts/IZeroEx.json';
import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json'; import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json';
import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json'; import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json';
@ -58,6 +61,7 @@ import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
import * as LibNativeOrder from '../test/generated-artifacts/LibNativeOrder.json'; import * as LibNativeOrder from '../test/generated-artifacts/LibNativeOrder.json';
import * as LibNativeOrdersRichErrors from '../test/generated-artifacts/LibNativeOrdersRichErrors.json'; import * as LibNativeOrdersRichErrors from '../test/generated-artifacts/LibNativeOrdersRichErrors.json';
import * as LibNativeOrdersStorage from '../test/generated-artifacts/LibNativeOrdersStorage.json'; import * as LibNativeOrdersStorage from '../test/generated-artifacts/LibNativeOrdersStorage.json';
import * as LibOtcOrdersStorage from '../test/generated-artifacts/LibOtcOrdersStorage.json';
import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json'; import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json';
import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json'; import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json';
import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErrors.json'; import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErrors.json';
@ -102,6 +106,7 @@ import * as NativeOrdersFeature from '../test/generated-artifacts/NativeOrdersFe
import * as NativeOrdersInfo from '../test/generated-artifacts/NativeOrdersInfo.json'; import * as NativeOrdersInfo from '../test/generated-artifacts/NativeOrdersInfo.json';
import * as NativeOrdersProtocolFees from '../test/generated-artifacts/NativeOrdersProtocolFees.json'; import * as NativeOrdersProtocolFees from '../test/generated-artifacts/NativeOrdersProtocolFees.json';
import * as NativeOrdersSettlement from '../test/generated-artifacts/NativeOrdersSettlement.json'; import * as NativeOrdersSettlement from '../test/generated-artifacts/NativeOrdersSettlement.json';
import * as OtcOrdersFeature from '../test/generated-artifacts/OtcOrdersFeature.json';
import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json'; import * as OwnableFeature from '../test/generated-artifacts/OwnableFeature.json';
import * as PancakeSwapFeature from '../test/generated-artifacts/PancakeSwapFeature.json'; import * as PancakeSwapFeature from '../test/generated-artifacts/PancakeSwapFeature.json';
import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json'; import * as PayTakerTransformer from '../test/generated-artifacts/PayTakerTransformer.json';
@ -130,6 +135,7 @@ import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintabl
import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json'; import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json';
import * as TestMooniswap from '../test/generated-artifacts/TestMooniswap.json'; import * as TestMooniswap from '../test/generated-artifacts/TestMooniswap.json';
import * as TestNativeOrdersFeature from '../test/generated-artifacts/TestNativeOrdersFeature.json'; import * as TestNativeOrdersFeature from '../test/generated-artifacts/TestNativeOrdersFeature.json';
import * as TestNoEthRecipient from '../test/generated-artifacts/TestNoEthRecipient.json';
import * as TestOrderSignerRegistryWithContractWallet from '../test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json'; import * as TestOrderSignerRegistryWithContractWallet from '../test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json';
import * as TestPermissionlessTransformerDeployerSuicidal from '../test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json'; import * as TestPermissionlessTransformerDeployerSuicidal from '../test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json';
import * as TestPermissionlessTransformerDeployerTransformer from '../test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json'; import * as TestPermissionlessTransformerDeployerTransformer from '../test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json';
@ -142,6 +148,9 @@ import * as TestTransformerBase from '../test/generated-artifacts/TestTransforme
import * as TestTransformERC20 from '../test/generated-artifacts/TestTransformERC20.json'; import * as TestTransformERC20 from '../test/generated-artifacts/TestTransformERC20.json';
import * as TestTransformerDeployerTransformer from '../test/generated-artifacts/TestTransformerDeployerTransformer.json'; import * as TestTransformerDeployerTransformer from '../test/generated-artifacts/TestTransformerDeployerTransformer.json';
import * as TestTransformerHost from '../test/generated-artifacts/TestTransformerHost.json'; import * as TestTransformerHost from '../test/generated-artifacts/TestTransformerHost.json';
import * as TestUniswapV3Factory from '../test/generated-artifacts/TestUniswapV3Factory.json';
import * as TestUniswapV3Feature from '../test/generated-artifacts/TestUniswapV3Feature.json';
import * as TestUniswapV3Pool from '../test/generated-artifacts/TestUniswapV3Pool.json';
import * as TestWeth from '../test/generated-artifacts/TestWeth.json'; import * as TestWeth from '../test/generated-artifacts/TestWeth.json';
import * as TestWethTransformerHost from '../test/generated-artifacts/TestWethTransformerHost.json'; import * as TestWethTransformerHost from '../test/generated-artifacts/TestWethTransformerHost.json';
import * as TestZeroExFeature from '../test/generated-artifacts/TestZeroExFeature.json'; import * as TestZeroExFeature from '../test/generated-artifacts/TestZeroExFeature.json';
@ -149,6 +158,7 @@ import * as Transformer from '../test/generated-artifacts/Transformer.json';
import * as TransformERC20Feature from '../test/generated-artifacts/TransformERC20Feature.json'; import * as TransformERC20Feature from '../test/generated-artifacts/TransformERC20Feature.json';
import * as TransformerDeployer from '../test/generated-artifacts/TransformerDeployer.json'; import * as TransformerDeployer from '../test/generated-artifacts/TransformerDeployer.json';
import * as UniswapFeature from '../test/generated-artifacts/UniswapFeature.json'; import * as UniswapFeature from '../test/generated-artifacts/UniswapFeature.json';
import * as UniswapV3Feature from '../test/generated-artifacts/UniswapV3Feature.json';
import * as WethTransformer from '../test/generated-artifacts/WethTransformer.json'; import * as WethTransformer from '../test/generated-artifacts/WethTransformer.json';
import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json'; import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json';
import * as ZeroExOptimized from '../test/generated-artifacts/ZeroExOptimized.json'; import * as ZeroExOptimized from '../test/generated-artifacts/ZeroExOptimized.json';
@ -181,11 +191,13 @@ export const artifacts = {
MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact, MetaTransactionsFeature: MetaTransactionsFeature as ContractArtifact,
MultiplexFeature: MultiplexFeature as ContractArtifact, MultiplexFeature: MultiplexFeature as ContractArtifact,
NativeOrdersFeature: NativeOrdersFeature as ContractArtifact, NativeOrdersFeature: NativeOrdersFeature as ContractArtifact,
OtcOrdersFeature: OtcOrdersFeature as ContractArtifact,
OwnableFeature: OwnableFeature as ContractArtifact, OwnableFeature: OwnableFeature as ContractArtifact,
PancakeSwapFeature: PancakeSwapFeature as ContractArtifact, PancakeSwapFeature: PancakeSwapFeature as ContractArtifact,
SimpleFunctionRegistryFeature: SimpleFunctionRegistryFeature as ContractArtifact, SimpleFunctionRegistryFeature: SimpleFunctionRegistryFeature as ContractArtifact,
TransformERC20Feature: TransformERC20Feature as ContractArtifact, TransformERC20Feature: TransformERC20Feature as ContractArtifact,
UniswapFeature: UniswapFeature as ContractArtifact, UniswapFeature: UniswapFeature as ContractArtifact,
UniswapV3Feature: UniswapV3Feature as ContractArtifact,
IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact, IBatchFillNativeOrdersFeature: IBatchFillNativeOrdersFeature as ContractArtifact,
IBootstrapFeature: IBootstrapFeature as ContractArtifact, IBootstrapFeature: IBootstrapFeature as ContractArtifact,
IFeature: IFeature as ContractArtifact, IFeature: IFeature as ContractArtifact,
@ -194,12 +206,14 @@ export const artifacts = {
IMultiplexFeature: IMultiplexFeature as ContractArtifact, IMultiplexFeature: IMultiplexFeature as ContractArtifact,
INativeOrdersEvents: INativeOrdersEvents as ContractArtifact, INativeOrdersEvents: INativeOrdersEvents as ContractArtifact,
INativeOrdersFeature: INativeOrdersFeature as ContractArtifact, INativeOrdersFeature: INativeOrdersFeature as ContractArtifact,
IOtcOrdersFeature: IOtcOrdersFeature as ContractArtifact,
IOwnableFeature: IOwnableFeature as ContractArtifact, IOwnableFeature: IOwnableFeature as ContractArtifact,
IPancakeSwapFeature: IPancakeSwapFeature as ContractArtifact, IPancakeSwapFeature: IPancakeSwapFeature as ContractArtifact,
ISimpleFunctionRegistryFeature: ISimpleFunctionRegistryFeature as ContractArtifact, ISimpleFunctionRegistryFeature: ISimpleFunctionRegistryFeature as ContractArtifact,
ITokenSpenderFeature: ITokenSpenderFeature as ContractArtifact, ITokenSpenderFeature: ITokenSpenderFeature as ContractArtifact,
ITransformERC20Feature: ITransformERC20Feature as ContractArtifact, ITransformERC20Feature: ITransformERC20Feature as ContractArtifact,
IUniswapFeature: IUniswapFeature as ContractArtifact, IUniswapFeature: IUniswapFeature as ContractArtifact,
IUniswapV3Feature: IUniswapV3Feature as ContractArtifact,
LibNativeOrder: LibNativeOrder as ContractArtifact, LibNativeOrder: LibNativeOrder as ContractArtifact,
LibSignature: LibSignature as ContractArtifact, LibSignature: LibSignature as ContractArtifact,
NativeOrdersCancellation: NativeOrdersCancellation as ContractArtifact, NativeOrdersCancellation: NativeOrdersCancellation as ContractArtifact,
@ -219,6 +233,7 @@ export const artifacts = {
LibMigrate: LibMigrate as ContractArtifact, LibMigrate: LibMigrate as ContractArtifact,
LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact, LibMetaTransactionsStorage: LibMetaTransactionsStorage as ContractArtifact,
LibNativeOrdersStorage: LibNativeOrdersStorage as ContractArtifact, LibNativeOrdersStorage: LibNativeOrdersStorage as ContractArtifact,
LibOtcOrdersStorage: LibOtcOrdersStorage as ContractArtifact,
LibOwnableStorage: LibOwnableStorage as ContractArtifact, LibOwnableStorage: LibOwnableStorage as ContractArtifact,
LibProxyStorage: LibProxyStorage as ContractArtifact, LibProxyStorage: LibProxyStorage as ContractArtifact,
LibReentrancyGuardStorage: LibReentrancyGuardStorage as ContractArtifact, LibReentrancyGuardStorage: LibReentrancyGuardStorage as ContractArtifact,
@ -260,6 +275,7 @@ export const artifacts = {
ILiquidityProvider: ILiquidityProvider as ContractArtifact, ILiquidityProvider: ILiquidityProvider as ContractArtifact,
IMooniswapPool: IMooniswapPool as ContractArtifact, IMooniswapPool: IMooniswapPool as ContractArtifact,
IUniswapV2Pair: IUniswapV2Pair as ContractArtifact, IUniswapV2Pair: IUniswapV2Pair as ContractArtifact,
IUniswapV3Pool: IUniswapV3Pool as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact, IERC20Bridge: IERC20Bridge as ContractArtifact,
IStaking: IStaking as ContractArtifact, IStaking: IStaking as ContractArtifact,
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
@ -285,6 +301,7 @@ export const artifacts = {
TestMintableERC20Token: TestMintableERC20Token as ContractArtifact, TestMintableERC20Token: TestMintableERC20Token as ContractArtifact,
TestMooniswap: TestMooniswap as ContractArtifact, TestMooniswap: TestMooniswap as ContractArtifact,
TestNativeOrdersFeature: TestNativeOrdersFeature as ContractArtifact, TestNativeOrdersFeature: TestNativeOrdersFeature as ContractArtifact,
TestNoEthRecipient: TestNoEthRecipient as ContractArtifact,
TestOrderSignerRegistryWithContractWallet: TestOrderSignerRegistryWithContractWallet as ContractArtifact, TestOrderSignerRegistryWithContractWallet: TestOrderSignerRegistryWithContractWallet as ContractArtifact,
TestPermissionlessTransformerDeployerSuicidal: TestPermissionlessTransformerDeployerSuicidal as ContractArtifact, TestPermissionlessTransformerDeployerSuicidal: TestPermissionlessTransformerDeployerSuicidal as ContractArtifact,
TestPermissionlessTransformerDeployerTransformer: TestPermissionlessTransformerDeployerTransformer as ContractArtifact, TestPermissionlessTransformerDeployerTransformer: TestPermissionlessTransformerDeployerTransformer as ContractArtifact,
@ -297,6 +314,9 @@ export const artifacts = {
TestTransformerBase: TestTransformerBase as ContractArtifact, TestTransformerBase: TestTransformerBase as ContractArtifact,
TestTransformerDeployerTransformer: TestTransformerDeployerTransformer as ContractArtifact, TestTransformerDeployerTransformer: TestTransformerDeployerTransformer as ContractArtifact,
TestTransformerHost: TestTransformerHost as ContractArtifact, TestTransformerHost: TestTransformerHost as ContractArtifact,
TestUniswapV3Factory: TestUniswapV3Factory as ContractArtifact,
TestUniswapV3Feature: TestUniswapV3Feature as ContractArtifact,
TestUniswapV3Pool: TestUniswapV3Pool as ContractArtifact,
TestWeth: TestWeth as ContractArtifact, TestWeth: TestWeth as ContractArtifact,
TestWethTransformerHost: TestWethTransformerHost as ContractArtifact, TestWethTransformerHost: TestWethTransformerHost as ContractArtifact,
TestZeroExFeature: TestZeroExFeature as ContractArtifact, TestZeroExFeature: TestZeroExFeature as ContractArtifact,

View File

@ -141,7 +141,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const value = testUtils.protocolFee.times(orders.length); const value = testUtils.protocolFee.times(orders.length);
const tx = await feature const tx = await feature
.batchFillLimitOrders(orders, signatures, orders.map(order => order.takerAmount), false) .batchFillLimitOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
false,
)
.awaitTransactionSuccessAsync({ from: taker, value }); .awaitTransactionSuccessAsync({ from: taker, value });
const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync();
orderInfos.map((orderInfo, i) => orderInfos.map((orderInfo, i) =>
@ -192,7 +197,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const value = testUtils.protocolFee.times(orders.length).plus(420); const value = testUtils.protocolFee.times(orders.length).plus(420);
const tx = await feature const tx = await feature
.batchFillLimitOrders(orders, signatures, orders.map(order => order.takerAmount), false) .batchFillLimitOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
false,
)
.awaitTransactionSuccessAsync({ from: taker, value }); .awaitTransactionSuccessAsync({ from: taker, value });
const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync();
orderInfos.map((orderInfo, i) => orderInfos.map((orderInfo, i) =>
@ -219,7 +229,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const value = testUtils.protocolFee.times(orders.length); const value = testUtils.protocolFee.times(orders.length);
const tx = await feature const tx = await feature
.batchFillLimitOrders(orders, signatures, orders.map(order => order.takerAmount), false) .batchFillLimitOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
false,
)
.awaitTransactionSuccessAsync({ from: taker, value }); .awaitTransactionSuccessAsync({ from: taker, value });
const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync();
const [expiredOrderInfo, ...filledOrderInfos] = orderInfos; const [expiredOrderInfo, ...filledOrderInfos] = orderInfos;
@ -250,7 +265,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const value = testUtils.protocolFee.times(orders.length); const value = testUtils.protocolFee.times(orders.length);
const tx = await feature const tx = await feature
.batchFillLimitOrders(orders, signatures, orders.map(order => order.takerAmount), true) .batchFillLimitOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
true,
)
.awaitTransactionSuccessAsync({ from: taker, value }); .awaitTransactionSuccessAsync({ from: taker, value });
const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetLimitOrderRelevantStates(orders, signatures).callAsync();
orderInfos.map((orderInfo, i) => orderInfos.map((orderInfo, i) =>
@ -277,7 +297,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const value = testUtils.protocolFee.times(orders.length); const value = testUtils.protocolFee.times(orders.length);
const tx = feature const tx = feature
.batchFillLimitOrders(orders, signatures, orders.map(order => order.takerAmount), true) .batchFillLimitOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
true,
)
.awaitTransactionSuccessAsync({ from: taker, value }); .awaitTransactionSuccessAsync({ from: taker, value });
return expect(tx).to.revertWith( return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.BatchFillIncompleteError( new RevertErrors.NativeOrders.BatchFillIncompleteError(
@ -299,7 +324,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const value = testUtils.protocolFee.times(orders.length); const value = testUtils.protocolFee.times(orders.length);
const tx = feature const tx = feature
.batchFillLimitOrders(orders, signatures, orders.map(order => order.takerAmount), true) .batchFillLimitOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
true,
)
.awaitTransactionSuccessAsync({ from: taker, value }); .awaitTransactionSuccessAsync({ from: taker, value });
return expect(tx).to.revertWith( return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.BatchFillIncompleteError( new RevertErrors.NativeOrders.BatchFillIncompleteError(
@ -337,7 +367,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
); );
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const tx = await feature const tx = await feature
.batchFillRfqOrders(orders, signatures, orders.map(order => order.takerAmount), false) .batchFillRfqOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
false,
)
.awaitTransactionSuccessAsync({ from: taker }); .awaitTransactionSuccessAsync({ from: taker });
const [orderInfos] = await zeroEx.batchGetRfqOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetRfqOrderRelevantStates(orders, signatures).callAsync();
orderInfos.map((orderInfo, i) => orderInfos.map((orderInfo, i) =>
@ -388,7 +423,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
); );
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const tx = await feature const tx = await feature
.batchFillRfqOrders(orders, signatures, orders.map(order => order.takerAmount), false) .batchFillRfqOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
false,
)
.awaitTransactionSuccessAsync({ from: taker }); .awaitTransactionSuccessAsync({ from: taker });
const [orderInfos] = await zeroEx.batchGetRfqOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetRfqOrderRelevantStates(orders, signatures).callAsync();
const [expiredOrderInfo, ...filledOrderInfos] = orderInfos; const [expiredOrderInfo, ...filledOrderInfos] = orderInfos;
@ -418,7 +458,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
); );
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const tx = await feature const tx = await feature
.batchFillRfqOrders(orders, signatures, orders.map(order => order.takerAmount), true) .batchFillRfqOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
true,
)
.awaitTransactionSuccessAsync({ from: taker }); .awaitTransactionSuccessAsync({ from: taker });
const [orderInfos] = await zeroEx.batchGetRfqOrderRelevantStates(orders, signatures).callAsync(); const [orderInfos] = await zeroEx.batchGetRfqOrderRelevantStates(orders, signatures).callAsync();
orderInfos.map((orderInfo, i) => orderInfos.map((orderInfo, i) =>
@ -444,7 +489,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
); );
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const tx = feature const tx = feature
.batchFillRfqOrders(orders, signatures, orders.map(order => order.takerAmount), true) .batchFillRfqOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
true,
)
.awaitTransactionSuccessAsync({ from: taker }); .awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith( return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.BatchFillIncompleteError( new RevertErrors.NativeOrders.BatchFillIncompleteError(
@ -465,7 +515,12 @@ blockchainTests.resets('BatchFillNativeOrdersFeature', env => {
); );
await testUtils.prepareBalancesForOrdersAsync(orders); await testUtils.prepareBalancesForOrdersAsync(orders);
const tx = feature const tx = feature
.batchFillRfqOrders(orders, signatures, orders.map(order => order.takerAmount), true) .batchFillRfqOrders(
orders,
signatures,
orders.map(order => order.takerAmount),
true,
)
.awaitTransactionSuccessAsync({ from: taker }); .awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith( return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.BatchFillIncompleteError( new RevertErrors.NativeOrders.BatchFillIncompleteError(

View File

@ -304,7 +304,10 @@ blockchainTests.fork.skip('Multiplex feature', env => {
{ {
name: 'transformations', name: 'transformations',
type: 'tuple[]', type: 'tuple[]',
components: [{ name: 'deploymentNonce', type: 'uint32' }, { name: 'data', type: 'bytes' }], components: [
{ name: 'deploymentNonce', type: 'uint32' },
{ name: 'data', type: 'bytes' },
],
}, },
{ name: 'ethValue', type: 'uint256' }, { name: 'ethValue', type: 'uint256' },
]); ]);
@ -439,7 +442,10 @@ blockchainTests.fork.skip('Multiplex feature', env => {
{ {
name: 'transformations', name: 'transformations',
type: 'tuple[]', type: 'tuple[]',
components: [{ name: 'deploymentNonce', type: 'uint32' }, { name: 'data', type: 'bytes' }], components: [
{ name: 'deploymentNonce', type: 'uint32' },
{ name: 'data', type: 'bytes' },
],
}, },
{ name: 'ethValue', type: 'uint256' }, { name: 'ethValue', type: 'uint256' },
]); ]);
@ -460,7 +466,10 @@ blockchainTests.fork.skip('Multiplex feature', env => {
{ {
name: 'calls', name: 'calls',
type: 'tuple[]', type: 'tuple[]',
components: [{ name: 'selector', type: 'bytes4' }, { name: 'data', type: 'bytes' }], components: [
{ name: 'selector', type: 'bytes4' },
{ name: 'data', type: 'bytes' },
],
}, },
{ name: 'ethValue', type: 'uint256' }, { name: 'ethValue', type: 'uint256' },
]); ]);

View File

@ -0,0 +1,753 @@
import { blockchainTests, constants, describe, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
import { OrderStatus, OtcOrder, RevertErrors, SignatureType } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils';
import { IOwnableFeatureContract, IZeroExContract, IZeroExEvents } from '../../src/wrappers';
import { artifacts } from '../artifacts';
import { abis } from '../utils/abis';
import { fullMigrateAsync } from '../utils/migration';
import {
computeOtcOrderFilledAmounts,
createExpiry,
getRandomOtcOrder,
NativeOrdersTestEnvironment,
} from '../utils/orders';
import {
OtcOrdersFeatureContract,
TestMintableERC20TokenContract,
TestOrderSignerRegistryWithContractWalletContract,
TestWethContract,
} from '../wrappers';
blockchainTests.resets('OtcOrdersFeature', env => {
const { NULL_ADDRESS, MAX_UINT256, ZERO_AMOUNT: ZERO } = constants;
let maker: string;
let taker: string;
let notMaker: string;
let notTaker: string;
let contractWalletOwner: string;
let contractWalletSigner: string;
let txOrigin: string;
let notTxOrigin: string;
let zeroEx: IZeroExContract;
let verifyingContract: string;
let makerToken: TestMintableERC20TokenContract;
let takerToken: TestMintableERC20TokenContract;
let wethToken: TestWethContract;
let contractWallet: TestOrderSignerRegistryWithContractWalletContract;
let testUtils: NativeOrdersTestEnvironment;
before(async () => {
// Useful for ETH balance accounting
const txDefaults = { ...env.txDefaults, gasPrice: 0 };
let owner;
[
owner,
maker,
taker,
notMaker,
notTaker,
contractWalletOwner,
contractWalletSigner,
txOrigin,
notTxOrigin,
] = await env.getAccountAddressesAsync();
[makerToken, takerToken] = await Promise.all(
[...new Array(2)].map(async () =>
TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestMintableERC20Token,
env.provider,
txDefaults,
artifacts,
),
),
);
wethToken = await TestWethContract.deployFrom0xArtifactAsync(
artifacts.TestWeth,
env.provider,
txDefaults,
artifacts,
);
zeroEx = await fullMigrateAsync(owner, env.provider, txDefaults, {}, { wethAddress: wethToken.address });
const otcFeatureImpl = await OtcOrdersFeatureContract.deployFrom0xArtifactAsync(
artifacts.OtcOrdersFeature,
env.provider,
txDefaults,
artifacts,
zeroEx.address,
wethToken.address,
);
await new IOwnableFeatureContract(zeroEx.address, env.provider, txDefaults, abis)
.migrate(otcFeatureImpl.address, otcFeatureImpl.migrate().getABIEncodedTransactionData(), owner)
.awaitTransactionSuccessAsync();
verifyingContract = zeroEx.address;
await Promise.all([
makerToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: maker }),
makerToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: notMaker }),
takerToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: taker }),
takerToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: notTaker }),
wethToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: maker }),
wethToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: notMaker }),
wethToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: taker }),
wethToken.approve(zeroEx.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: notTaker }),
]);
// contract wallet for signer delegation
contractWallet = await TestOrderSignerRegistryWithContractWalletContract.deployFrom0xArtifactAsync(
artifacts.TestOrderSignerRegistryWithContractWallet,
env.provider,
{
from: contractWalletOwner,
},
artifacts,
zeroEx.address,
);
await contractWallet
.approveERC20(makerToken.address, zeroEx.address, MAX_UINT256)
.awaitTransactionSuccessAsync({ from: contractWalletOwner });
await contractWallet
.approveERC20(takerToken.address, zeroEx.address, MAX_UINT256)
.awaitTransactionSuccessAsync({ from: contractWalletOwner });
testUtils = new NativeOrdersTestEnvironment(maker, taker, makerToken, takerToken, zeroEx, ZERO, ZERO, env);
});
function getTestOtcOrder(fields: Partial<OtcOrder> = {}): OtcOrder {
return getRandomOtcOrder({
maker,
verifyingContract,
chainId: 1337,
takerToken: takerToken.address,
makerToken: makerToken.address,
taker: NULL_ADDRESS,
txOrigin: taker,
...fields,
});
}
describe('getOtcOrderHash()', () => {
it('returns the correct hash', async () => {
const order = getTestOtcOrder();
const hash = await zeroEx.getOtcOrderHash(order).callAsync();
expect(hash).to.eq(order.getHash());
});
});
describe('lastOtcTxOriginNonce()', () => {
it('returns 0 if bucket is unused', async () => {
const nonce = await zeroEx.lastOtcTxOriginNonce(taker, ZERO).callAsync();
expect(nonce).to.bignumber.eq(0);
});
it('returns the last nonce used in a bucket', async () => {
const order = getTestOtcOrder();
await testUtils.fillOtcOrderAsync(order);
const nonce = await zeroEx.lastOtcTxOriginNonce(taker, order.nonceBucket).callAsync();
expect(nonce).to.bignumber.eq(order.nonce);
});
});
describe('getOtcOrderInfo()', () => {
it('unfilled order', async () => {
const order = getTestOtcOrder();
const info = await zeroEx.getOtcOrderInfo(order).callAsync();
expect(info).to.deep.equal({
status: OrderStatus.Fillable,
orderHash: order.getHash(),
});
});
it('unfilled expired order', async () => {
const expiry = createExpiry(-60);
const order = getTestOtcOrder({ expiry });
const info = await zeroEx.getOtcOrderInfo(order).callAsync();
expect(info).to.deep.equal({
status: OrderStatus.Expired,
orderHash: order.getHash(),
});
});
it('filled then expired order', async () => {
const expiry = createExpiry(60);
const order = getTestOtcOrder({ expiry });
await testUtils.fillOtcOrderAsync(order);
// Advance time to expire the order.
await env.web3Wrapper.increaseTimeAsync(61);
const info = await zeroEx.getOtcOrderInfo(order).callAsync();
expect(info).to.deep.equal({
status: OrderStatus.Invalid,
orderHash: order.getHash(),
});
});
it('filled order', async () => {
const order = getTestOtcOrder();
// Fill the order first.
await testUtils.fillOtcOrderAsync(order);
const info = await zeroEx.getOtcOrderInfo(order).callAsync();
expect(info).to.deep.equal({
status: OrderStatus.Invalid,
orderHash: order.getHash(),
});
});
});
async function assertExpectedFinalBalancesFromOtcOrderFillAsync(
order: OtcOrder,
takerTokenFillAmount: BigNumber = order.takerAmount,
): Promise<void> {
const { makerTokenFilledAmount, takerTokenFilledAmount } = computeOtcOrderFilledAmounts(
order,
takerTokenFillAmount,
);
const makerBalance = await new TestMintableERC20TokenContract(order.takerToken, env.provider)
.balanceOf(order.maker)
.callAsync();
const takerBalance = await new TestMintableERC20TokenContract(order.makerToken, env.provider)
.balanceOf(order.taker !== NULL_ADDRESS ? order.taker : taker)
.callAsync();
expect(makerBalance, 'maker balance').to.bignumber.eq(takerTokenFilledAmount);
expect(takerBalance, 'taker balance').to.bignumber.eq(makerTokenFilledAmount);
}
describe('fillOtcOrder()', () => {
it('can fully fill an order', async () => {
const order = getTestOtcOrder();
const receipt = await testUtils.fillOtcOrderAsync(order);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order);
});
it('can partially fill an order', async () => {
const order = getTestOtcOrder();
const fillAmount = order.takerAmount.minus(1);
const receipt = await testUtils.fillOtcOrderAsync(order, fillAmount);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order, fillAmount)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order, fillAmount);
});
it('clamps fill amount to remaining available', async () => {
const order = getTestOtcOrder();
const fillAmount = order.takerAmount.plus(1);
const receipt = await testUtils.fillOtcOrderAsync(order, fillAmount);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order, fillAmount)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order, fillAmount);
});
it('cannot fill an order with wrong tx.origin', async () => {
const order = getTestOtcOrder();
const tx = testUtils.fillOtcOrderAsync(order, order.takerAmount, notTaker);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByOriginError(order.getHash(), notTaker, taker),
);
});
it('cannot fill an order with wrong taker', async () => {
const order = getTestOtcOrder({ taker: notTaker });
const tx = testUtils.fillOtcOrderAsync(order);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByTakerError(order.getHash(), taker, notTaker),
);
});
it('can fill an order from a different tx.origin if registered', async () => {
const order = getTestOtcOrder();
await zeroEx.registerAllowedRfqOrigins([notTaker], true).awaitTransactionSuccessAsync({ from: taker });
return testUtils.fillOtcOrderAsync(order, order.takerAmount, notTaker);
});
it('cannot fill an order with registered then unregistered tx.origin', async () => {
const order = getTestOtcOrder();
await zeroEx.registerAllowedRfqOrigins([notTaker], true).awaitTransactionSuccessAsync({ from: taker });
await zeroEx.registerAllowedRfqOrigins([notTaker], false).awaitTransactionSuccessAsync({ from: taker });
const tx = testUtils.fillOtcOrderAsync(order, order.takerAmount, notTaker);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByOriginError(order.getHash(), notTaker, taker),
);
});
it('cannot fill an order with a zero tx.origin', async () => {
const order = getTestOtcOrder({ txOrigin: NULL_ADDRESS });
const tx = testUtils.fillOtcOrderAsync(order);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByOriginError(order.getHash(), taker, NULL_ADDRESS),
);
});
it('cannot fill an expired order', async () => {
const order = getTestOtcOrder({ expiry: createExpiry(-60) });
const tx = testUtils.fillOtcOrderAsync(order);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order.getHash(), OrderStatus.Expired),
);
});
it('cannot fill order with bad signature', async () => {
const order = getTestOtcOrder();
// Overwrite chainId to result in a different hash and therefore different
// signature.
const tx = testUtils.fillOtcOrderAsync(order.clone({ chainId: 1234 }));
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotSignedByMakerError(order.getHash(), undefined, order.maker),
);
});
it('fails if ETH is attached', async () => {
const order = getTestOtcOrder();
await testUtils.prepareBalancesForOrdersAsync([order], taker);
const tx = zeroEx
.fillOtcOrder(order, await order.getSignatureWithProviderAsync(env.provider), order.takerAmount, false)
.awaitTransactionSuccessAsync({ from: taker, value: 1 });
// This will revert at the language level because the fill function is not payable.
return expect(tx).to.be.rejectedWith('revert');
});
it('cannot fill the same order twice', async () => {
const order = getTestOtcOrder();
await testUtils.fillOtcOrderAsync(order);
const tx = testUtils.fillOtcOrderAsync(order);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order.getHash(), OrderStatus.Invalid),
);
});
it('cannot fill two orders with the same nonceBucket and nonce', async () => {
const order1 = getTestOtcOrder();
await testUtils.fillOtcOrderAsync(order1);
const order2 = getTestOtcOrder({ nonceBucket: order1.nonceBucket, nonce: order1.nonce });
const tx = testUtils.fillOtcOrderAsync(order2);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order2.getHash(), OrderStatus.Invalid),
);
});
it('cannot fill an order whose nonce is less than the nonce last used in that bucket', async () => {
const order1 = getTestOtcOrder();
await testUtils.fillOtcOrderAsync(order1);
const order2 = getTestOtcOrder({ nonceBucket: order1.nonceBucket, nonce: order1.nonce.minus(1) });
const tx = testUtils.fillOtcOrderAsync(order2);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order2.getHash(), OrderStatus.Invalid),
);
});
it('can fill two orders that use the same nonce bucket and increasing nonces', async () => {
const order1 = getTestOtcOrder();
const tx1 = await testUtils.fillOtcOrderAsync(order1);
verifyEventsFromLogs(
tx1.logs,
[testUtils.createOtcOrderFilledEventArgs(order1)],
IZeroExEvents.OtcOrderFilled,
);
const order2 = getTestOtcOrder({ nonceBucket: order1.nonceBucket, nonce: order1.nonce.plus(1) });
const tx2 = await testUtils.fillOtcOrderAsync(order2);
verifyEventsFromLogs(
tx2.logs,
[testUtils.createOtcOrderFilledEventArgs(order2)],
IZeroExEvents.OtcOrderFilled,
);
});
it('can fill two orders that use the same nonce but different nonce buckets', async () => {
const order1 = getTestOtcOrder();
const tx1 = await testUtils.fillOtcOrderAsync(order1);
verifyEventsFromLogs(
tx1.logs,
[testUtils.createOtcOrderFilledEventArgs(order1)],
IZeroExEvents.OtcOrderFilled,
);
const order2 = getTestOtcOrder({ nonce: order1.nonce });
const tx2 = await testUtils.fillOtcOrderAsync(order2);
verifyEventsFromLogs(
tx2.logs,
[testUtils.createOtcOrderFilledEventArgs(order2)],
IZeroExEvents.OtcOrderFilled,
);
});
it('can fill a WETH buy order and receive ETH', async () => {
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(taker);
const order = getTestOtcOrder({ makerToken: wethToken.address, makerAmount: new BigNumber('1e18') });
await wethToken.deposit().awaitTransactionSuccessAsync({ from: maker, value: order.makerAmount });
const receipt = await testUtils.fillOtcOrderAsync(order, order.takerAmount, taker, true);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(taker);
expect(takerEthBalanceAfter.minus(takerEthBalanceBefore)).to.bignumber.equal(order.makerAmount);
});
it('reverts if `unwrapWeth` is true but maker token is not WETH', async () => {
const order = getTestOtcOrder();
const tx = testUtils.fillOtcOrderAsync(order, order.takerAmount, taker, true);
return expect(tx).to.revertWith('OtcOrdersFeature/INVALID_UNWRAP_WETH');
});
it('allows for fills on orders signed by a approved signer', async () => {
const order = getTestOtcOrder({ maker: contractWallet.address });
const sig = await order.getSignatureWithProviderAsync(
env.provider,
SignatureType.EthSign,
contractWalletSigner,
);
// covers taker
await testUtils.prepareBalancesForOrdersAsync([order]);
// need to provide contract wallet with a balance
await makerToken.mint(contractWallet.address, order.makerAmount).awaitTransactionSuccessAsync();
// allow signer
await contractWallet
.registerAllowedOrderSigner(contractWalletSigner, true)
.awaitTransactionSuccessAsync({ from: contractWalletOwner });
// fill should succeed
const receipt = await zeroEx
.fillOtcOrder(order, sig, order.takerAmount, false)
.awaitTransactionSuccessAsync({ from: taker });
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order);
});
it('disallows fills if the signer is revoked', async () => {
const order = getTestOtcOrder({ maker: contractWallet.address });
const sig = await order.getSignatureWithProviderAsync(
env.provider,
SignatureType.EthSign,
contractWalletSigner,
);
// covers taker
await testUtils.prepareBalancesForOrdersAsync([order]);
// need to provide contract wallet with a balance
await makerToken.mint(contractWallet.address, order.makerAmount).awaitTransactionSuccessAsync();
// first allow signer
await contractWallet
.registerAllowedOrderSigner(contractWalletSigner, true)
.awaitTransactionSuccessAsync({ from: contractWalletOwner });
// then disallow signer
await contractWallet
.registerAllowedOrderSigner(contractWalletSigner, false)
.awaitTransactionSuccessAsync({ from: contractWalletOwner });
// fill should revert
const tx = zeroEx
.fillOtcOrder(order, sig, order.takerAmount, false)
.awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotSignedByMakerError(
order.getHash(),
contractWalletSigner,
order.maker,
),
);
});
it(`doesn't allow fills with an unapproved signer`, async () => {
const order = getTestOtcOrder({ maker: contractWallet.address });
const sig = await order.getSignatureWithProviderAsync(env.provider, SignatureType.EthSign, maker);
// covers taker
await testUtils.prepareBalancesForOrdersAsync([order]);
// need to provide contract wallet with a balance
await makerToken.mint(contractWallet.address, order.makerAmount).awaitTransactionSuccessAsync();
// fill should revert
const tx = zeroEx
.fillOtcOrder(order, sig, order.takerAmount, false)
.awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotSignedByMakerError(order.getHash(), maker, order.maker),
);
});
});
describe('fillOtcOrderWithEth()', () => {
it('Can fill an order with ETH', async () => {
const order = getTestOtcOrder({ takerToken: wethToken.address });
const receipt = await testUtils.fillOtcOrderWithEthAsync(order);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order);
});
it('Can partially fill an order with ETH', async () => {
const order = getTestOtcOrder({ takerToken: wethToken.address });
const fillAmount = order.takerAmount.minus(1);
const receipt = await testUtils.fillOtcOrderWithEthAsync(order, fillAmount);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order, fillAmount)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order, fillAmount);
});
it('Can refund excess ETH is msg.value > order.takerAmount', async () => {
const order = getTestOtcOrder({ takerToken: wethToken.address });
const fillAmount = order.takerAmount.plus(420);
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(taker);
const receipt = await testUtils.fillOtcOrderWithEthAsync(order, fillAmount);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(taker);
expect(takerEthBalanceBefore.minus(takerEthBalanceAfter)).to.bignumber.equal(order.takerAmount);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order);
});
it('Cannot fill an order if taker token is not WETH', async () => {
const order = getTestOtcOrder();
const tx = testUtils.fillOtcOrderWithEthAsync(order);
return expect(tx).to.revertWith('OtcOrdersFeature/INVALID_WRAP_ETH');
});
});
describe('fillTakerSignedOtcOrder()', () => {
it('can fully fill an order', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
const receipt = await testUtils.fillTakerSignedOtcOrderAsync(order);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order);
});
it('cannot fill an order with wrong tx.origin', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order, notTxOrigin);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByOriginError(order.getHash(), notTxOrigin, txOrigin),
);
});
it('can fill an order from a different tx.origin if registered', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
await zeroEx
.registerAllowedRfqOrigins([notTxOrigin], true)
.awaitTransactionSuccessAsync({ from: txOrigin });
return testUtils.fillTakerSignedOtcOrderAsync(order, notTxOrigin);
});
it('cannot fill an order with registered then unregistered tx.origin', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
await zeroEx
.registerAllowedRfqOrigins([notTxOrigin], true)
.awaitTransactionSuccessAsync({ from: txOrigin });
await zeroEx
.registerAllowedRfqOrigins([notTxOrigin], false)
.awaitTransactionSuccessAsync({ from: txOrigin });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order, notTxOrigin);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByOriginError(order.getHash(), notTxOrigin, txOrigin),
);
});
it('cannot fill an order with a zero tx.origin', async () => {
const order = getTestOtcOrder({ taker, txOrigin: NULL_ADDRESS });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order, txOrigin);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableByOriginError(order.getHash(), txOrigin, NULL_ADDRESS),
);
});
it('cannot fill an expired order', async () => {
const order = getTestOtcOrder({ taker, txOrigin, expiry: createExpiry(-60) });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order.getHash(), OrderStatus.Expired),
);
});
it('cannot fill an order with bad taker signature', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order, txOrigin, notTaker);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotSignedByTakerError(order.getHash(), notTaker, taker),
);
});
it('cannot fill order with bad maker signature', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
// Overwrite chainId to result in a different hash and therefore different
// signature.
const tx = testUtils.fillTakerSignedOtcOrderAsync(order.clone({ chainId: 1234 }));
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotSignedByMakerError(order.getHash(), undefined, order.maker),
);
});
it('fails if ETH is attached', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
await testUtils.prepareBalancesForOrdersAsync([order], taker);
const tx = zeroEx
.fillTakerSignedOtcOrder(
order,
await order.getSignatureWithProviderAsync(env.provider),
await order.getSignatureWithProviderAsync(env.provider, SignatureType.EthSign, taker),
false,
)
.awaitTransactionSuccessAsync({ from: txOrigin, value: 1 });
// This will revert at the language level because the fill function is not payable.
return expect(tx).to.be.rejectedWith('revert');
});
it('cannot fill the same order twice', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
await testUtils.fillTakerSignedOtcOrderAsync(order);
const tx = testUtils.fillTakerSignedOtcOrderAsync(order);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order.getHash(), OrderStatus.Invalid),
);
});
it('cannot fill two orders with the same nonceBucket and nonce', async () => {
const order1 = getTestOtcOrder({ taker, txOrigin });
await testUtils.fillTakerSignedOtcOrderAsync(order1);
const order2 = getTestOtcOrder({ taker, txOrigin, nonceBucket: order1.nonceBucket, nonce: order1.nonce });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order2);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order2.getHash(), OrderStatus.Invalid),
);
});
it('cannot fill an order whose nonce is less than the nonce last used in that bucket', async () => {
const order1 = getTestOtcOrder({ taker, txOrigin });
await testUtils.fillTakerSignedOtcOrderAsync(order1);
const order2 = getTestOtcOrder({
taker,
txOrigin,
nonceBucket: order1.nonceBucket,
nonce: order1.nonce.minus(1),
});
const tx = testUtils.fillTakerSignedOtcOrderAsync(order2);
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotFillableError(order2.getHash(), OrderStatus.Invalid),
);
});
it('can fill two orders that use the same nonce bucket and increasing nonces', async () => {
const order1 = getTestOtcOrder({ taker, txOrigin });
const tx1 = await testUtils.fillTakerSignedOtcOrderAsync(order1);
verifyEventsFromLogs(
tx1.logs,
[testUtils.createOtcOrderFilledEventArgs(order1)],
IZeroExEvents.OtcOrderFilled,
);
const order2 = getTestOtcOrder({
taker,
txOrigin,
nonceBucket: order1.nonceBucket,
nonce: order1.nonce.plus(1),
});
const tx2 = await testUtils.fillTakerSignedOtcOrderAsync(order2);
verifyEventsFromLogs(
tx2.logs,
[testUtils.createOtcOrderFilledEventArgs(order2)],
IZeroExEvents.OtcOrderFilled,
);
});
it('can fill two orders that use the same nonce but different nonce buckets', async () => {
const order1 = getTestOtcOrder({ taker, txOrigin });
const tx1 = await testUtils.fillTakerSignedOtcOrderAsync(order1);
verifyEventsFromLogs(
tx1.logs,
[testUtils.createOtcOrderFilledEventArgs(order1)],
IZeroExEvents.OtcOrderFilled,
);
const order2 = getTestOtcOrder({ taker, txOrigin, nonce: order1.nonce });
const tx2 = await testUtils.fillTakerSignedOtcOrderAsync(order2);
verifyEventsFromLogs(
tx2.logs,
[testUtils.createOtcOrderFilledEventArgs(order2)],
IZeroExEvents.OtcOrderFilled,
);
});
it('can fill a WETH buy order and receive ETH', async () => {
const takerEthBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(taker);
const order = getTestOtcOrder({
taker,
txOrigin,
makerToken: wethToken.address,
makerAmount: new BigNumber('1e18'),
});
await wethToken.deposit().awaitTransactionSuccessAsync({ from: maker, value: order.makerAmount });
const receipt = await testUtils.fillTakerSignedOtcOrderAsync(order, txOrigin, taker, true);
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
const takerEthBalanceAfter = await env.web3Wrapper.getBalanceInWeiAsync(taker);
expect(takerEthBalanceAfter.minus(takerEthBalanceBefore)).to.bignumber.equal(order.makerAmount);
});
it('reverts if `unwrapWeth` is true but maker token is not WETH', async () => {
const order = getTestOtcOrder({ taker, txOrigin });
const tx = testUtils.fillTakerSignedOtcOrderAsync(order, txOrigin, taker, true);
return expect(tx).to.revertWith('OtcOrdersFeature/INVALID_UNWRAP_WETH');
});
it('allows for fills on orders signed by a approved signer (taker)', async () => {
const order = getTestOtcOrder({ txOrigin, taker: contractWallet.address });
await testUtils.prepareBalancesForOrdersAsync([order], contractWallet.address);
// allow signer
await contractWallet
.registerAllowedOrderSigner(contractWalletSigner, true)
.awaitTransactionSuccessAsync({ from: contractWalletOwner });
// fill should succeed
const receipt = await zeroEx
.fillTakerSignedOtcOrder(
order,
await order.getSignatureWithProviderAsync(env.provider),
await order.getSignatureWithProviderAsync(
env.provider,
SignatureType.EthSign,
contractWalletSigner,
),
false,
)
.awaitTransactionSuccessAsync({ from: txOrigin });
verifyEventsFromLogs(
receipt.logs,
[testUtils.createOtcOrderFilledEventArgs(order)],
IZeroExEvents.OtcOrderFilled,
);
await assertExpectedFinalBalancesFromOtcOrderFillAsync(order);
});
it(`doesn't allow fills with an unapproved signer (taker)`, async () => {
const order = getTestOtcOrder({ txOrigin, taker: contractWallet.address });
await testUtils.prepareBalancesForOrdersAsync([order], contractWallet.address);
// fill should succeed
const tx = zeroEx
.fillTakerSignedOtcOrder(
order,
await order.getSignatureWithProviderAsync(env.provider),
await order.getSignatureWithProviderAsync(env.provider, SignatureType.EthSign, notTaker),
false,
)
.awaitTransactionSuccessAsync({ from: txOrigin });
return expect(tx).to.revertWith(
new RevertErrors.NativeOrders.OrderNotSignedByTakerError(order.getHash(), notTaker, order.taker),
);
});
});
});

View File

@ -43,12 +43,14 @@ blockchainTests.resets('TransformERC20 feature', env => {
env.provider, env.provider,
env.txDefaults, env.txDefaults,
{ {
transformERC20: (await TestTransformERC20Contract.deployFrom0xArtifactAsync( transformERC20: (
await TestTransformERC20Contract.deployFrom0xArtifactAsync(
artifacts.TestTransformERC20, artifacts.TestTransformERC20,
env.provider, env.provider,
env.txDefaults, env.txDefaults,
artifacts, artifacts,
)).address, )
).address,
}, },
{ transformerDeployer }, { transformerDeployer },
); );

View File

@ -0,0 +1,258 @@
import {
blockchainTests,
constants,
describe,
expect,
getRandomPortion,
randomAddress,
} from '@0x/contracts-test-utils';
import { BigNumber, hexUtils } from '@0x/utils';
import { LogWithDecodedArgs } from 'ethereum-types';
import { artifacts } from '../artifacts';
import {
TestMintableERC20TokenContract,
TestNoEthRecipientContract,
TestUniswapV3FactoryContract,
TestUniswapV3FactoryPoolCreatedEventArgs,
TestUniswapV3PoolContract,
TestWethContract,
UniswapV3FeatureContract,
} from '../wrappers';
blockchainTests.resets('UniswapV3Feature', env => {
const { MAX_UINT256, NULL_ADDRESS, ZERO_AMOUNT } = constants;
const POOL_FEE = 1234;
const MAX_SUPPLY = new BigNumber('10e18');
let uniFactory: TestUniswapV3FactoryContract;
let feature: UniswapV3FeatureContract;
let weth: TestWethContract;
let tokens: TestMintableERC20TokenContract[];
const sellAmount = getRandomPortion(MAX_SUPPLY);
const buyAmount = getRandomPortion(MAX_SUPPLY);
let taker: string;
const recipient = randomAddress();
let noEthRecipient: TestNoEthRecipientContract;
before(async () => {
[, taker] = await env.getAccountAddressesAsync();
weth = await TestWethContract.deployFrom0xArtifactAsync(
artifacts.TestWeth,
env.provider,
env.txDefaults,
artifacts,
);
tokens = await Promise.all(
[...new Array(3)].map(async () =>
TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestMintableERC20Token,
env.provider,
env.txDefaults,
artifacts,
),
),
);
noEthRecipient = await TestNoEthRecipientContract.deployFrom0xArtifactAsync(
artifacts.TestNoEthRecipient,
env.provider,
env.txDefaults,
artifacts,
);
uniFactory = await TestUniswapV3FactoryContract.deployFrom0xArtifactAsync(
artifacts.TestUniswapV3Factory,
env.provider,
env.txDefaults,
artifacts,
);
feature = await UniswapV3FeatureContract.deployFrom0xArtifactAsync(
artifacts.TestUniswapV3Feature,
env.provider,
env.txDefaults,
artifacts,
weth.address,
uniFactory.address,
await uniFactory.POOL_INIT_CODE_HASH().callAsync(),
);
await Promise.all(
[...tokens, weth].map(t =>
t.approve(feature.address, MAX_UINT256).awaitTransactionSuccessAsync({ from: taker }),
),
);
});
function isWethContract(t: TestMintableERC20TokenContract | TestWethContract): t is TestWethContract {
return !!(t as any).deposit;
}
async function mintToAsync(
token: TestMintableERC20TokenContract | TestWethContract,
owner: string,
amount: BigNumber,
): Promise<void> {
if (isWethContract(token)) {
await token.depositTo(owner).awaitTransactionSuccessAsync({ value: amount });
} else {
await token.mint(owner, amount).awaitTransactionSuccessAsync();
}
}
async function createPoolAsync(
token0: TestMintableERC20TokenContract | TestWethContract,
token1: TestMintableERC20TokenContract | TestWethContract,
balance0: BigNumber,
balance1: BigNumber,
): Promise<TestUniswapV3PoolContract> {
const r = await uniFactory
.createPool(token0.address, token1.address, new BigNumber(POOL_FEE))
.awaitTransactionSuccessAsync();
const pool = new TestUniswapV3PoolContract(
(r.logs[0] as LogWithDecodedArgs<TestUniswapV3FactoryPoolCreatedEventArgs>).args.pool,
env.provider,
env.txDefaults,
);
await mintToAsync(token0, pool.address, balance0);
await mintToAsync(token1, pool.address, balance1);
return pool;
}
function encodePath(tokens_: Array<TestMintableERC20TokenContract | TestWethContract>): string {
const elems: string[] = [];
tokens_.forEach((t, i) => {
if (i) {
elems.push(hexUtils.leftPad(POOL_FEE, 3));
}
elems.push(hexUtils.leftPad(t.address, 20));
});
return hexUtils.concat(...elems);
}
describe('sellTokenForTokenToUniswapV3()', () => {
it('1-hop swap', async () => {
const [sellToken, buyToken] = tokens;
const pool = await createPoolAsync(sellToken, buyToken, ZERO_AMOUNT, buyAmount);
await mintToAsync(sellToken, taker, sellAmount);
await feature
.sellTokenForTokenToUniswapV3(encodePath([sellToken, buyToken]), sellAmount, buyAmount, recipient)
.awaitTransactionSuccessAsync({ from: taker });
// Test pools always ask for full sell amount and pay entire balance.
expect(await sellToken.balanceOf(taker).callAsync()).to.bignumber.eq(0);
expect(await buyToken.balanceOf(recipient).callAsync()).to.bignumber.eq(buyAmount);
expect(await sellToken.balanceOf(pool.address).callAsync()).to.bignumber.eq(sellAmount);
});
it('2-hop swap', async () => {
const pools = [
await createPoolAsync(tokens[0], tokens[1], ZERO_AMOUNT, buyAmount),
await createPoolAsync(tokens[1], tokens[2], ZERO_AMOUNT, buyAmount),
];
await mintToAsync(tokens[0], taker, sellAmount);
await feature
.sellTokenForTokenToUniswapV3(encodePath(tokens), sellAmount, buyAmount, recipient)
.awaitTransactionSuccessAsync({ from: taker });
// Test pools always ask for full sell amount and pay entire balance.
expect(await tokens[0].balanceOf(taker).callAsync()).to.bignumber.eq(0);
expect(await tokens[2].balanceOf(recipient).callAsync()).to.bignumber.eq(buyAmount);
expect(await tokens[0].balanceOf(pools[0].address).callAsync()).to.bignumber.eq(sellAmount);
expect(await tokens[1].balanceOf(pools[1].address).callAsync()).to.bignumber.eq(buyAmount);
});
it('1-hop underbuy fails', async () => {
const [sellToken, buyToken] = tokens;
await createPoolAsync(sellToken, buyToken, ZERO_AMOUNT, buyAmount.minus(1));
await mintToAsync(sellToken, taker, sellAmount);
const tx = feature
.sellTokenForTokenToUniswapV3(encodePath([sellToken, buyToken]), sellAmount, buyAmount, recipient)
.awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith('UniswapV3Feature/UNDERBOUGHT');
});
it('2-hop underbuy fails', async () => {
await createPoolAsync(tokens[0], tokens[1], ZERO_AMOUNT, buyAmount);
await createPoolAsync(tokens[1], tokens[2], ZERO_AMOUNT, buyAmount.minus(1));
await mintToAsync(tokens[0], taker, sellAmount);
const tx = feature
.sellTokenForTokenToUniswapV3(encodePath(tokens), sellAmount, buyAmount, recipient)
.awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.revertWith('UniswapV3Feature/UNDERBOUGHT');
});
it('null recipient is sender', async () => {
const [sellToken, buyToken] = tokens;
await createPoolAsync(sellToken, buyToken, ZERO_AMOUNT, buyAmount);
await mintToAsync(sellToken, taker, sellAmount);
await feature
.sellTokenForTokenToUniswapV3(encodePath([sellToken, buyToken]), sellAmount, buyAmount, NULL_ADDRESS)
.awaitTransactionSuccessAsync({ from: taker });
// Test pools always ask for full sell amount and pay entire balance.
expect(await buyToken.balanceOf(taker).callAsync()).to.bignumber.eq(buyAmount);
});
});
describe('sellEthForTokenToUniswapV3()', () => {
it('1-hop swap', async () => {
const [buyToken] = tokens;
const pool = await createPoolAsync(weth, buyToken, ZERO_AMOUNT, buyAmount);
await feature
.sellEthForTokenToUniswapV3(encodePath([weth, buyToken]), buyAmount, recipient)
.awaitTransactionSuccessAsync({ from: taker, value: sellAmount });
// Test pools always ask for full sell amount and pay entire balance.
expect(await buyToken.balanceOf(recipient).callAsync()).to.bignumber.eq(buyAmount);
expect(await weth.balanceOf(pool.address).callAsync()).to.bignumber.eq(sellAmount);
});
it('null recipient is sender', async () => {
const [buyToken] = tokens;
const pool = await createPoolAsync(weth, buyToken, ZERO_AMOUNT, buyAmount);
await feature
.sellEthForTokenToUniswapV3(encodePath([weth, buyToken]), buyAmount, NULL_ADDRESS)
.awaitTransactionSuccessAsync({ from: taker, value: sellAmount });
// Test pools always ask for full sell amount and pay entire balance.
expect(await buyToken.balanceOf(taker).callAsync()).to.bignumber.eq(buyAmount);
expect(await weth.balanceOf(pool.address).callAsync()).to.bignumber.eq(sellAmount);
});
});
describe('sellTokenForEthToUniswapV3()', () => {
it('1-hop swap', async () => {
const [sellToken] = tokens;
const pool = await createPoolAsync(sellToken, weth, ZERO_AMOUNT, buyAmount);
await mintToAsync(sellToken, taker, sellAmount);
await feature
.sellTokenForEthToUniswapV3(encodePath([sellToken, weth]), sellAmount, buyAmount, recipient)
.awaitTransactionSuccessAsync({ from: taker });
// Test pools always ask for full sell amount and pay entire balance.
expect(await sellToken.balanceOf(taker).callAsync()).to.bignumber.eq(0);
expect(await env.web3Wrapper.getBalanceInWeiAsync(recipient)).to.bignumber.eq(buyAmount);
expect(await sellToken.balanceOf(pool.address).callAsync()).to.bignumber.eq(sellAmount);
});
it('null recipient is sender', async () => {
const [sellToken] = tokens;
const pool = await createPoolAsync(sellToken, weth, ZERO_AMOUNT, buyAmount);
await mintToAsync(sellToken, taker, sellAmount);
const takerBalanceBefore = await env.web3Wrapper.getBalanceInWeiAsync(taker);
await feature
.sellTokenForEthToUniswapV3(encodePath([sellToken, weth]), sellAmount, buyAmount, NULL_ADDRESS)
.awaitTransactionSuccessAsync({ from: taker, gasPrice: ZERO_AMOUNT });
// Test pools always ask for full sell amount and pay entire balance.
expect((await env.web3Wrapper.getBalanceInWeiAsync(taker)).minus(takerBalanceBefore)).to.bignumber.eq(
buyAmount,
);
expect(await sellToken.balanceOf(pool.address).callAsync()).to.bignumber.eq(sellAmount);
});
it('fails if receipient cannot receive ETH', async () => {
const [sellToken] = tokens;
await mintToAsync(sellToken, taker, sellAmount);
const tx = feature
.sellTokenForEthToUniswapV3(
encodePath([sellToken, weth]),
sellAmount,
buyAmount,
noEthRecipient.address,
)
.awaitTransactionSuccessAsync({ from: taker });
return expect(tx).to.be.rejectedWith('revert');
});
});
});

View File

@ -42,19 +42,19 @@ blockchainTests.resets('FixinTokenSpender', env => {
); );
}); });
describe('transferERC20Tokens()', () => { describe('transferERC20TokensFrom()', () => {
const EMPTY_RETURN_AMOUNT = 1337; const EMPTY_RETURN_AMOUNT = 1337;
const FALSE_RETURN_AMOUNT = 1338; const FALSE_RETURN_AMOUNT = 1338;
const REVERT_RETURN_AMOUNT = 1339; const REVERT_RETURN_AMOUNT = 1339;
const EXTRA_RETURN_TRUE_AMOUNT = 1341; const EXTRA_RETURN_TRUE_AMOUNT = 1341;
const EXTRA_RETURN_FALSE_AMOUNT = 1342; const EXTRA_RETURN_FALSE_AMOUNT = 1342;
it('transferERC20Tokens() successfully calls compliant ERC20 token', async () => { it('transferERC20TokensFrom() successfully calls compliant ERC20 token', async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(123456); const tokenAmount = new BigNumber(123456);
const receipt = await tokenSpender const receipt = await tokenSpender
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
verifyEventsFromLogs( verifyEventsFromLogs(
receipt.logs, receipt.logs,
@ -70,12 +70,12 @@ blockchainTests.resets('FixinTokenSpender', env => {
); );
}); });
it('transferERC20Tokens() successfully calls non-compliant ERC20 token', async () => { it('transferERC20TokensFrom() successfully calls non-compliant ERC20 token', async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(EMPTY_RETURN_AMOUNT); const tokenAmount = new BigNumber(EMPTY_RETURN_AMOUNT);
const receipt = await tokenSpender const receipt = await tokenSpender
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
verifyEventsFromLogs( verifyEventsFromLogs(
receipt.logs, receipt.logs,
@ -91,34 +91,34 @@ blockchainTests.resets('FixinTokenSpender', env => {
); );
}); });
it('transferERC20Tokens() reverts if ERC20 token reverts', async () => { it('transferERC20TokensFrom() reverts if ERC20 token reverts', async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(REVERT_RETURN_AMOUNT); const tokenAmount = new BigNumber(REVERT_RETURN_AMOUNT);
const tx = tokenSpender const tx = tokenSpender
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
const expectedError = new StringRevertError('TestTokenSpenderERC20Token/Revert'); const expectedError = new StringRevertError('TestTokenSpenderERC20Token/Revert');
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
it('transferERC20Tokens() reverts if ERC20 token returns false', async () => { it('transferERC20TokensFrom() reverts if ERC20 token returns false', async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(FALSE_RETURN_AMOUNT); const tokenAmount = new BigNumber(FALSE_RETURN_AMOUNT);
const tx = tokenSpender const tx = tokenSpender
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0))); return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
}); });
it('transferERC20Tokens() allows extra data after true', async () => { it('transferERC20TokensFrom() allows extra data after true', async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(EXTRA_RETURN_TRUE_AMOUNT); const tokenAmount = new BigNumber(EXTRA_RETURN_TRUE_AMOUNT);
const receipt = await tokenSpender const receipt = await tokenSpender
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
verifyEventsFromLogs( verifyEventsFromLogs(
receipt.logs, receipt.logs,
@ -134,24 +134,24 @@ blockchainTests.resets('FixinTokenSpender', env => {
); );
}); });
it("transferERC20Tokens() reverts when there's extra data after false", async () => { it("transferERC20TokensFrom() reverts when there's extra data after false", async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(EXTRA_RETURN_FALSE_AMOUNT); const tokenAmount = new BigNumber(EXTRA_RETURN_FALSE_AMOUNT);
const tx = tokenSpender const tx = tokenSpender
.transferERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(EXTRA_RETURN_FALSE_AMOUNT, 64))); return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(EXTRA_RETURN_FALSE_AMOUNT, 64)));
}); });
it('transferERC20Tokens() cannot call self', async () => { it('transferERC20TokensFrom() cannot call self', async () => {
const tokenFrom = randomAddress(); const tokenFrom = randomAddress();
const tokenTo = randomAddress(); const tokenTo = randomAddress();
const tokenAmount = new BigNumber(123456); const tokenAmount = new BigNumber(123456);
const tx = tokenSpender const tx = tokenSpender
.transferERC20Tokens(tokenSpender.address, tokenFrom, tokenTo, tokenAmount) .transferERC20TokensFrom(tokenSpender.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync(); .awaitTransactionSuccessAsync();
return expect(tx).to.revertWith('FixinTokenSpender/CANNOT_INVOKE_SELF'); return expect(tx).to.revertWith('FixinTokenSpender/CANNOT_INVOKE_SELF');
}); });

View File

@ -5,11 +5,25 @@ import {
getRandomInteger, getRandomInteger,
randomAddress, randomAddress,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { LimitOrder, LimitOrderFields, OrderBase, OrderInfo, RfqOrder, RfqOrderFields } from '@0x/protocol-utils'; import {
LimitOrder,
LimitOrderFields,
OrderBase,
OrderInfo,
OtcOrder,
RfqOrder,
RfqOrderFields,
SignatureType,
} from '@0x/protocol-utils';
import { BigNumber, hexUtils } from '@0x/utils'; import { BigNumber, hexUtils } from '@0x/utils';
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import { IZeroExContract, IZeroExLimitOrderFilledEventArgs, IZeroExRfqOrderFilledEventArgs } from '../../src/wrappers'; import {
IZeroExContract,
IZeroExLimitOrderFilledEventArgs,
IZeroExOtcOrderFilledEventArgs,
IZeroExRfqOrderFilledEventArgs,
} from '../../src/wrappers';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { fullMigrateAsync } from '../utils/migration'; import { fullMigrateAsync } from '../utils/migration';
import { TestMintableERC20TokenContract } from '../wrappers'; import { TestMintableERC20TokenContract } from '../wrappers';
@ -20,6 +34,7 @@ interface RfqOrderFilledAmounts {
makerTokenFilledAmount: BigNumber; makerTokenFilledAmount: BigNumber;
takerTokenFilledAmount: BigNumber; takerTokenFilledAmount: BigNumber;
} }
interface OtcOrderFilledAmounts extends RfqOrderFilledAmounts {}
interface LimitOrderFilledAmounts { interface LimitOrderFilledAmounts {
makerTokenFilledAmount: BigNumber; makerTokenFilledAmount: BigNumber;
@ -27,6 +42,12 @@ interface LimitOrderFilledAmounts {
takerTokenFeeFilledAmount: BigNumber; takerTokenFeeFilledAmount: BigNumber;
} }
export enum OtcOrderWethOptions {
LeaveAsWeth,
WrapEth,
UnwrapWeth,
}
export class NativeOrdersTestEnvironment { export class NativeOrdersTestEnvironment {
public static async createAsync( public static async createAsync(
env: BlockchainTestsEnvironment, env: BlockchainTestsEnvironment,
@ -71,7 +92,7 @@ export class NativeOrdersTestEnvironment {
) {} ) {}
public async prepareBalancesForOrdersAsync( public async prepareBalancesForOrdersAsync(
orders: LimitOrder[] | RfqOrder[], orders: LimitOrder[] | RfqOrder[] | OtcOrder[],
taker: string = this.taker, taker: string = this.taker,
): Promise<void> { ): Promise<void> {
await this.makerToken await this.makerToken
@ -128,6 +149,51 @@ export class NativeOrdersTestEnvironment {
.awaitTransactionSuccessAsync({ from: taker }); .awaitTransactionSuccessAsync({ from: taker });
} }
public async fillOtcOrderAsync(
order: OtcOrder,
fillAmount: BigNumber | number = order.takerAmount,
taker: string = this.taker,
unwrapWeth: boolean = false,
): Promise<TransactionReceiptWithDecodedLogs> {
await this.prepareBalancesForOrdersAsync([order], taker);
return this.zeroEx
.fillOtcOrder(
order,
await order.getSignatureWithProviderAsync(this._env.provider),
new BigNumber(fillAmount),
unwrapWeth,
)
.awaitTransactionSuccessAsync({ from: taker });
}
public async fillTakerSignedOtcOrderAsync(
order: OtcOrder,
origin: string = order.txOrigin,
taker: string = order.taker,
unwrapWeth: boolean = false,
): Promise<TransactionReceiptWithDecodedLogs> {
await this.prepareBalancesForOrdersAsync([order], taker);
return this.zeroEx
.fillTakerSignedOtcOrder(
order,
await order.getSignatureWithProviderAsync(this._env.provider),
await order.getSignatureWithProviderAsync(this._env.provider, SignatureType.EthSign, taker),
unwrapWeth,
)
.awaitTransactionSuccessAsync({ from: origin });
}
public async fillOtcOrderWithEthAsync(
order: OtcOrder,
fillAmount: BigNumber | number = order.takerAmount,
taker: string = this.taker,
): Promise<TransactionReceiptWithDecodedLogs> {
await this.prepareBalancesForOrdersAsync([order], taker);
return this.zeroEx
.fillOtcOrderWithEth(order, await order.getSignatureWithProviderAsync(this._env.provider))
.awaitTransactionSuccessAsync({ from: taker, value: fillAmount });
}
public createLimitOrderFilledEventArgs( public createLimitOrderFilledEventArgs(
order: LimitOrder, order: LimitOrder,
takerTokenFillAmount: BigNumber = order.takerAmount, takerTokenFillAmount: BigNumber = order.takerAmount,
@ -175,6 +241,25 @@ export class NativeOrdersTestEnvironment {
pool: order.pool, pool: order.pool,
}; };
} }
public createOtcOrderFilledEventArgs(
order: OtcOrder,
takerTokenFillAmount: BigNumber = order.takerAmount,
): IZeroExOtcOrderFilledEventArgs {
const { makerTokenFilledAmount, takerTokenFilledAmount } = computeOtcOrderFilledAmounts(
order,
takerTokenFillAmount,
);
return {
takerTokenFilledAmount,
makerTokenFilledAmount,
orderHash: order.getHash(),
maker: order.maker,
taker: order.taker !== NULL_ADDRESS ? order.taker : this.taker,
makerToken: order.makerToken,
takerToken: order.takerToken,
};
}
} }
/** /**
@ -216,6 +301,27 @@ export function getRandomRfqOrder(fields: Partial<RfqOrderFields> = {}): RfqOrde
}); });
} }
/**
* Generate a random OTC Order
*/
export function getRandomOtcOrder(fields: Partial<OtcOrder> = {}): OtcOrder {
return new OtcOrder({
makerToken: randomAddress(),
takerToken: randomAddress(),
makerAmount: getRandomInteger('1e18', '100e18'),
takerAmount: getRandomInteger('1e6', '100e6'),
maker: randomAddress(),
taker: randomAddress(),
txOrigin: randomAddress(),
expiryAndNonce: OtcOrder.encodeExpiryAndNonce(
fields.expiry ?? new BigNumber(Math.floor(Date.now() / 1000 + 60)), // expiry
fields.nonceBucket ?? getRandomInteger(0, OtcOrder.MAX_NONCE_BUCKET), // nonceBucket
fields.nonce ?? getRandomInteger(0, OtcOrder.MAX_NONCE_VALUE), // nonce
),
...fields,
});
}
/** /**
* Asserts the fields of an OrderInfo object. * Asserts the fields of an OrderInfo object.
*/ */
@ -286,6 +392,24 @@ export function computeRfqOrderFilledAmounts(
}; };
} }
/**
* Computes the maker and taker amounts filled for the given OTC order.
*/
export function computeOtcOrderFilledAmounts(
order: OtcOrder,
takerTokenFillAmount: BigNumber = order.takerAmount,
): OtcOrderFilledAmounts {
const fillAmount = BigNumber.min(order.takerAmount, takerTokenFillAmount, order.takerAmount);
const makerTokenFilledAmount = fillAmount
.times(order.makerAmount)
.div(order.takerAmount)
.integerValue(BigNumber.ROUND_DOWN);
return {
makerTokenFilledAmount,
takerTokenFilledAmount: fillAmount,
};
}
/** /**
* Computes the remaining fillable amount in maker token for * Computes the remaining fillable amount in maker token for
* the given order. * the given order.

View File

@ -34,6 +34,7 @@ export * from '../test/generated-wrappers/i_mooniswap_pool';
export * from '../test/generated-wrappers/i_multiplex_feature'; export * from '../test/generated-wrappers/i_multiplex_feature';
export * from '../test/generated-wrappers/i_native_orders_events'; export * from '../test/generated-wrappers/i_native_orders_events';
export * from '../test/generated-wrappers/i_native_orders_feature'; export * from '../test/generated-wrappers/i_native_orders_feature';
export * from '../test/generated-wrappers/i_otc_orders_feature';
export * from '../test/generated-wrappers/i_ownable_feature'; export * from '../test/generated-wrappers/i_ownable_feature';
export * from '../test/generated-wrappers/i_pancake_swap_feature'; export * from '../test/generated-wrappers/i_pancake_swap_feature';
export * from '../test/generated-wrappers/i_simple_function_registry_feature'; export * from '../test/generated-wrappers/i_simple_function_registry_feature';
@ -43,6 +44,8 @@ export * from '../test/generated-wrappers/i_token_spender_feature';
export * from '../test/generated-wrappers/i_transform_erc20_feature'; export * from '../test/generated-wrappers/i_transform_erc20_feature';
export * from '../test/generated-wrappers/i_uniswap_feature'; export * from '../test/generated-wrappers/i_uniswap_feature';
export * from '../test/generated-wrappers/i_uniswap_v2_pair'; export * from '../test/generated-wrappers/i_uniswap_v2_pair';
export * from '../test/generated-wrappers/i_uniswap_v3_feature';
export * from '../test/generated-wrappers/i_uniswap_v3_pool';
export * from '../test/generated-wrappers/i_zero_ex'; export * from '../test/generated-wrappers/i_zero_ex';
export * from '../test/generated-wrappers/initial_migration'; export * from '../test/generated-wrappers/initial_migration';
export * from '../test/generated-wrappers/lib_bootstrap'; export * from '../test/generated-wrappers/lib_bootstrap';
@ -56,6 +59,7 @@ export * from '../test/generated-wrappers/lib_migrate';
export * from '../test/generated-wrappers/lib_native_order'; export * from '../test/generated-wrappers/lib_native_order';
export * from '../test/generated-wrappers/lib_native_orders_rich_errors'; export * from '../test/generated-wrappers/lib_native_orders_rich_errors';
export * from '../test/generated-wrappers/lib_native_orders_storage'; export * from '../test/generated-wrappers/lib_native_orders_storage';
export * from '../test/generated-wrappers/lib_otc_orders_storage';
export * from '../test/generated-wrappers/lib_ownable_rich_errors'; export * from '../test/generated-wrappers/lib_ownable_rich_errors';
export * from '../test/generated-wrappers/lib_ownable_storage'; export * from '../test/generated-wrappers/lib_ownable_storage';
export * from '../test/generated-wrappers/lib_proxy_rich_errors'; export * from '../test/generated-wrappers/lib_proxy_rich_errors';
@ -100,6 +104,7 @@ export * from '../test/generated-wrappers/native_orders_feature';
export * from '../test/generated-wrappers/native_orders_info'; export * from '../test/generated-wrappers/native_orders_info';
export * from '../test/generated-wrappers/native_orders_protocol_fees'; export * from '../test/generated-wrappers/native_orders_protocol_fees';
export * from '../test/generated-wrappers/native_orders_settlement'; export * from '../test/generated-wrappers/native_orders_settlement';
export * from '../test/generated-wrappers/otc_orders_feature';
export * from '../test/generated-wrappers/ownable_feature'; export * from '../test/generated-wrappers/ownable_feature';
export * from '../test/generated-wrappers/pancake_swap_feature'; export * from '../test/generated-wrappers/pancake_swap_feature';
export * from '../test/generated-wrappers/pay_taker_transformer'; export * from '../test/generated-wrappers/pay_taker_transformer';
@ -128,6 +133,7 @@ export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
export * from '../test/generated-wrappers/test_mintable_erc20_token'; export * from '../test/generated-wrappers/test_mintable_erc20_token';
export * from '../test/generated-wrappers/test_mooniswap'; export * from '../test/generated-wrappers/test_mooniswap';
export * from '../test/generated-wrappers/test_native_orders_feature'; export * from '../test/generated-wrappers/test_native_orders_feature';
export * from '../test/generated-wrappers/test_no_eth_recipient';
export * from '../test/generated-wrappers/test_order_signer_registry_with_contract_wallet'; export * from '../test/generated-wrappers/test_order_signer_registry_with_contract_wallet';
export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_suicidal'; export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_suicidal';
export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_transformer'; export * from '../test/generated-wrappers/test_permissionless_transformer_deployer_transformer';
@ -140,6 +146,9 @@ export * from '../test/generated-wrappers/test_transform_erc20';
export * from '../test/generated-wrappers/test_transformer_base'; export * from '../test/generated-wrappers/test_transformer_base';
export * from '../test/generated-wrappers/test_transformer_deployer_transformer'; export * from '../test/generated-wrappers/test_transformer_deployer_transformer';
export * from '../test/generated-wrappers/test_transformer_host'; export * from '../test/generated-wrappers/test_transformer_host';
export * from '../test/generated-wrappers/test_uniswap_v3_factory';
export * from '../test/generated-wrappers/test_uniswap_v3_feature';
export * from '../test/generated-wrappers/test_uniswap_v3_pool';
export * from '../test/generated-wrappers/test_weth'; export * from '../test/generated-wrappers/test_weth';
export * from '../test/generated-wrappers/test_weth_transformer_host'; export * from '../test/generated-wrappers/test_weth_transformer_host';
export * from '../test/generated-wrappers/test_zero_ex_feature'; export * from '../test/generated-wrappers/test_zero_ex_feature';
@ -147,6 +156,7 @@ export * from '../test/generated-wrappers/transform_erc20_feature';
export * from '../test/generated-wrappers/transformer'; export * from '../test/generated-wrappers/transformer';
export * from '../test/generated-wrappers/transformer_deployer'; export * from '../test/generated-wrappers/transformer_deployer';
export * from '../test/generated-wrappers/uniswap_feature'; export * from '../test/generated-wrappers/uniswap_feature';
export * from '../test/generated-wrappers/uniswap_v3_feature';
export * from '../test/generated-wrappers/weth_transformer'; export * from '../test/generated-wrappers/weth_transformer';
export * from '../test/generated-wrappers/zero_ex'; export * from '../test/generated-wrappers/zero_ex';
export * from '../test/generated-wrappers/zero_ex_optimized'; export * from '../test/generated-wrappers/zero_ex_optimized';

View File

@ -17,6 +17,7 @@
"generated-artifacts/ILiquidityProviderFeature.json", "generated-artifacts/ILiquidityProviderFeature.json",
"generated-artifacts/IMultiplexFeature.json", "generated-artifacts/IMultiplexFeature.json",
"generated-artifacts/INativeOrdersFeature.json", "generated-artifacts/INativeOrdersFeature.json",
"generated-artifacts/IOtcOrdersFeature.json",
"generated-artifacts/IOwnableFeature.json", "generated-artifacts/IOwnableFeature.json",
"generated-artifacts/ISimpleFunctionRegistryFeature.json", "generated-artifacts/ISimpleFunctionRegistryFeature.json",
"generated-artifacts/ITransformERC20Feature.json", "generated-artifacts/ITransformERC20Feature.json",
@ -27,6 +28,7 @@
"generated-artifacts/MetaTransactionsFeature.json", "generated-artifacts/MetaTransactionsFeature.json",
"generated-artifacts/MultiplexFeature.json", "generated-artifacts/MultiplexFeature.json",
"generated-artifacts/NativeOrdersFeature.json", "generated-artifacts/NativeOrdersFeature.json",
"generated-artifacts/OtcOrdersFeature.json",
"generated-artifacts/OwnableFeature.json", "generated-artifacts/OwnableFeature.json",
"generated-artifacts/PayTakerTransformer.json", "generated-artifacts/PayTakerTransformer.json",
"generated-artifacts/PositiveSlippageFeeTransformer.json", "generated-artifacts/PositiveSlippageFeeTransformer.json",
@ -65,6 +67,7 @@
"test/generated-artifacts/IMultiplexFeature.json", "test/generated-artifacts/IMultiplexFeature.json",
"test/generated-artifacts/INativeOrdersEvents.json", "test/generated-artifacts/INativeOrdersEvents.json",
"test/generated-artifacts/INativeOrdersFeature.json", "test/generated-artifacts/INativeOrdersFeature.json",
"test/generated-artifacts/IOtcOrdersFeature.json",
"test/generated-artifacts/IOwnableFeature.json", "test/generated-artifacts/IOwnableFeature.json",
"test/generated-artifacts/IPancakeSwapFeature.json", "test/generated-artifacts/IPancakeSwapFeature.json",
"test/generated-artifacts/ISimpleFunctionRegistryFeature.json", "test/generated-artifacts/ISimpleFunctionRegistryFeature.json",
@ -74,6 +77,8 @@
"test/generated-artifacts/ITransformERC20Feature.json", "test/generated-artifacts/ITransformERC20Feature.json",
"test/generated-artifacts/IUniswapFeature.json", "test/generated-artifacts/IUniswapFeature.json",
"test/generated-artifacts/IUniswapV2Pair.json", "test/generated-artifacts/IUniswapV2Pair.json",
"test/generated-artifacts/IUniswapV3Feature.json",
"test/generated-artifacts/IUniswapV3Pool.json",
"test/generated-artifacts/IZeroEx.json", "test/generated-artifacts/IZeroEx.json",
"test/generated-artifacts/InitialMigration.json", "test/generated-artifacts/InitialMigration.json",
"test/generated-artifacts/LibBootstrap.json", "test/generated-artifacts/LibBootstrap.json",
@ -87,6 +92,7 @@
"test/generated-artifacts/LibNativeOrder.json", "test/generated-artifacts/LibNativeOrder.json",
"test/generated-artifacts/LibNativeOrdersRichErrors.json", "test/generated-artifacts/LibNativeOrdersRichErrors.json",
"test/generated-artifacts/LibNativeOrdersStorage.json", "test/generated-artifacts/LibNativeOrdersStorage.json",
"test/generated-artifacts/LibOtcOrdersStorage.json",
"test/generated-artifacts/LibOwnableRichErrors.json", "test/generated-artifacts/LibOwnableRichErrors.json",
"test/generated-artifacts/LibOwnableStorage.json", "test/generated-artifacts/LibOwnableStorage.json",
"test/generated-artifacts/LibProxyRichErrors.json", "test/generated-artifacts/LibProxyRichErrors.json",
@ -131,6 +137,7 @@
"test/generated-artifacts/NativeOrdersInfo.json", "test/generated-artifacts/NativeOrdersInfo.json",
"test/generated-artifacts/NativeOrdersProtocolFees.json", "test/generated-artifacts/NativeOrdersProtocolFees.json",
"test/generated-artifacts/NativeOrdersSettlement.json", "test/generated-artifacts/NativeOrdersSettlement.json",
"test/generated-artifacts/OtcOrdersFeature.json",
"test/generated-artifacts/OwnableFeature.json", "test/generated-artifacts/OwnableFeature.json",
"test/generated-artifacts/PancakeSwapFeature.json", "test/generated-artifacts/PancakeSwapFeature.json",
"test/generated-artifacts/PayTakerTransformer.json", "test/generated-artifacts/PayTakerTransformer.json",
@ -159,6 +166,7 @@
"test/generated-artifacts/TestMintableERC20Token.json", "test/generated-artifacts/TestMintableERC20Token.json",
"test/generated-artifacts/TestMooniswap.json", "test/generated-artifacts/TestMooniswap.json",
"test/generated-artifacts/TestNativeOrdersFeature.json", "test/generated-artifacts/TestNativeOrdersFeature.json",
"test/generated-artifacts/TestNoEthRecipient.json",
"test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json", "test/generated-artifacts/TestOrderSignerRegistryWithContractWallet.json",
"test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json", "test/generated-artifacts/TestPermissionlessTransformerDeployerSuicidal.json",
"test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json", "test/generated-artifacts/TestPermissionlessTransformerDeployerTransformer.json",
@ -171,6 +179,9 @@
"test/generated-artifacts/TestTransformerBase.json", "test/generated-artifacts/TestTransformerBase.json",
"test/generated-artifacts/TestTransformerDeployerTransformer.json", "test/generated-artifacts/TestTransformerDeployerTransformer.json",
"test/generated-artifacts/TestTransformerHost.json", "test/generated-artifacts/TestTransformerHost.json",
"test/generated-artifacts/TestUniswapV3Factory.json",
"test/generated-artifacts/TestUniswapV3Feature.json",
"test/generated-artifacts/TestUniswapV3Pool.json",
"test/generated-artifacts/TestWeth.json", "test/generated-artifacts/TestWeth.json",
"test/generated-artifacts/TestWethTransformerHost.json", "test/generated-artifacts/TestWethTransformerHost.json",
"test/generated-artifacts/TestZeroExFeature.json", "test/generated-artifacts/TestZeroExFeature.json",
@ -178,6 +189,7 @@
"test/generated-artifacts/Transformer.json", "test/generated-artifacts/Transformer.json",
"test/generated-artifacts/TransformerDeployer.json", "test/generated-artifacts/TransformerDeployer.json",
"test/generated-artifacts/UniswapFeature.json", "test/generated-artifacts/UniswapFeature.json",
"test/generated-artifacts/UniswapV3Feature.json",
"test/generated-artifacts/WethTransformer.json", "test/generated-artifacts/WethTransformer.json",
"test/generated-artifacts/ZeroEx.json", "test/generated-artifacts/ZeroEx.json",
"test/generated-artifacts/ZeroExOptimized.json" "test/generated-artifacts/ZeroExOptimized.json"

View File

@ -12,8 +12,8 @@
"deps_versions:ci": "node ./node_modules/@0x/monorepo-scripts/lib/deps_versions.js", "deps_versions:ci": "node ./node_modules/@0x/monorepo-scripts/lib/deps_versions.js",
"fix": "wsrun --fast-exit --parallel --exclude-missing -p $PKG -c fix", "fix": "wsrun --fast-exit --parallel --exclude-missing -p $PKG -c fix",
"ganache": "ganache-cli -p 8545 --gasLimit 10000000 --networkId 50 -m \"${npm_package_config_mnemonic}\"", "ganache": "ganache-cli -p 8545 --gasLimit 10000000 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
"prettier": "prettier --write '**/*.{ts,tsx,json,md}' --config .prettierrc", "prettier": "prettier --write '**/*.{ts,tsx,json}' --config .prettierrc",
"prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc", "prettier:ci": "prettier --list-different '**/*.{ts,tsx,json}' --config .prettierrc",
"report_coverage": "lcov-result-merger './packages/*/coverage/lcov.info' | coveralls", "report_coverage": "lcov-result-merger './packages/*/coverage/lcov.info' | coveralls",
"test:installation": "node ./node_modules/@0x/monorepo-scripts/lib/test_installation.js", "test:installation": "node ./node_modules/@0x/monorepo-scripts/lib/test_installation.js",
"test:installation:local": "IS_LOCAL_PUBLISH=true node ./node_modules/@0x/monorepo-scripts/lib/test_installation.js", "test:installation:local": "IS_LOCAL_PUBLISH=true node ./node_modules/@0x/monorepo-scripts/lib/test_installation.js",
@ -69,7 +69,7 @@
"lcov-result-merger": "^3.0.0", "lcov-result-merger": "^3.0.0",
"lerna": "^3.0.0-beta.25", "lerna": "^3.0.0-beta.25",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
"prettier": "~1.16.3", "prettier": "1.19.1",
"source-map-support": "^0.5.6", "source-map-support": "^0.5.6",
"typescript": "4.2.2", "typescript": "4.2.2",
"wsrun": "^5.2.4" "wsrun": "^5.2.4"

View File

@ -46,6 +46,10 @@
{ {
"note": "Add support for additional sources and intermediate tokens on Ropsten", "note": "Add support for additional sources and intermediate tokens on Ropsten",
"pr": 231 "pr": 231
},
{
"note": "Add UniswapV3 VIP support",
"pr": 237
} }
], ],
"timestamp": 1620810800 "timestamp": 1620810800

View File

@ -17,7 +17,7 @@
"compile": "sol-compiler", "compile": "sol-compiler",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", "lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"lint-contracts": "#solhint -c .solhint.json contracts/**/**/**/**/*.sol", "lint-contracts": "#solhint -c .solhint.json contracts/**/**/**/**/*.sol",
"prettier": "prettier --write '**/*.{ts,tsx,json,md}' --config ../../.prettierrc --ignore-path ../../.prettierignore", "prettier": "prettier --write '**/*.{ts,tsx,json}' --config ../../.prettierrc --ignore-path ../../.prettierignore",
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts", "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-wrappers/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"test": "yarn run_mocha", "test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test", "rebuild_and_test": "run-s clean build test",

View File

@ -40,6 +40,7 @@ import { poolEncoder } from '../utils/market_operation_utils/orders';
import { import {
CurveFillData, CurveFillData,
ERC20BridgeSource, ERC20BridgeSource,
FinalUniswapV3FillData,
LiquidityProviderFillData, LiquidityProviderFillData,
MooniswapFillData, MooniswapFillData,
OptimizedMarketBridgeOrder, OptimizedMarketBridgeOrder,
@ -186,6 +187,34 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}; };
} }
if (
this.chainId === ChainId.Mainnet &&
isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.UniswapV3])
) {
const fillData = (slippedOrders[0] as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
let _calldataHexString;
if (isFromETH) {
_calldataHexString = this._exchangeProxy
.sellEthForTokenToUniswapV3(fillData.uniswapPath, minBuyAmount, NULL_ADDRESS)
.getABIEncodedTransactionData();
} else if (isToETH) {
_calldataHexString = this._exchangeProxy
.sellTokenForEthToUniswapV3(fillData.uniswapPath, sellAmount, minBuyAmount, NULL_ADDRESS)
.getABIEncodedTransactionData();
} else {
_calldataHexString = this._exchangeProxy
.sellTokenForTokenToUniswapV3(fillData.uniswapPath, sellAmount, minBuyAmount, NULL_ADDRESS)
.getABIEncodedTransactionData();
}
return {
calldataHexString: _calldataHexString,
ethAmount: isFromETH ? sellAmount : ZERO_AMOUNT,
toAddress: this._exchangeProxy.address,
allowanceTarget: this._exchangeProxy.address,
gasOverhead: ZERO_AMOUNT,
};
}
if ( if (
this.chainId === ChainId.BSC && this.chainId === ChainId.BSC &&
isDirectSwapCompatible(quote, optsWithDefaults, [ isDirectSwapCompatible(quote, optsWithDefaults, [
@ -520,6 +549,14 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}), }),
}); });
break switch_statement; break switch_statement;
case ERC20BridgeSource.UniswapV3:
const fillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData;
wrappedBatchCalls.push({
selector: this._exchangeProxy.getSelector('sellTokenForTokenToUniswapV3'),
sellAmount: order.takerAmount,
data: fillData.uniswapPath,
});
break switch_statement;
default: default:
const fqtData = encodeFillQuoteTransformerData({ const fqtData = encodeFillQuoteTransformerData({
side: FillQuoteTransformerSide.Sell, side: FillQuoteTransformerSide.Sell,

View File

@ -5,7 +5,10 @@ export const multiplexTransformERC20Encoder = AbiEncoder.create([
{ {
name: 'transformations', name: 'transformations',
type: 'tuple[]', type: 'tuple[]',
components: [{ name: 'deploymentNonce', type: 'uint32' }, { name: 'data', type: 'bytes' }], components: [
{ name: 'deploymentNonce', type: 'uint32' },
{ name: 'data', type: 'bytes' },
],
}, },
{ name: 'ethValue', type: 'uint256' }, { name: 'ethValue', type: 'uint256' },
]); ]);

View File

@ -19,6 +19,7 @@ const MULTIPLEX_BATCH_FILL_SOURCES = [
ERC20BridgeSource.SushiSwap, ERC20BridgeSource.SushiSwap,
ERC20BridgeSource.LiquidityProvider, ERC20BridgeSource.LiquidityProvider,
ERC20BridgeSource.Native, ERC20BridgeSource.Native,
ERC20BridgeSource.UniswapV3,
]; ];
/** /**
@ -39,7 +40,7 @@ export function isMultiplexBatchFillCompatible(quote: SwapQuote, opts: ExchangeP
return false; return false;
} }
// Use Multiplex if the non-fallback sources are a subset of // Use Multiplex if the non-fallback sources are a subset of
// {Uniswap, Sushiswap, RFQ, PLP} // {UniswapV2, Sushiswap, RFQ, PLP, UniswapV3}
const nonFallbackSources = Object.keys(quote.sourceBreakdown); const nonFallbackSources = Object.keys(quote.sourceBreakdown);
return nonFallbackSources.every(source => MULTIPLEX_BATCH_FILL_SOURCES.includes(source as ERC20BridgeSource)); return nonFallbackSources.every(source => MULTIPLEX_BATCH_FILL_SOURCES.includes(source as ERC20BridgeSource));
} }

View File

@ -1359,10 +1359,10 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = {
return gas; return gas;
}, },
[ERC20BridgeSource.UniswapV3]: (fillData?: FillData) => { [ERC20BridgeSource.UniswapV3]: (fillData?: FillData) => {
let gas = 160e3; let gas = 100e3;
const path = (fillData as UniswapV3FillData).tokenAddressPath; const path = (fillData as UniswapV3FillData).tokenAddressPath;
if (path.length > 2) { if (path.length > 2) {
gas += (path.length - 2) * 117e3; // +117k for each hop. gas += (path.length - 2) * 32e3; // +32k for each hop.
} }
return gas; return gas;
}, },

View File

@ -15,6 +15,7 @@ import {
DODOFillData, DODOFillData,
ERC20BridgeSource, ERC20BridgeSource,
FillData, FillData,
FinalUniswapV3FillData,
GenericRouterFillData, GenericRouterFillData,
KyberDmmFillData, KyberDmmFillData,
KyberFillData, KyberFillData,
@ -45,11 +46,6 @@ export interface CreateOrderFromPathOpts {
bridgeSlippage: number; bridgeSlippage: number;
} }
interface FinalUniswapV3FillData extends Omit<UniswapV3FillData, 'uniswapPaths'> {
// The uniswap-encoded path that can fll the maximum input amount.
uniswapPath: string;
}
export function createOrdersFromTwoHopSample( export function createOrdersFromTwoHopSample(
sample: DexSample<MultiHopFillData>, sample: DexSample<MultiHopFillData>,
opts: CreateOrderFromPathOpts, opts: CreateOrderFromPathOpts,
@ -364,7 +360,10 @@ const makerPsmEncoder = AbiEncoder.create([
{ name: 'psmAddress', type: 'address' }, { name: 'psmAddress', type: 'address' },
{ name: 'gemTokenAddress', type: 'address' }, { name: 'gemTokenAddress', type: 'address' },
]); ]);
const balancerV2Encoder = AbiEncoder.create([{ name: 'vault', type: 'address' }, { name: 'poolId', type: 'bytes32' }]); const balancerV2Encoder = AbiEncoder.create([
{ name: 'vault', type: 'address' },
{ name: 'poolId', type: 'bytes32' },
]);
const routerAddressPathEncoder = AbiEncoder.create('(address,address[])'); const routerAddressPathEncoder = AbiEncoder.create('(address,address[])');
const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]); const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]);
@ -372,7 +371,7 @@ export const BRIDGE_ENCODERS: {
[key in Exclude< [key in Exclude<
ERC20BridgeSource, ERC20BridgeSource,
ERC20BridgeSource.Native | ERC20BridgeSource.MultiHop | ERC20BridgeSource.MultiBridge ERC20BridgeSource.Native | ERC20BridgeSource.MultiHop | ERC20BridgeSource.MultiBridge
>]: AbiEncoder.DataType >]: AbiEncoder.DataType;
} = { } = {
[ERC20BridgeSource.LiquidityProvider]: AbiEncoder.create([ [ERC20BridgeSource.LiquidityProvider]: AbiEncoder.create([
{ name: 'provider', type: 'address' }, { name: 'provider', type: 'address' },

View File

@ -1152,8 +1152,7 @@ export class SamplerOperations {
.exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]) .exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native])
.getAllowed(sources); .getAllowed(sources);
const allOps = _.flatten( const allOps = _.flatten(
_sources.map( _sources.map((source): SourceQuoteOperation | SourceQuoteOperation[] => {
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
if (isBadTokenForSource(makerToken, source) || isBadTokenForSource(takerToken, source)) { if (isBadTokenForSource(makerToken, source) || isBadTokenForSource(takerToken, source)) {
return []; return [];
} }
@ -1202,11 +1201,7 @@ export class SamplerOperations {
if (!isValidAddress(kyberDmmRouter)) { if (!isValidAddress(kyberDmmRouter)) {
return []; return [];
} }
return this.getKyberDmmSellQuotes( return this.getKyberDmmSellQuotes(kyberDmmRouter, [takerToken, makerToken], takerFillAmounts);
kyberDmmRouter,
[takerToken, makerToken],
takerFillAmounts,
);
case ERC20BridgeSource.Kyber: case ERC20BridgeSource.Kyber:
return getKyberOffsets().map(offset => return getKyberOffsets().map(offset =>
this.getKyberSellQuotes( this.getKyberSellQuotes(
@ -1397,8 +1392,7 @@ export class SamplerOperations {
default: default:
throw new Error(`Unsupported sell sample source: ${source}`); throw new Error(`Unsupported sell sample source: ${source}`);
} }
}, }),
),
); );
return allOps; return allOps;
} }
@ -1414,8 +1408,7 @@ export class SamplerOperations {
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph); const intermediateTokens = getIntermediateTokens(makerToken, takerToken, this.tokenAdjacencyGraph);
const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources); const _sources = BATCH_SOURCE_FILTERS.getAllowed(sources);
return _.flatten( return _.flatten(
_sources.map( _sources.map((source): SourceQuoteOperation | SourceQuoteOperation[] => {
(source): SourceQuoteOperation | SourceQuoteOperation[] => {
switch (source) { switch (source) {
case ERC20BridgeSource.Eth2Dai: case ERC20BridgeSource.Eth2Dai:
return isValidAddress(OASIS_ROUTER_BY_CHAIN_ID[this.chainId]) return isValidAddress(OASIS_ROUTER_BY_CHAIN_ID[this.chainId])
@ -1461,11 +1454,7 @@ export class SamplerOperations {
if (!isValidAddress(kyberDmmRouter)) { if (!isValidAddress(kyberDmmRouter)) {
return []; return [];
} }
return this.getKyberDmmBuyQuotes( return this.getKyberDmmBuyQuotes(kyberDmmRouter, [takerToken, makerToken], makerFillAmounts);
kyberDmmRouter,
[takerToken, makerToken],
makerFillAmounts,
);
case ERC20BridgeSource.Kyber: case ERC20BridgeSource.Kyber:
return getKyberOffsets().map(offset => return getKyberOffsets().map(offset =>
this.getKyberBuyQuotes( this.getKyberBuyQuotes(
@ -1650,8 +1639,7 @@ export class SamplerOperations {
default: default:
throw new Error(`Unsupported buy sample source: ${source}`); throw new Error(`Unsupported buy sample source: ${source}`);
} }
}, }),
),
); );
} }

View File

@ -232,6 +232,11 @@ export interface KyberDmmFillData extends UniswapV2FillData {
poolsPath: string[]; poolsPath: string[];
} }
export interface FinalUniswapV3FillData extends Omit<UniswapV3FillData, 'uniswapPaths'> {
// The uniswap-encoded path that can fll the maximum input amount.
uniswapPath: string;
}
/** /**
* Represents a node on a fill path. * Represents a node on a fill path.
*/ */

View File

@ -499,11 +499,7 @@ export class QuoteRequestor {
rfqMakerBlacklist.logTimeoutOrLackThereof(typedMakerUrl.url, latencyMs >= timeoutMs); rfqMakerBlacklist.logTimeoutOrLackThereof(typedMakerUrl.url, latencyMs >= timeoutMs);
this._warningLogger( this._warningLogger(
convertIfAxiosError(err), convertIfAxiosError(err),
`Failed to get RFQ-T ${quoteType} quote from market maker endpoint ${ `Failed to get RFQ-T ${quoteType} quote from market maker endpoint ${typedMakerUrl.url} for API key ${options.apiKey} for taker address ${options.takerAddress} and tx origin ${options.txOrigin}`,
typedMakerUrl.url
} for API key ${options.apiKey} for taker address ${options.takerAddress} and tx origin ${
options.txOrigin
}`,
); );
return; return;
} }
@ -620,7 +616,12 @@ export class QuoteRequestor {
this._warningLogger(result, 'Invalid RFQ indicative quote received, filtering out'); this._warningLogger(result, 'Invalid RFQ indicative quote received, filtering out');
return false; return false;
} }
if (!hasExpectedAddresses([[makerToken, order.makerToken], [takerToken, order.takerToken]])) { if (
!hasExpectedAddresses([
[makerToken, order.makerToken],
[takerToken, order.takerToken],
])
) {
this._warningLogger(order, 'Unexpected token or taker address in RFQ order, filtering out'); this._warningLogger(order, 'Unexpected token or taker address in RFQ order, filtering out');
return false; return false;
} }

View File

@ -194,7 +194,10 @@ describe('ExchangeProxySwapQuoteConsumer', () => {
{ {
type: 'tuple[]', type: 'tuple[]',
name: 'transformations', name: 'transformations',
components: [{ type: 'uint32', name: 'deploymentNonce' }, { type: 'bytes', name: 'data' }], components: [
{ type: 'uint32', name: 'deploymentNonce' },
{ type: 'bytes', name: 'data' },
],
}, },
]); ]);

View File

@ -254,7 +254,11 @@ describe('MarketOperationUtils tests', () => {
_wethAddress: string, _wethAddress: string,
) => { ) => {
return BATCH_SOURCE_FILTERS.getAllowed(sources).map(s => return BATCH_SOURCE_FILTERS.getAllowed(sources).map(s =>
createSamplesFromRates(s, fillAmounts, rates[s].map(r => new BigNumber(1).div(r))), createSamplesFromRates(
s,
fillAmounts,
rates[s].map(r => new BigNumber(1).div(r)),
),
); );
}; };
} }

View File

@ -36,7 +36,11 @@ describe('Pools Caches for Balancer-based sampling', () => {
describe('BalancerPoolsCache', () => { describe('BalancerPoolsCache', () => {
const cache = new BalancerPoolsCache(); const cache = new BalancerPoolsCache();
it('fetches pools', async () => { it('fetches pools', async () => {
const pairs = [[usdcAddress, daiAddress], [usdcAddress, wethAddress], [daiAddress, wethAddress]]; const pairs = [
[usdcAddress, daiAddress],
[usdcAddress, wethAddress],
[daiAddress, wethAddress],
];
await Promise.all( await Promise.all(
// tslint:disable-next-line:promise-function-async // tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)), pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
@ -47,7 +51,10 @@ describe('Pools Caches for Balancer-based sampling', () => {
describe('BalancerV2PoolsCache', () => { describe('BalancerV2PoolsCache', () => {
const cache = new BalancerV2PoolsCache(); const cache = new BalancerV2PoolsCache();
it('fetches pools', async () => { it('fetches pools', async () => {
const pairs = [[wethAddress, wbtcAddress], [wethAddress, balAddress]]; const pairs = [
[wethAddress, wbtcAddress],
[wethAddress, balAddress],
];
await Promise.all( await Promise.all(
// tslint:disable-next-line:promise-function-async // tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)), pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
@ -58,7 +65,10 @@ describe('Pools Caches for Balancer-based sampling', () => {
describe('CreamPoolsCache', () => { describe('CreamPoolsCache', () => {
const cache = new CreamPoolsCache(); const cache = new CreamPoolsCache();
it('fetches pools', async () => { it('fetches pools', async () => {
const pairs = [[usdcAddress, creamAddress], [creamAddress, wethAddress]]; const pairs = [
[usdcAddress, creamAddress],
[creamAddress, wethAddress],
];
await Promise.all( await Promise.all(
// tslint:disable-next-line:promise-function-async // tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)), pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),

View File

@ -1,4 +1,17 @@
[ [
{
"version": "3.15.0",
"changes": [
{
"note": "Update artifacts",
"pr": 237
},
{
"note": "Update IZeroEx artifact",
"pr": 244
}
]
},
{ {
"timestamp": 1620214333, "timestamp": 1620214333,
"version": "3.14.2", "version": "3.14.2",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -47,10 +47,10 @@
}, },
"evm": { "evm": {
"bytecode": { "bytecode": {
"object": "0x608060405234801561001057600080fd5b506103e9806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635b2388be1461003b5780636c90fedb146100ad575b600080fd5b6100ab6004803603602081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b509092509050610155565b005b6100e0600480360360208110156100c357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610227565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561011a578181015183820152602001610102565b50505050905090810190601f1680156101475780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b33600081815260208190526040902061016f9084846102fb565b507fd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e818484604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081815260409182902080548351601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156102ef5780601f106102c4576101008083540402835291602001916102ef565b820191906000526020600020905b8154815290600101906020018083116102d257829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061035a578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555610387565b82800160010185558215610387579182015b8281111561038757823582559160200191906001019061036c565b50610393929150610397565b5090565b6103b191905b80821115610393576000815560010161039d565b9056fea265627a7a72315820f9f613c4d787e3dbaca384615c764f551bb0bf783f7e065251bf8298b929608f64736f6c63430005110032" "object": "0x608060405234801561001057600080fd5b506103e9806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635b2388be1461003b5780636c90fedb146100ad575b600080fd5b6100ab6004803603602081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b509092509050610155565b005b6100e0600480360360208110156100c357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610227565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561011a578181015183820152602001610102565b50505050905090810190601f1680156101475780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b33600081815260208190526040902061016f9084846102fb565b507fd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e818484604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081815260409182902080548351601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156102ef5780601f106102c4576101008083540402835291602001916102ef565b820191906000526020600020905b8154815290600101906020018083116102d257829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061035a578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555610387565b82800160010185558215610387579182015b8281111561038757823582559160200191906001019061036c565b50610393929150610397565b5090565b6103b191905b80821115610393576000815560010161039d565b9056fea265627a7a72315820b312a87be49bf27917f0152f924a8c36406c062ebd65d69024a8ca83cedd7d4d64736f6c63430005110032"
}, },
"deployedBytecode": { "deployedBytecode": {
"object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635b2388be1461003b5780636c90fedb146100ad575b600080fd5b6100ab6004803603602081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b509092509050610155565b005b6100e0600480360360208110156100c357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610227565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561011a578181015183820152602001610102565b50505050905090810190601f1680156101475780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b33600081815260208190526040902061016f9084846102fb565b507fd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e818484604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081815260409182902080548351601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156102ef5780601f106102c4576101008083540402835291602001916102ef565b820191906000526020600020905b8154815290600101906020018083116102d257829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061035a578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555610387565b82800160010185558215610387579182015b8281111561038757823582559160200191906001019061036c565b50610393929150610397565b5090565b6103b191905b80821115610393576000815560010161039d565b9056fea265627a7a72315820f9f613c4d787e3dbaca384615c764f551bb0bf783f7e065251bf8298b929608f64736f6c63430005110032" "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635b2388be1461003b5780636c90fedb146100ad575b600080fd5b6100ab6004803603602081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b509092509050610155565b005b6100e0600480360360208110156100c357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610227565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561011a578181015183820152602001610102565b50505050905090810190601f1680156101475780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b33600081815260208190526040902061016f9084846102fb565b507fd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e818484604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081815260409182902080548351601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156102ef5780601f106102c4576101008083540402835291602001916102ef565b820191906000526020600020905b8154815290600101906020018083116102d257829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061035a578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555610387565b82800160010185558215610387579182015b8281111561038757823582559160200191906001019061036c565b50610393929150610397565b5090565b6103b191905b80821115610393576000815560010161039d565b9056fea265627a7a72315820b312a87be49bf27917f0152f924a8c36406c062ebd65d69024a8ca83cedd7d4d64736f6c63430005110032"
} }
} }
}, },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -135,10 +135,10 @@
}, },
"evm": { "evm": {
"bytecode": { "bytecode": {
"object": "0x608060405234801561001057600080fd5b506106bf806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c806370a082311161005057806370a0823114610121578063a9059cbb14610154578063dd62ed3e1461018d57610072565b8063095ea7b31461007757806318160ddd146100c457806323b872dd146100de575b600080fd5b6100b06004803603604081101561008d57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356101c8565b604080519115158252519081900360200190f35b6100cc61023b565b60408051918252519081900360200190f35b6100b0600480360360608110156100f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610241565b6100cc6004803603602081101561013757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661049d565b6100b06004803603604081101561016a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356104c5565b6100cc600480360360408110156101a357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610652565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b60025490565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120548211156102d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482111561037457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f45524332305f494e53554646494349454e545f414c4c4f57414e434500000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054828101101561040a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff80841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060019392505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b3360009081526020819052604081205482111561054357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110156105d957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209390941682529190915220549056fea265627a7a72315820a8dfa820cda53e10b121646b3f703605fd72bb2675c3ae54b48e68b47c09b50f64736f6c63430005110032" "object": "0x608060405234801561001057600080fd5b506106bf806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c806370a082311161005057806370a0823114610121578063a9059cbb14610154578063dd62ed3e1461018d57610072565b8063095ea7b31461007757806318160ddd146100c457806323b872dd146100de575b600080fd5b6100b06004803603604081101561008d57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356101c8565b604080519115158252519081900360200190f35b6100cc61023b565b60408051918252519081900360200190f35b6100b0600480360360608110156100f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610241565b6100cc6004803603602081101561013757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661049d565b6100b06004803603604081101561016a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356104c5565b6100cc600480360360408110156101a357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610652565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b60025490565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120548211156102d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482111561037457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f45524332305f494e53554646494349454e545f414c4c4f57414e434500000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054828101101561040a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff80841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060019392505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b3360009081526020819052604081205482111561054357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110156105d957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209390941682529190915220549056fea265627a7a723158200a0e5b4813b81b4a59cf323e9296dbdc12eadc2b35caf21c2052aa9fc5df88b364736f6c63430005110032"
}, },
"deployedBytecode": { "deployedBytecode": {
"object": "0x608060405234801561001057600080fd5b50600436106100725760003560e01c806370a082311161005057806370a0823114610121578063a9059cbb14610154578063dd62ed3e1461018d57610072565b8063095ea7b31461007757806318160ddd146100c457806323b872dd146100de575b600080fd5b6100b06004803603604081101561008d57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356101c8565b604080519115158252519081900360200190f35b6100cc61023b565b60408051918252519081900360200190f35b6100b0600480360360608110156100f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610241565b6100cc6004803603602081101561013757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661049d565b6100b06004803603604081101561016a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356104c5565b6100cc600480360360408110156101a357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610652565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b60025490565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120548211156102d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482111561037457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f45524332305f494e53554646494349454e545f414c4c4f57414e434500000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054828101101561040a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff80841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060019392505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b3360009081526020819052604081205482111561054357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110156105d957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209390941682529190915220549056fea265627a7a72315820a8dfa820cda53e10b121646b3f703605fd72bb2675c3ae54b48e68b47c09b50f64736f6c63430005110032" "object": "0x608060405234801561001057600080fd5b50600436106100725760003560e01c806370a082311161005057806370a0823114610121578063a9059cbb14610154578063dd62ed3e1461018d57610072565b8063095ea7b31461007757806318160ddd146100c457806323b872dd146100de575b600080fd5b6100b06004803603604081101561008d57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356101c8565b604080519115158252519081900360200190f35b6100cc61023b565b60408051918252519081900360200190f35b6100b0600480360360608110156100f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610241565b6100cc6004803603602081101561013757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661049d565b6100b06004803603604081101561016a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356104c5565b6100cc600480360360408110156101a357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610652565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b60025490565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120548211156102d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482111561037457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f45524332305f494e53554646494349454e545f414c4c4f57414e434500000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260208190526040902054828101101561040a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff80841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060019392505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b3360009081526020819052604081205482111561054357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110156105d957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209390941682529190915220549056fea265627a7a723158200a0e5b4813b81b4a59cf323e9296dbdc12eadc2b35caf21c2052aa9fc5df88b364736f6c63430005110032"
} }
} }
}, },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -35,10 +35,10 @@
}, },
"evm": { "evm": {
"bytecode": { "bytecode": {
"object": "0x608060405234801561001057600080fd5b5060405161042b38038061042b83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610082565b600060208284031215610065578081fd5b81516001600160a01b038116811461007b578182fd5b9392505050565b61039a806100916000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80639256050a14610030575b600080fd5b61004361003e3660046101fd565b610045565b005b60008061005483850185610197565b600080546040517fb93a89f700000000000000000000000000000000000000000000000000000000815293955091935091829173ffffffffffffffffffffffffffffffffffffffff169063b93a89f7906100b2908a9060040161032c565b604080518083038186803b1580156100c957600080fd5b505afa1580156100dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061010191908101906101cf565b915091508361ffff168261ffff161461014f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610146906102cf565b60405180910390fd5b8260ff168160ff161461018e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014690610272565b50505050505050565b600080604083850312156101a9578182fd5b82356101b481610335565b915060208301356101c481610348565b809150509250929050565b600080604083850312156101e1578182fd5b82516101ec81610335565b60208401519092506101c481610348565b600080600060408486031215610211578081fd5b83359250602084013567ffffffffffffffff8082111561022f578283fd5b81860187601f820112610240578384fd5b8035925081831115610250578384fd5b876020848301011115610261578384fd5b949760209095019650909450505050565b60208082526027908201527f476f6473556e636861696e656456616c696461746f722f5155414c4954595f4d60408201527f49534d4154434800000000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f476f6473556e636861696e656456616c696461746f722f50524f544f5f4d495360408201527f4d41544348000000000000000000000000000000000000000000000000000000606082015260800190565b90815260200190565b61ffff8116811461034557600080fd5b50565b60ff8116811461034557600080fdfea365627a7a723158202171d9b2e4d8e447f88f7b80197b861cd8130f01ab66a3a2ba094d4a968e8ff86c6578706572696d656e74616cf564736f6c63430005110040" "object": "0x608060405234801561001057600080fd5b5060405161042b38038061042b83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610082565b600060208284031215610065578081fd5b81516001600160a01b038116811461007b578182fd5b9392505050565b61039a806100916000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80639256050a14610030575b600080fd5b61004361003e3660046101fd565b610045565b005b60008061005483850185610197565b600080546040517fb93a89f700000000000000000000000000000000000000000000000000000000815293955091935091829173ffffffffffffffffffffffffffffffffffffffff169063b93a89f7906100b2908a9060040161032c565b604080518083038186803b1580156100c957600080fd5b505afa1580156100dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061010191908101906101cf565b915091508361ffff168261ffff161461014f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610146906102cf565b60405180910390fd5b8260ff168160ff161461018e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014690610272565b50505050505050565b600080604083850312156101a9578182fd5b82356101b481610335565b915060208301356101c481610348565b809150509250929050565b600080604083850312156101e1578182fd5b82516101ec81610335565b60208401519092506101c481610348565b600080600060408486031215610211578081fd5b83359250602084013567ffffffffffffffff8082111561022f578283fd5b81860187601f820112610240578384fd5b8035925081831115610250578384fd5b876020848301011115610261578384fd5b949760209095019650909450505050565b60208082526027908201527f476f6473556e636861696e656456616c696461746f722f5155414c4954595f4d60408201527f49534d4154434800000000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f476f6473556e636861696e656456616c696461746f722f50524f544f5f4d495360408201527f4d41544348000000000000000000000000000000000000000000000000000000606082015260800190565b90815260200190565b61ffff8116811461034557600080fd5b50565b60ff8116811461034557600080fdfea365627a7a723158202e078abc4192f31bdba8b9ee66aa83710b9d92589098be5440423730c6275c306c6578706572696d656e74616cf564736f6c63430005110040"
}, },
"deployedBytecode": { "deployedBytecode": {
"object": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80639256050a14610030575b600080fd5b61004361003e3660046101fd565b610045565b005b60008061005483850185610197565b600080546040517fb93a89f700000000000000000000000000000000000000000000000000000000815293955091935091829173ffffffffffffffffffffffffffffffffffffffff169063b93a89f7906100b2908a9060040161032c565b604080518083038186803b1580156100c957600080fd5b505afa1580156100dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061010191908101906101cf565b915091508361ffff168261ffff161461014f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610146906102cf565b60405180910390fd5b8260ff168160ff161461018e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014690610272565b50505050505050565b600080604083850312156101a9578182fd5b82356101b481610335565b915060208301356101c481610348565b809150509250929050565b600080604083850312156101e1578182fd5b82516101ec81610335565b60208401519092506101c481610348565b600080600060408486031215610211578081fd5b83359250602084013567ffffffffffffffff8082111561022f578283fd5b81860187601f820112610240578384fd5b8035925081831115610250578384fd5b876020848301011115610261578384fd5b949760209095019650909450505050565b60208082526027908201527f476f6473556e636861696e656456616c696461746f722f5155414c4954595f4d60408201527f49534d4154434800000000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f476f6473556e636861696e656456616c696461746f722f50524f544f5f4d495360408201527f4d41544348000000000000000000000000000000000000000000000000000000606082015260800190565b90815260200190565b61ffff8116811461034557600080fd5b50565b60ff8116811461034557600080fdfea365627a7a723158202171d9b2e4d8e447f88f7b80197b861cd8130f01ab66a3a2ba094d4a968e8ff86c6578706572696d656e74616cf564736f6c63430005110040" "object": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80639256050a14610030575b600080fd5b61004361003e3660046101fd565b610045565b005b60008061005483850185610197565b600080546040517fb93a89f700000000000000000000000000000000000000000000000000000000815293955091935091829173ffffffffffffffffffffffffffffffffffffffff169063b93a89f7906100b2908a9060040161032c565b604080518083038186803b1580156100c957600080fd5b505afa1580156100dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061010191908101906101cf565b915091508361ffff168261ffff161461014f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610146906102cf565b60405180910390fd5b8260ff168160ff161461018e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014690610272565b50505050505050565b600080604083850312156101a9578182fd5b82356101b481610335565b915060208301356101c481610348565b809150509250929050565b600080604083850312156101e1578182fd5b82516101ec81610335565b60208401519092506101c481610348565b600080600060408486031215610211578081fd5b83359250602084013567ffffffffffffffff8082111561022f578283fd5b81860187601f820112610240578384fd5b8035925081831115610250578384fd5b876020848301011115610261578384fd5b949760209095019650909450505050565b60208082526027908201527f476f6473556e636861696e656456616c696461746f722f5155414c4954595f4d60408201527f49534d4154434800000000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f476f6473556e636861696e656456616c696461746f722f50524f544f5f4d495360408201527f4d41544348000000000000000000000000000000000000000000000000000000606082015260800190565b90815260200190565b61ffff8116811461034557600080fd5b50565b60ff8116811461034557600080fdfea365627a7a723158202e078abc4192f31bdba8b9ee66aa83710b9d92589098be5440423730c6275c306c6578706572696d656e74616cf564736f6c63430005110040"
} }
} }
}, },

View File

@ -89,6 +89,35 @@
"name": "OrderCancelled", "name": "OrderCancelled",
"type": "event" "type": "event"
}, },
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "address", "name": "maker", "type": "address" },
{ "indexed": false, "internalType": "address", "name": "signer", "type": "address" },
{ "indexed": false, "internalType": "bool", "name": "allowed", "type": "bool" }
],
"name": "OrderSignerRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "bytes32", "name": "orderHash", "type": "bytes32" },
{ "indexed": false, "internalType": "address", "name": "maker", "type": "address" },
{ "indexed": false, "internalType": "address", "name": "taker", "type": "address" },
{ "indexed": false, "internalType": "address", "name": "makerToken", "type": "address" },
{ "indexed": false, "internalType": "address", "name": "takerToken", "type": "address" },
{
"indexed": false,
"internalType": "uint128",
"name": "takerTokenFilledAmount",
"type": "uint128"
},
{ "indexed": false, "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
],
"name": "OtcOrderFilled",
"type": "event"
},
{ {
"anonymous": false, "anonymous": false,
"inputs": [ "inputs": [
@ -351,6 +380,18 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "address", "name": "maker", "type": "address" },
{ "internalType": "contract IERC20TokenV06[]", "name": "makerTokens", "type": "address[]" },
{ "internalType": "contract IERC20TokenV06[]", "name": "takerTokens", "type": "address[]" },
{ "internalType": "uint256[]", "name": "minValidSalts", "type": "uint256[]" }
],
"name": "batchCancelPairLimitOrdersWithSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ "internalType": "contract IERC20TokenV06[]", "name": "makerTokens", "type": "address[]" }, { "internalType": "contract IERC20TokenV06[]", "name": "makerTokens", "type": "address[]" },
@ -362,6 +403,18 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "address", "name": "maker", "type": "address" },
{ "internalType": "contract IERC20TokenV06[]", "name": "makerTokens", "type": "address[]" },
{ "internalType": "contract IERC20TokenV06[]", "name": "takerTokens", "type": "address[]" },
{ "internalType": "uint256[]", "name": "minValidSalts", "type": "uint256[]" }
],
"name": "batchCancelPairRfqOrdersWithSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
@ -694,6 +747,18 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "address", "name": "maker", "type": "address" },
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
{ "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" },
{ "internalType": "uint256", "name": "minValidSalt", "type": "uint256" }
],
"name": "cancelPairLimitOrdersWithSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" }, { "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
@ -705,6 +770,18 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "address", "name": "maker", "type": "address" },
{ "internalType": "contract IERC20TokenV06", "name": "makerToken", "type": "address" },
{ "internalType": "contract IERC20TokenV06", "name": "takerToken", "type": "address" },
{ "internalType": "uint256", "name": "minValidSalt", "type": "uint256" }
],
"name": "cancelPairRfqOrdersWithSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
@ -917,6 +994,90 @@
"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" },
{ "internalType": "bool", "name": "unwrapWeth", "type": "bool" }
],
"name": "fillOtcOrder",
"outputs": [
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" },
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
],
"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"
}
],
"name": "fillOtcOrderWithEth",
"outputs": [
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" },
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
],
"stateMutability": "payable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
@ -961,6 +1122,63 @@
"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"
},
{
"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"
},
{ "internalType": "bool", "name": "unwrapWeth", "type": "bool" }
],
"name": "fillTakerSignedOtcOrder",
"outputs": [
{ "internalType": "uint128", "name": "takerTokenFilledAmount", "type": "uint128" },
{ "internalType": "uint128", "name": "makerTokenFilledAmount", "type": "uint128" }
],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
@ -1138,6 +1356,62 @@
"stateMutability": "view", "stateMutability": "view",
"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"
}
],
"name": "getOtcOrderHash",
"outputs": [{ "internalType": "bytes32", "name": "orderHash", "type": "bytes32" }],
"stateMutability": "view",
"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"
}
],
"name": "getOtcOrderInfo",
"outputs": [
{
"components": [
{ "internalType": "bytes32", "name": "orderHash", "type": "bytes32" },
{ "internalType": "enum LibNativeOrder.OrderStatus", "name": "status", "type": "uint8" }
],
"internalType": "struct LibNativeOrder.OtcOrderInfo",
"name": "orderInfo",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "getProtocolFeeMultiplier", "name": "getProtocolFeeMultiplier",
@ -1297,6 +1571,26 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "address", "name": "maker", "type": "address" },
{ "internalType": "address", "name": "signer", "type": "address" }
],
"name": "isValidOrderSigner",
"outputs": [{ "internalType": "bool", "name": "isAllowed", "type": "bool" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "address", "name": "txOrigin", "type": "address" },
{ "internalType": "uint64", "name": "nonceBucket", "type": "uint64" }
],
"name": "lastOtcTxOriginNonce",
"outputs": [{ "internalType": "uint128", "name": "lastNonce", "type": "uint128" }],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ "internalType": "address", "name": "target", "type": "address" }, { "internalType": "address", "name": "target", "type": "address" },
@ -1342,6 +1636,16 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "address", "name": "signer", "type": "address" },
{ "internalType": "bool", "name": "allowed", "type": "bool" }
],
"name": "registerAllowedOrderSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ "internalType": "address[]", "name": "origins", "type": "address[]" }, { "internalType": "address[]", "name": "origins", "type": "address[]" },
@ -1362,6 +1666,17 @@
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{ "internalType": "bytes", "name": "encodedPath", "type": "bytes" },
{ "internalType": "uint256", "name": "minBuyAmount", "type": "uint256" },
{ "internalType": "address", "name": "recipient", "type": "address" }
],
"name": "sellEthForTokenToUniswapV3",
"outputs": [{ "internalType": "uint256", "name": "buyAmount", "type": "uint256" }],
"stateMutability": "payable",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" }, { "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" },
@ -1401,6 +1716,30 @@
"stateMutability": "payable", "stateMutability": "payable",
"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 payable", "name": "recipient", "type": "address" }
],
"name": "sellTokenForEthToUniswapV3",
"outputs": [{ "internalType": "uint256", "name": "buyAmount", "type": "uint256" }],
"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": "sellTokenForTokenToUniswapV3",
"outputs": [{ "internalType": "uint256", "name": "buyAmount", "type": "uint256" }],
"stateMutability": "nonpayable",
"type": "function"
},
{ {
"inputs": [{ "internalType": "address", "name": "quoteSigner", "type": "address" }], "inputs": [{ "internalType": "address", "name": "quoteSigner", "type": "address" }],
"name": "setQuoteSigner", "name": "setQuoteSigner",
@ -1449,6 +1788,17 @@
"outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }], "outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }],
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "type": "function"
},
{
"inputs": [
{ "internalType": "int256", "name": "amount0Delta", "type": "int256" },
{ "internalType": "int256", "name": "amount1Delta", "type": "int256" },
{ "internalType": "bytes", "name": "data", "type": "bytes" }
],
"name": "uniswapV3SwapCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
} }
], ],
"devdoc": { "devdoc": {
@ -1488,27 +1838,45 @@
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." } "returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." }
}, },
"batchCancelLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[])": { "batchCancelLimitOrders((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256)[])": {
"details": "Cancel multiple limit orders. The caller must be the maker. Silently succeeds if the order has already been cancelled.", "details": "Cancel multiple limit orders. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.",
"params": { "orders": "The limit orders." } "params": { "orders": "The limit orders." }
}, },
"batchCancelPairLimitOrders(address[],address[],uint256[])": { "batchCancelPairLimitOrders(address[],address[],uint256[])": {
"details": "Cancel all limit orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", "details": "Cancel all limit orders for a given maker and pairs with salts less than the values provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.",
"params": { "params": {
"makerTokens": "The maker tokens.", "makerTokens": "The maker tokens.",
"minValidSalts": "The new minimum valid salts.", "minValidSalts": "The new minimum valid salts.",
"takerTokens": "The taker tokens." "takerTokens": "The taker tokens."
} }
}, },
"batchCancelPairLimitOrdersWithSigner(address,address[],address[],uint256[])": {
"details": "Cancel all limit orders for a given maker and pairs with salts less than the values provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.",
"params": {
"maker": "The maker for which to cancel.",
"makerTokens": "The maker tokens.",
"minValidSalts": "The new minimum valid salts.",
"takerTokens": "The taker tokens."
}
},
"batchCancelPairRfqOrders(address[],address[],uint256[])": { "batchCancelPairRfqOrders(address[],address[],uint256[])": {
"details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", "details": "Cancel all RFQ orders for a given maker and pairs with salts less than the values provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.",
"params": { "params": {
"makerTokens": "The maker tokens.", "makerTokens": "The maker tokens.",
"minValidSalts": "The new minimum valid salts.", "minValidSalts": "The new minimum valid salts.",
"takerTokens": "The taker tokens." "takerTokens": "The taker tokens."
} }
}, },
"batchCancelPairRfqOrdersWithSigner(address,address[],address[],uint256[])": {
"details": "Cancel all RFQ orders for a given maker and pairs with salts less than the values provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.",
"params": {
"maker": "The maker for which to cancel.",
"makerTokens": "The maker tokens.",
"minValidSalts": "The new minimum valid salts.",
"takerTokens": "The taker tokens."
}
},
"batchCancelRfqOrders((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[])": { "batchCancelRfqOrders((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256)[])": {
"details": "Cancel multiple RFQ orders. The caller must be the maker. Silently succeeds if the order has already been cancelled.", "details": "Cancel multiple RFQ orders. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.",
"params": { "orders": "The RFQ orders." } "params": { "orders": "The RFQ orders." }
}, },
"batchExecuteMetaTransactions((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256)[],(uint8,uint8,bytes32,bytes32)[])": { "batchExecuteMetaTransactions((address,address,uint256,uint256,uint256,uint256,bytes,uint256,address,uint256)[],(uint8,uint8,bytes32,bytes32)[])": {
@ -1572,7 +1940,7 @@
} }
}, },
"cancelLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": { "cancelLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256))": {
"details": "Cancel a single limit order. The caller must be the maker. Silently succeeds if the order has already been cancelled.", "details": "Cancel a single limit order. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.",
"params": { "order": "The limit order." } "params": { "order": "The limit order." }
}, },
"cancelPairLimitOrders(address,address,uint256)": { "cancelPairLimitOrders(address,address,uint256)": {
@ -1583,6 +1951,15 @@
"takerToken": "The taker token." "takerToken": "The taker token."
} }
}, },
"cancelPairLimitOrdersWithSigner(address,address,address,uint256)": {
"details": "Cancel all limit orders for a given maker and pair with a salt less than the value provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.",
"params": {
"maker": "The maker for which to cancel.",
"makerToken": "The maker token.",
"minValidSalt": "The new minimum valid salt.",
"takerToken": "The taker token."
}
},
"cancelPairRfqOrders(address,address,uint256)": { "cancelPairRfqOrders(address,address,uint256)": {
"details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.", "details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be the maker. Subsequent calls to this function with the same caller and pair require the new salt to be >= the old salt.",
"params": { "params": {
@ -1591,8 +1968,17 @@
"takerToken": "The taker token." "takerToken": "The taker token."
} }
}, },
"cancelPairRfqOrdersWithSigner(address,address,address,uint256)": {
"details": "Cancel all RFQ orders for a given maker and pair with a salt less than the value provided. The caller must be a signer registered to the maker. Subsequent calls to this function with the same maker and pair require the new salt to be >= the old salt.",
"params": {
"maker": "The maker for which to cancel.",
"makerToken": "The maker token.",
"minValidSalt": "The new minimum valid salt.",
"takerToken": "The taker token."
}
},
"cancelRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": { "cancelRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256))": {
"details": "Cancel a single RFQ order. The caller must be the maker. Silently succeeds if the order has already been cancelled.", "details": "Cancel a single RFQ order. The caller must be the maker or a valid order signer. Silently succeeds if the order has already been cancelled.",
"params": { "order": "The RFQ order." } "params": { "order": "The RFQ order." }
}, },
"createTransformWallet()": { "createTransformWallet()": {
@ -1641,6 +2027,27 @@
}, },
"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)": {
"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"
},
"returns": {
"makerTokenFilledAmount": "How much maker token was filled.",
"takerTokenFilledAmount": "How much taker token was filled."
}
},
"fillOtcOrderWithEth((address,address,uint128,uint128,address,address,address,uint256),(uint8,uint8,bytes32,bytes32))": {
"details": "Fill an OTC order whose taker token is WETH for up to `msg.value`.",
"params": { "makerSignature": "The order signature from the maker.", "order": "The OTC order." },
"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)": { "fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": {
"details": "Fill an RFQ order for up to `takerTokenFillAmount` taker tokens. The taker will be the caller.", "details": "Fill an RFQ order for up to `takerTokenFillAmount` taker tokens. The taker will be the caller.",
"params": { "params": {
@ -1653,6 +2060,19 @@
"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)": {
"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."
}
},
"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))": {
"details": "Get the canonical hash of a limit order.", "details": "Get the canonical hash of a limit order.",
"params": { "order": "The limit order." }, "params": { "order": "The limit order." },
@ -1687,6 +2107,16 @@
"params": { "mtxHash": "The meta-transaction hash." }, "params": { "mtxHash": "The meta-transaction hash." },
"returns": { "blockNumber": "The block height when the meta-transactioin was executed." } "returns": { "blockNumber": "The block height when the meta-transactioin was executed." }
}, },
"getOtcOrderHash((address,address,uint128,uint128,address,address,address,uint256))": {
"details": "Get the canonical hash of an OTC order.",
"params": { "order": "The OTC order." },
"returns": { "orderHash": "The order hash." }
},
"getOtcOrderInfo((address,address,uint128,uint128,address,address,address,uint256))": {
"details": "Get the order info for an OTC order.",
"params": { "order": "The OTC order." },
"returns": { "orderInfo": "Info about the order." }
},
"getProtocolFeeMultiplier()": { "getProtocolFeeMultiplier()": {
"details": "Get the protocol fee multiplier. This should be multiplied by the gas price to arrive at the required protocol fee to fill a native order.", "details": "Get the protocol fee multiplier. This should be multiplied by the gas price to arrive at the required protocol fee to fill a native order.",
"returns": { "multiplier": "The protocol fee multiplier." } "returns": { "multiplier": "The protocol fee multiplier." }
@ -1734,6 +2164,18 @@
"details": "Return the allowed deployer for transformers.", "details": "Return the allowed deployer for transformers.",
"returns": { "deployer": "The transform deployer address." } "returns": { "deployer": "The transform deployer address." }
}, },
"isValidOrderSigner(address,address)": {
"details": "checks if a given address is registered to sign on behalf of a maker address",
"params": {
"maker": "The maker address encoded in an order (can be a contract)",
"signer": "The address that is providing a signature"
}
},
"lastOtcTxOriginNonce(address,uint64)": {
"details": "Get the last nonce used for a particular tx.origin address and nonce bucket.",
"params": { "nonceBucket": "The nonce bucket index.", "txOrigin": "The address." },
"returns": { "lastNonce": "The last nonce value used." }
},
"migrate(address,bytes,address)": { "migrate(address,bytes,address)": {
"details": "Execute a migration function in the context of the ZeroEx contract. The result of the function being called should be the magic bytes 0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner. The owner will be temporarily set to `address(this)` inside the call. Before returning, the owner will be set to `newOwner`.", "details": "Execute a migration function in the context of the ZeroEx contract. The result of the function being called should be the magic bytes 0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner. The owner will be temporarily set to `address(this)` inside the call. Before returning, the owner will be set to `newOwner`.",
"params": { "params": {
@ -1754,6 +2196,13 @@
"details": "The owner of this contract.", "details": "The owner of this contract.",
"returns": { "ownerAddress": "The owner address." } "returns": { "ownerAddress": "The owner address." }
}, },
"registerAllowedOrderSigner(address,bool)": {
"details": "Register a signer who can sign on behalf of msg.sender This allows one to sign on behalf of a contract that calls this function",
"params": {
"allowed": "True to register, false to unregister.",
"signer": "The address from which you plan to generate signatures"
}
},
"registerAllowedRfqOrigins(address[],bool)": { "registerAllowedRfqOrigins(address[],bool)": {
"details": "Mark what tx.origin addresses are allowed to fill an order that specifies the message sender as its txOrigin.", "details": "Mark what tx.origin addresses are allowed to fill an order that specifies the message sender as its txOrigin.",
"params": { "params": {
@ -1768,6 +2217,15 @@
"targetImpl": "The address of an older implementation of the function." "targetImpl": "The address of an older implementation of the function."
} }
}, },
"sellEthForTokenToUniswapV3(bytes,uint256,address)": {
"details": "Sell attached ETH directly against uniswap v3.",
"params": {
"encodedPath": "Uniswap-encoded path, where the first token is WETH.",
"minBuyAmount": "Minimum amount of the last token in the path to buy.",
"recipient": "The recipient of the bought tokens. Can be zero for sender."
},
"returns": { "buyAmount": "Amount of the last token in the path bought." }
},
"sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)": { "sellToLiquidityProvider(address,address,address,address,uint256,uint256,bytes)": {
"details": "Sells `sellAmount` of `inputToken` to the liquidity provider at the given `provider` address.", "details": "Sells `sellAmount` of `inputToken` to the liquidity provider at the given `provider` address.",
"params": { "params": {
@ -1782,7 +2240,7 @@
"returns": { "boughtAmount": "The amount of `outputToken` bought." } "returns": { "boughtAmount": "The amount of `outputToken` bought." }
}, },
"sellToPancakeSwap(address[],uint256,uint256,uint8)": { "sellToPancakeSwap(address[],uint256,uint256,uint8)": {
"details": "Efficiently sell directly to PancakeSwap/BakerySwap/Sushiswap.", "details": "Efficiently sell directly to PancakeSwap (and forks).",
"params": { "params": {
"fork": "The protocol fork to use.", "fork": "The protocol fork to use.",
"minBuyAmount": "Minimum amount of `tokens[-1]` to buy.", "minBuyAmount": "Minimum amount of `tokens[-1]` to buy.",
@ -1801,6 +2259,26 @@
}, },
"returns": { "buyAmount": "Amount of `tokens[-1]` bought." } "returns": { "buyAmount": "Amount of `tokens[-1]` bought." }
}, },
"sellTokenForEthToUniswapV3(bytes,uint256,uint256,address)": {
"details": "Sell a token for ETH directly against uniswap v3.",
"params": {
"encodedPath": "Uniswap-encoded path, where the last token is WETH.",
"minBuyAmount": "Minimum amount of ETH 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 ETH bought." }
},
"sellTokenForTokenToUniswapV3(bytes,uint256,uint256,address)": {
"details": "Sell a token for another token directly against uniswap v3.",
"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." }
},
"setQuoteSigner(address)": { "setQuoteSigner(address)": {
"details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.", "details": "Replace the optional signer for `transformERC20()` calldata. Only callable by the owner.",
"params": { "quoteSigner": "The address of the new calldata signer." } "params": { "quoteSigner": "The address of the new calldata signer." }
@ -1829,6 +2307,14 @@
"transformations": "The transformations to execute on the token balance(s) in sequence." "transformations": "The transformations to execute on the token balance(s) in sequence."
}, },
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the sender." } "returns": { "outputTokenAmount": "The amount of `outputToken` received by the sender." }
},
"uniswapV3SwapCallback(int256,int256,bytes)": {
"details": "The UniswapV3 pool swap callback which pays the funds requested by the caller/pool to the pool. Can only be called by a valid UniswapV3 pool.",
"params": {
"amount0Delta": "Token0 amount owed.",
"amount1Delta": "Token1 amount owed.",
"data": "Arbitrary data forwarded from swap() caller. An ABI-encoded struct of: inputToken, outputToken, fee, payer"
}
} }
}, },
"version": 1 "version": 1

File diff suppressed because one or more lines are too long

View File

@ -58,9 +58,15 @@
}, },
{ {
"constant": true, "constant": true,
"inputs": [{ "name": "target", "type": "address" }, { "name": "assetData", "type": "bytes" }], "inputs": [
{ "name": "target", "type": "address" },
{ "name": "assetData", "type": "bytes" }
],
"name": "getBalanceAndAllowance", "name": "getBalanceAndAllowance",
"outputs": [{ "name": "balance", "type": "uint256" }, { "name": "allowance", "type": "uint256" }], "outputs": [
{ "name": "balance", "type": "uint256" },
{ "name": "allowance", "type": "uint256" }
],
"payable": false, "payable": false,
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
@ -164,7 +170,10 @@
}, },
{ {
"constant": true, "constant": true,
"inputs": [{ "name": "token", "type": "address" }, { "name": "tokenId", "type": "uint256" }], "inputs": [
{ "name": "token", "type": "address" },
{ "name": "tokenId", "type": "uint256" }
],
"name": "getERC721TokenOwner", "name": "getERC721TokenOwner",
"outputs": [{ "name": "owner", "type": "address" }], "outputs": [{ "name": "owner", "type": "address" }],
"payable": false, "payable": false,
@ -173,9 +182,15 @@
}, },
{ {
"constant": true, "constant": true,
"inputs": [{ "name": "target", "type": "address" }, { "name": "assetData", "type": "bytes[]" }], "inputs": [
{ "name": "target", "type": "address" },
{ "name": "assetData", "type": "bytes[]" }
],
"name": "getBalancesAndAllowances", "name": "getBalancesAndAllowances",
"outputs": [{ "name": "", "type": "uint256[]" }, { "name": "", "type": "uint256[]" }], "outputs": [
{ "name": "", "type": "uint256[]" },
{ "name": "", "type": "uint256[]" }
],
"payable": false, "payable": false,
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
@ -225,7 +240,10 @@
"type": "function" "type": "function"
}, },
{ {
"inputs": [{ "name": "_exchange", "type": "address" }, { "name": "_zrxAssetData", "type": "bytes" }], "inputs": [
{ "name": "_exchange", "type": "address" },
{ "name": "_zrxAssetData", "type": "bytes" }
],
"payable": false, "payable": false,
"stateMutability": "nonpayable", "stateMutability": "nonpayable",
"type": "constructor" "type": "constructor"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -46,10 +46,10 @@
}, },
"evm": { "evm": {
"bytecode": { "bytecode": {
"object": "0x608060405234801561001057600080fd5b50610505806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a85e59e41461003b578063ae25532e146100d3575b600080fd5b6100d16004803603608081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610110565b005b6100db6103a5565b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b6000606060006101656004898990508a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff6103c5169050565b806020019051606081101561017957600080fd5b8151602083018051604051929492938301929190846401000000008211156101a057600080fd5b9083019060208201858111156101b557600080fd5b82516401000000008111828201881017156101cf57600080fd5b82525081516020918201929091019080838360005b838110156101fc5781810151838201526020016101e4565b50505050905090810190601f1680156102295780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190505050925092509250600060608473ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b602083106102ac57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161026f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461030c576040519150601f19603f3d011682016040523d82523d6000602084013e610311565b606091505b50915091508161032357805160208201fd5b8051602082012083811461039857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f554e45585045435445445f5354415449435f43414c4c5f524553554c54000000604482015290519081900360640190fd5b5050505050505050505050565b600060405180806104b06021913960210190506040518091039020905090565b6060818311156103e3576103e36103de60008585610408565b6104a7565b83518211156103fc576103fc6103de6001848751610408565b50819003910190815290565b6060632800659560e01b8484846040516024018084600781111561042857fe5b60ff1681526020018381526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090509392505050565b805160208201fdfe53746174696343616c6c28616464726573732c62797465732c6279746573333229a265627a7a72315820cd5eb07e7dbc2032db9244c3c2a1537a30a5215455203f4ba8dcfbe3a44c00ed64736f6c63430005110032" "object": "0x608060405234801561001057600080fd5b50610505806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a85e59e41461003b578063ae25532e146100d3575b600080fd5b6100d16004803603608081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610110565b005b6100db6103a5565b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b6000606060006101656004898990508a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff6103c5169050565b806020019051606081101561017957600080fd5b8151602083018051604051929492938301929190846401000000008211156101a057600080fd5b9083019060208201858111156101b557600080fd5b82516401000000008111828201881017156101cf57600080fd5b82525081516020918201929091019080838360005b838110156101fc5781810151838201526020016101e4565b50505050905090810190601f1680156102295780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190505050925092509250600060608473ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b602083106102ac57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161026f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461030c576040519150601f19603f3d011682016040523d82523d6000602084013e610311565b606091505b50915091508161032357805160208201fd5b8051602082012083811461039857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f554e45585045435445445f5354415449435f43414c4c5f524553554c54000000604482015290519081900360640190fd5b5050505050505050505050565b600060405180806104b06021913960210190506040518091039020905090565b6060818311156103e3576103e36103de60008585610408565b6104a7565b83518211156103fc576103fc6103de6001848751610408565b50819003910190815290565b6060632800659560e01b8484846040516024018084600781111561042857fe5b60ff1681526020018381526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090509392505050565b805160208201fdfe53746174696343616c6c28616464726573732c62797465732c6279746573333229a265627a7a72315820b0263a415f7a30e5dfb57dfdca6a544c1deec40d1259b7cf5cd5c3ccf13825ff64736f6c63430005110032"
}, },
"deployedBytecode": { "deployedBytecode": {
"object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063a85e59e41461003b578063ae25532e146100d3575b600080fd5b6100d16004803603608081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610110565b005b6100db6103a5565b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b6000606060006101656004898990508a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff6103c5169050565b806020019051606081101561017957600080fd5b8151602083018051604051929492938301929190846401000000008211156101a057600080fd5b9083019060208201858111156101b557600080fd5b82516401000000008111828201881017156101cf57600080fd5b82525081516020918201929091019080838360005b838110156101fc5781810151838201526020016101e4565b50505050905090810190601f1680156102295780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190505050925092509250600060608473ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b602083106102ac57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161026f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461030c576040519150601f19603f3d011682016040523d82523d6000602084013e610311565b606091505b50915091508161032357805160208201fd5b8051602082012083811461039857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f554e45585045435445445f5354415449435f43414c4c5f524553554c54000000604482015290519081900360640190fd5b5050505050505050505050565b600060405180806104b06021913960210190506040518091039020905090565b6060818311156103e3576103e36103de60008585610408565b6104a7565b83518211156103fc576103fc6103de6001848751610408565b50819003910190815290565b6060632800659560e01b8484846040516024018084600781111561042857fe5b60ff1681526020018381526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090509392505050565b805160208201fdfe53746174696343616c6c28616464726573732c62797465732c6279746573333229a265627a7a72315820cd5eb07e7dbc2032db9244c3c2a1537a30a5215455203f4ba8dcfbe3a44c00ed64736f6c63430005110032" "object": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063a85e59e41461003b578063ae25532e146100d3575b600080fd5b6100d16004803603608081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610110565b005b6100db6103a5565b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b6000606060006101656004898990508a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff6103c5169050565b806020019051606081101561017957600080fd5b8151602083018051604051929492938301929190846401000000008211156101a057600080fd5b9083019060208201858111156101b557600080fd5b82516401000000008111828201881017156101cf57600080fd5b82525081516020918201929091019080838360005b838110156101fc5781810151838201526020016101e4565b50505050905090810190601f1680156102295780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190505050925092509250600060608473ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b602083106102ac57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161026f565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461030c576040519150601f19603f3d011682016040523d82523d6000602084013e610311565b606091505b50915091508161032357805160208201fd5b8051602082012083811461039857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f554e45585045435445445f5354415449435f43414c4c5f524553554c54000000604482015290519081900360640190fd5b5050505050505050505050565b600060405180806104b06021913960210190506040518091039020905090565b6060818311156103e3576103e36103de60008585610408565b6104a7565b83518211156103fc576103fc6103de6001848751610408565b50819003910190815290565b6060632800659560e01b8484846040516024018084600781111561042857fe5b60ff1681526020018381526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090509392505050565b805160208201fdfe53746174696343616c6c28616464726573732c62797465732c6279746573333229a265627a7a72315820b0263a415f7a30e5dfb57dfdca6a544c1deec40d1259b7cf5cd5c3ccf13825ff64736f6c63430005110032"
} }
} }
}, },

View File

@ -158,10 +158,10 @@
"devdoc": { "methods": {} }, "devdoc": { "methods": {} },
"evm": { "evm": {
"bytecode": { "bytecode": {
"object": "0x60c0604052600d60808190526c2bb930b83832b21022ba3432b960991b60a090815261002e916000919061007a565b50604080518082019091526004808252630ae8aa8960e31b602090920191825261005a9160019161007a565b506002805460ff1916601217905534801561007457600080fd5b50610115565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100bb57805160ff19168380011785556100e8565b828001600101855582156100e8579182015b828111156100e85782518255916020019190600101906100cd565b506100f49291506100f8565b5090565b61011291905b808211156100f457600081556001016100fe565b90565b6107f9806101246000396000f3fe6080604052600436106100bc5760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146102cb578063d0e30db0146100bc578063dd62ed3e14610311576100bc565b8063313ce5671461024b57806370a082311461027657806395d89b41146102b6576100bc565b806318160ddd116100a557806318160ddd146101aa57806323b872dd146101d15780632e1a7d4d14610221576100bc565b806306fdde03146100c6578063095ea7b314610150575b6100c4610359565b005b3480156100d257600080fd5b506100db6103a8565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101155781810151838201526020016100fd565b50505050905090810190601f1680156101425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015c57600080fd5b506101966004803603604081101561017357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610454565b604080519115158252519081900360200190f35b3480156101b657600080fd5b506101bf6104c7565b60408051918252519081900360200190f35b3480156101dd57600080fd5b50610196600480360360608110156101f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356104cb565b34801561022d57600080fd5b506100c46004803603602081101561024457600080fd5b503561066b565b34801561025757600080fd5b50610260610700565b6040805160ff9092168252519081900360200190f35b34801561028257600080fd5b506101bf6004803603602081101561029957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610709565b3480156102c257600080fd5b506100db61071b565b3480156102d757600080fd5b50610196600480360360408110156102ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610793565b34801561031d57600080fd5b506101bf6004803603604081101561033457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166107a7565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b820191906000526020600020905b81548152906001019060200180831161042f57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b4790565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156104fd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610573575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105ed5773ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020548211156105b557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b3360009081526003602052604090205481111561068757600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f193505050501580156106c6573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b60006107a03384846104cb565b9392505050565b60046020908152600092835260408084209091529082529020548156fea265627a7a72315820d9a3cb7dd9ede3ac96fb266672eff52fa24203242857daf9b531d43d4cdbd2c664736f6c63430005110032" "object": "0x60c0604052600d60808190526c2bb930b83832b21022ba3432b960991b60a090815261002e916000919061007a565b50604080518082019091526004808252630ae8aa8960e31b602090920191825261005a9160019161007a565b506002805460ff1916601217905534801561007457600080fd5b50610115565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100bb57805160ff19168380011785556100e8565b828001600101855582156100e8579182015b828111156100e85782518255916020019190600101906100cd565b506100f49291506100f8565b5090565b61011291905b808211156100f457600081556001016100fe565b90565b6107f9806101246000396000f3fe6080604052600436106100bc5760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146102cb578063d0e30db0146100bc578063dd62ed3e14610311576100bc565b8063313ce5671461024b57806370a082311461027657806395d89b41146102b6576100bc565b806318160ddd116100a557806318160ddd146101aa57806323b872dd146101d15780632e1a7d4d14610221576100bc565b806306fdde03146100c6578063095ea7b314610150575b6100c4610359565b005b3480156100d257600080fd5b506100db6103a8565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101155781810151838201526020016100fd565b50505050905090810190601f1680156101425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015c57600080fd5b506101966004803603604081101561017357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610454565b604080519115158252519081900360200190f35b3480156101b657600080fd5b506101bf6104c7565b60408051918252519081900360200190f35b3480156101dd57600080fd5b50610196600480360360608110156101f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356104cb565b34801561022d57600080fd5b506100c46004803603602081101561024457600080fd5b503561066b565b34801561025757600080fd5b50610260610700565b6040805160ff9092168252519081900360200190f35b34801561028257600080fd5b506101bf6004803603602081101561029957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610709565b3480156102c257600080fd5b506100db61071b565b3480156102d757600080fd5b50610196600480360360408110156102ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610793565b34801561031d57600080fd5b506101bf6004803603604081101561033457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166107a7565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b820191906000526020600020905b81548152906001019060200180831161042f57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b4790565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156104fd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610573575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105ed5773ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020548211156105b557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b3360009081526003602052604090205481111561068757600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f193505050501580156106c6573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b60006107a03384846104cb565b9392505050565b60046020908152600092835260408084209091529082529020548156fea265627a7a723158206b7dcca2f4268299085314087a9c8506d18f6b6a5debabd331b75cf760e6714564736f6c63430005110032"
}, },
"deployedBytecode": { "deployedBytecode": {
"object": "0x6080604052600436106100bc5760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146102cb578063d0e30db0146100bc578063dd62ed3e14610311576100bc565b8063313ce5671461024b57806370a082311461027657806395d89b41146102b6576100bc565b806318160ddd116100a557806318160ddd146101aa57806323b872dd146101d15780632e1a7d4d14610221576100bc565b806306fdde03146100c6578063095ea7b314610150575b6100c4610359565b005b3480156100d257600080fd5b506100db6103a8565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101155781810151838201526020016100fd565b50505050905090810190601f1680156101425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015c57600080fd5b506101966004803603604081101561017357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610454565b604080519115158252519081900360200190f35b3480156101b657600080fd5b506101bf6104c7565b60408051918252519081900360200190f35b3480156101dd57600080fd5b50610196600480360360608110156101f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356104cb565b34801561022d57600080fd5b506100c46004803603602081101561024457600080fd5b503561066b565b34801561025757600080fd5b50610260610700565b6040805160ff9092168252519081900360200190f35b34801561028257600080fd5b506101bf6004803603602081101561029957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610709565b3480156102c257600080fd5b506100db61071b565b3480156102d757600080fd5b50610196600480360360408110156102ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610793565b34801561031d57600080fd5b506101bf6004803603604081101561033457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166107a7565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b820191906000526020600020905b81548152906001019060200180831161042f57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b4790565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156104fd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610573575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105ed5773ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020548211156105b557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b3360009081526003602052604090205481111561068757600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f193505050501580156106c6573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b60006107a03384846104cb565b9392505050565b60046020908152600092835260408084209091529082529020548156fea265627a7a72315820d9a3cb7dd9ede3ac96fb266672eff52fa24203242857daf9b531d43d4cdbd2c664736f6c63430005110032" "object": "0x6080604052600436106100bc5760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146102cb578063d0e30db0146100bc578063dd62ed3e14610311576100bc565b8063313ce5671461024b57806370a082311461027657806395d89b41146102b6576100bc565b806318160ddd116100a557806318160ddd146101aa57806323b872dd146101d15780632e1a7d4d14610221576100bc565b806306fdde03146100c6578063095ea7b314610150575b6100c4610359565b005b3480156100d257600080fd5b506100db6103a8565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101155781810151838201526020016100fd565b50505050905090810190601f1680156101425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015c57600080fd5b506101966004803603604081101561017357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610454565b604080519115158252519081900360200190f35b3480156101b657600080fd5b506101bf6104c7565b60408051918252519081900360200190f35b3480156101dd57600080fd5b50610196600480360360608110156101f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356104cb565b34801561022d57600080fd5b506100c46004803603602081101561024457600080fd5b503561066b565b34801561025757600080fd5b50610260610700565b6040805160ff9092168252519081900360200190f35b34801561028257600080fd5b506101bf6004803603602081101561029957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610709565b3480156102c257600080fd5b506100db61071b565b3480156102d757600080fd5b50610196600480360360408110156102ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610793565b34801561031d57600080fd5b506101bf6004803603604081101561033457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166107a7565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b820191906000526020600020905b81548152906001019060200180831161042f57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b4790565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156104fd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610573575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105ed5773ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020548211156105b557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b3360009081526003602052604090205481111561068757600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f193505050501580156106c6573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b60006107a03384846104cb565b9392505050565b60046020908152600092835260408084209091529082529020548156fea265627a7a723158206b7dcca2f4268299085314087a9c8506d18f6b6a5debabd331b75cf760e6714564736f6c63430005110032"
} }
} }
}, },

View File

@ -13,7 +13,10 @@
}, },
{ {
"constant": false, "constant": false,
"inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }], "inputs": [
{ "name": "_spender", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "approve", "name": "approve",
"outputs": [{ "name": "", "type": "bool" }], "outputs": [{ "name": "", "type": "bool" }],
"payable": false, "payable": false,
@ -65,7 +68,10 @@
}, },
{ {
"constant": false, "constant": false,
"inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }], "inputs": [
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transfer", "name": "transfer",
"outputs": [{ "name": "", "type": "bool" }], "outputs": [{ "name": "", "type": "bool" }],
"payable": false, "payable": false,
@ -73,7 +79,10 @@
}, },
{ {
"constant": true, "constant": true,
"inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }], "inputs": [
{ "name": "_owner", "type": "address" },
{ "name": "_spender", "type": "address" }
],
"name": "allowance", "name": "allowance",
"outputs": [{ "name": "", "type": "uint256" }], "outputs": [{ "name": "", "type": "uint256" }],
"payable": false, "payable": false,
@ -116,10 +125,10 @@
}, },
"evm": { "evm": {
"bytecode": { "bytecode": {
"object": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b61078d8061004a6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a72305820efa3052a25415ea6f79477587210b6a7d91547c0ce4023ade95ef4cacd8adecc0029" "object": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b61078d8061004a6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a7230582046535601227b5593da4370a7dfeedd2cba029ac1cbef52fe6cae0e64fbbb37ce0029"
}, },
"deployedBytecode": { "deployedBytecode": {
"object": "0x606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a72305820efa3052a25415ea6f79477587210b6a7d91547c0ce4023ade95ef4cacd8adecc0029" "object": "0x606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a7230582046535601227b5593da4370a7dfeedd2cba029ac1cbef52fe6cae0e64fbbb37ce0029"
} }
} }
}, },

File diff suppressed because one or more lines are too long

View File

@ -39,9 +39,7 @@ for (const dir of contractsDirs) {
if (allArtifactPaths.length < pkgNames.length) { if (allArtifactPaths.length < pkgNames.length) {
throw new Error( throw new Error(
`Expected ${pkgNames.length} artifacts, found ${ `Expected ${pkgNames.length} artifacts, found ${allArtifactPaths.length}. Please ensure artifacts are present in ${contractsPath}/**/generated-artifacts`,
allArtifactPaths.length
}. Please ensure artifacts are present in ${contractsPath}/**/generated-artifacts`,
); );
} }

View File

@ -1,4 +1,17 @@
[ [
{
"version": "13.17.0",
"changes": [
{
"note": "Update wrappers",
"pr": 237
},
{
"note": "Update IZeroExContract wrapper",
"pr": 244
}
]
},
{ {
"timestamp": 1621944788, "timestamp": 1621944788,
"version": "13.16.3", "version": "13.16.3",

Some files were not shown because too many files have changed in this diff Show More