-
Notifications
You must be signed in to change notification settings - Fork 465
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lot's of work, nicely done! Left a few minor comments.
it(description, async () => { | ||
// Create orders to match. For ERC20s, there will be a spread. | ||
const leftMakerAssetAmount = combo.leftMaker.startsWith('ERC20') | ||
? Web3Wrapper.toBaseUnitAmount(15, 18) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there anything special about these values or were they just picked at random?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The values were taken from the existing ERC20 tests. I was wondering this too.
…FungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.
…nd `ERC1155NonFungible` combinatorial tests.
`@0x/contracts-echange`: Set up 1155 and MAP proxies for `matchOrders()` tests.
…o speed up tests.
…sts into the `fillOrder` and `matchOrders` test suites.
…1155 tokens to 2 to fix broken `asset-proxy` tests.
…en maker/taker is the same as feeRecipient and the assets match. `@0x/contracts-exchange`: Swap fill order in `fillOrder()` from maker -> taker to taker -> maker first
… when maker/feeRecipient and takerAssetData/makerFeeAssetData are the same. `@0x/conracts-exchange`: Disable combinatorial tests by default. Can be run by setting env var `TEST_ALL=1`.
Round 2!For convenience, here is the diff against the original PR. Summary
* fillOrder() combinatorial tests are disabled by default.Adding new asset fields and asset types exponentially increased the number of combinatorial tests in You can enable them by setting the environment variable |
I've been toying with the idea of using an embedded EVM implementation (i.e. one written in TypeScript/JavaScript) for combinatorial tests to drastically improve performance. @xianny I know you've been working with |
…atorial_utils.ts`.
// | 448 + C1 + C2 + C3 | C4 | takerFeeAssetData contents | | ||
// |-------------------------------------------------------------------| | ||
// | Total Length: 448 + C1 + C2 + C3 | | ||
bytes memory logData = new bytes( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a sense of the gas overhead created by manually constructing the event payload?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will check, but we don't really have an alternative aside from pure assembly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It costs 4.8% more gas to emit the hard way. Let's add it to the backlog if we want to further optimize it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the alternative would be cutting fields from the event... there aren't any obvious choices though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hysz Figured out that if you rearranged the Fill
event args, you can fit an emit
on the stack!
) { | ||
// Maker is fee recipient and the maker fee asset is the same as the taker asset. | ||
// We can transfer the taker asset and maker fees in one go. | ||
_dispatchTransferFrom( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm reading this line correctly, the Right Maker is paying their fee to the Left Fee Recipient. But it should go to the Right Fee Recipient.
This is the intended logic:
left.makerFeePaid → paid by Left Maker to Left Fee Recipient
left.takerFeePaid → paid by Taker to to Left Fee Recipient
right.makerFeePaid → paid by Right Maker to Right Fee Recipient
right.takerFeePaid → paid by Taker to Right Fee Recipient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, that is exactly what it's doing. I admit I have to work this out in my head every time I see it, but I think this behavior is correct.
We are basically collapsing the two transfers in the following else
clause because the the leftMaker == leftFeeRecipient
and the leftMakerFeeAssetData == leftTakerAssetData
. So rightMaker
can just pay the combined leftTakerAsset
and leftMakerFee
to leftMaker
/leftFeeRecipient
since it's all the same asset going to the same place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spoke with @hysz and he pointed out there were some other fundamental errors in this settlement optimization (for one, takers were actually paying more than their fair share). This affected both matchOrders()
and fillOrders()
. The combinatorial tests also weren't covering these scenarios so they slipped under the radar. Totes my bad!
I just now updated things so the only optimizations we do now are avoiding maker fee transfers if maker == feeRecipient
and taker fee transfers if taker == feeRecipient
. There are now also explicit tests to cover all these (and the previous) scenarios.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combinatorial tests now take even longer though. 😫
I am definitely adding these to demo sprint (woops, already did).
`@0x/contracts-exchange`: Minor code change to save an mload.
…tchOrders()` redundant transfer optimization code. `@0x/contracts-exchange`: Rearrange `Fill` event params to make regular `emit` code work without breaking the stack. `@0x/contracts-exchange`: Add edge case tests for redundant transfer optimizations.
…settlement optimizations in the Exchange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks solid, let's merge!
Goodbye, ZRX fees!
Who knew so much of our code relied on ZRX fees being baked in?
This PR implements ZEIP-28, which does away with ZRX fees and instead allows for arbitrary maker and taker fee tokens.
The Highlights
Order
type now has two new fields:makerFeeAssetData
andtakerFeeAssetData
.fillOrder()
andmatchOrders()
.Bonus Material
fillOrder()
has been change to taker -> maker first, instead of maker -> taker first. This is necessary for something like ZEIP-38.fillOrder()
andmatchOrders()
tests.base-contract
andabi-gen-templates
so that anyError
s thrown by acallAsync()
andsendTransactionAsync()
(ganache only) will be automatically decoded into aRevertError
, if possible. This means you no longer just see an opaqueVM exception: revert
when contract calls unexpectedly explode.fill_order_combinatorial_utils
andmatch_order_tester
) because they weren't robust enough to handle all the edge cases for arbitrary fees, as well as the upcoming changes tomatchOrders()
fee splitting.exchange-libs
to automatically generateLibExchangeSelectors.sol
because updating that by hand is a bunch of nopes. Just runyarn generate-exchange-selectors
from the package directory.Web3Wrapper.toBaseUnitAmount()
can now accept anumber
in addition to aBigNumber
, which makes a couple tests a lot more compact.Issues/Caveats
Fill
event grew by two new parameters, which was just enough to break the stack foremit
, so I had to resort to an ugly, low-level solution.extensions
andexchange-forwarder
packages have been disabled (hence why code coverage plummeted) from the pipeline. Those packages will probably need major rework beyond the scope of this PR.fillOrder()
combinatorial tests fromOrderStateUtils
andOrderValidationUtils
. The states that were being tested didn't really warrant them because the combinatorial tests do not generate consecutive fills. We were actually missing out on testing some reverting states becauseOrderValidationUtils
was preventing us from using fill amounts that would fail.Testing Instructions
You can find the most relevant tests in:
fill_order.ts
match_orders.ts
Types of changes
Breaking change (fix or feature that would cause existing functionality to change)
Checklist:
[WIP]
if necessary.