-
Notifications
You must be signed in to change notification settings - Fork 466
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.
Good work! Going to have to give this another pass tomorrow.
/// @return status Status of order. Statuses are defined in the LibStatus.Status struct. | ||
/// @return orderHash Keccak-256 EIP712 hash of the order. | ||
/// @return filledAmount Amount of order that has been filled. | ||
function getOrderInfo(Order memory order) | ||
public |
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.
This should probably be internal.
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 originally set it up this way so that it could be used by our tests -- the atomic order matching tests make extensive use of it. Is there any harm in keeping it public
?
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.
^ Could also be used by the forwarding contract. It should probably also be moved into LibOrder
. Then we could use the [ContractName]Test
pattern you used in the Solidity 0.4.23 PR.
returns ( | ||
uint8 orderStatus, | ||
bytes32 orderHash, | ||
uint256 filledAmount) |
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.
Let's rename this takerAssetFilledAmount
for consistency.
{ | ||
// Ensure order status is not invalid | ||
if (orderStatus == uint8(Status.INVALID)) { | ||
emit ExchangeStatus(uint8(orderStatus), orderHash); |
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.
revert
reverts all state, including events, so this patten won't work. Instead, let's just use a require
with a reason.
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'll replace with require(..., [message])
after rebasing against v0.4.23
/// @param takerAssetFillAmount Desired amount of order to fill by taker. | ||
/// @return status Return status of calculating fill amounts. Returns Status.SUCCESS on success. | ||
/// @return fillResults Amounts filled and fees paid by maker and taker. | ||
function calculateFillAmounts( |
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'd rename this to calculateFillResults
.
FillResults memory fillResults) | ||
{ | ||
// Fill Amount must be greater than 0 | ||
if(takerAssetFillAmount <= 0) { |
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.
Missing a space after if
here.
status = uint8(Status.ROUNDING_ERROR_TOO_LARGE); | ||
return (status, matchedFillOrderAmounts); | ||
} | ||
} else { |
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.
There's a lot of duplicate logic in this else block. Can we break this out into another function?
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.
Good call 👍
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.
Updated
Order memory leftOrder, | ||
Order memory rightOrder, | ||
MatchedOrderFillAmounts memory matchedFillOrderAmounts, | ||
address taker) |
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.
takerAddress
bytes rightSignature) | ||
public | ||
returns ( | ||
MatchedOrderFillAmounts memory matchedFillOrderAmounts) |
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.
Can we put this on the same line as returns
?
/// @param rightSignature Proof that order was created by the right maker. | ||
/// @return leftFillResults Amounts filled and fees paid by maker and taker of left order. | ||
/// @return leftFillResults Amounts filled and fees paid by maker and taker of right order. | ||
function matchOrders( |
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.
Nice! This function is very readable/easy to understand.
MatchedOrderFillAmounts memory matchedFillOrderAmounts) | ||
{ | ||
// Get left status | ||
OrderInfo memory leftOrderInfo; |
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 this a struct because of the stack variable limitations?
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.
Yeah =\ ... I left a note on the struct definition.
6d754f8
to
68f6816
Compare
@@ -48,64 +51,108 @@ contract MixinExchangeCore is | |||
// Orders with a salt less than their maker's epoch are considered cancelled | |||
mapping (address => uint256) public makerEpoch; | |||
|
|||
/// @dev Cancels all orders reated by sender with a salt less than or equal to the specified salt value. | |||
/// @param salt Orders created with a salt less or equal to this value will be cancelled. | |||
function cancelOrdersUpTo(uint256 salt) |
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 order for functions within our contracts should be external
, public
, and then internal
. WIthin each visibility section, they should be ordered by how frequently we think they will be used.
/// @return status Status of order. Statuses are defined in the LibStatus.Status struct. | ||
/// @return orderHash Keccak-256 EIP712 hash of the order. | ||
/// @return takerAssetFilledAmount Amount of order that has been filled. | ||
function getOrderInfo(Order memory order) |
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.
Let's make this internal
.
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.
Knowing the amount remaining to be filled is needed in the forwarding contract. Is there an alternative? In the mean time I have been keeping getUnavailable around in my PR.
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.
@dekz - I chatted offline with @abandeali1 about this & we decided to keep it public. Hoping it can be useful in the forwarding contract, for getting amount to fill & order state.
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.
Yep either this or calculateFillResults
would be ideal. If it was calculateFillResults
it requires getOrderInfo
, but would save also save us duplicating this calculation (and and edge cases) in the forwarding contract.
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'd be in favor of making calculateFillResults
public if it can simplify the forwarding contract. @abandeali1 Thoughts?
bytes32 orderHash = getOrderHash(order); | ||
// Compute the order hash and fetch filled amount | ||
orderHash = getOrderHash(order); | ||
takerAssetFilledAmount = filled[orderHash]; |
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.
We should make this check right before we actually need it. For the sake of efficiency, the checks should be ordered:
- makerAssetAmount
- takerAssetAmount
- block.timestamp
- cancelled
- makerEpoch
(For all of the above, takerAssetFilledAmount will be 0) - takerAssetFilledAmount (don't actually check the filled mapping until right before this check)
/// @param takerAddress Address of order taker. | ||
/// @param takerAssetFillAmount Desired amount of order to fill by taker. | ||
function validateFillOrderContextOrRevert( | ||
Order memory order, |
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.
Let's group these params by type.
/// @param signature Proof that the orders was created by its maker. | ||
/// @param takerAddress Address of order taker. | ||
/// @param takerAssetFillAmount Desired amount of order to fill by taker. | ||
function validateFillOrderContextOrRevert( |
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 this name is a little confusing. Maybe just validateFillOrRevert
?
rightOrderFilledAmount, | ||
rightOrderAmountToFill); | ||
if (status != uint8(Status.SUCCESS)) { | ||
return (status, matchedFillResults); |
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.
Hmm, if the left status is successful but the right is not, matchedFillResults
will be inaccurate here.
) = getOrderInfo(rightOrder); | ||
if (rightOrderInfo.orderStatus != uint8(Status.ORDER_FILLABLE)) { | ||
emit ExchangeStatus(uint8(rightOrderInfo.orderStatus), rightOrderInfo.orderHash); | ||
return matchedFillResults; |
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.
Same comment as above - matchedFillResults
can be inaccurate here.
// Update exchange state | ||
updateFilledState( | ||
leftOrder, | ||
rightOrder.makerAddress, |
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.
We should just use takerAddress
for both updateFilledState
calls.
|
||
// leftOrder.MakerAsset == rightOrder.TakerAsset | ||
// Taker should be left with a positive balance (the spread) | ||
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.
Currently, transfers look like:
leftMaker => taker
taker => rightMaker
rightMaker => leftMaker
The spread is always coming from the leftMaker.
However, we never want the taker to actually take custody of the tokens (other than the spread). So what would be more desirable would be:
leftMaker => rightMaker
rightMaker => leftMaker
leftMaker => taker
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 agree, this feels cleaner 👍
returns ( | ||
uint8 orderStatus, | ||
bytes32 orderHash, | ||
uint256 takerAssetFilledAmount); |
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.
Ending parenthesis should be on a newline when we have multiple line returns.
d8e0153
to
aca55fb
Compare
MixinTransactions() | ||
MixinAssetProxyDispatcher() | ||
MixinWrapperFunctions() |
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.
Can we perhaps order these alphabetically?
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.
So there actually is (now) a method to this ordering: contracts are instantiated in the order they are inherited. This makes it easy to update by simply copying the inheritance list to the constructor list. It also makes it easy to verify that all constructors are being called.
I've added a comment above the constructor to clarify this.
(also worth noting that the inheritance list must be ordered by least-to-most derived)
if (cancelled[orderHash]) { | ||
emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash); | ||
// Either our context is valid or we revert | ||
validateFillOrRevert( |
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.
This method is analogous to an assertion, do we want to rename it to assertValidFill?
order.takerAssetAmount, | ||
order.makerAssetAmount)) | ||
{ | ||
status = uint8(Status.ROUNDING_ERROR_TOO_LARGE); |
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.
Or perhaps don't set it to fillResults.takerAssetFilledAmount
until before returning below?
/// Throws if order is invalid or sender does not have permission to cancel. | ||
/// @param order Order to cancel. Order must be Status.FILLABLE. | ||
/// @return True if the order state changed to cancelled. | ||
/// False if the order was order was in a valid, but |
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.
Wording: if the order was order was
(orderStatus, orderHash, ) = getOrderInfo(order); | ||
|
||
// Validate context | ||
validateCancelOrRevert(order, orderStatus, orderHash); |
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.
assertValidCancel
matchedFillResults.right | ||
); | ||
|
||
// Return results |
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.
Think we can remove this comment.
@@ -225,6 +225,30 @@ export class ExchangeWrapper { | |||
const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex)); | |||
return filledAmount; | |||
} | |||
public async getOrderInfoAsync( | |||
signedOrder: SignedOrder, | |||
): Promise<[number /* orderStatus */, string /* orderHash */, BigNumber /* orderTakerAssetAmountFilled */]> { |
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 these comments show up in-line in text editors? If not, why don't we marshal the array into an object with named parameters? I don't think keeping the exact same interface as the contract is important here.
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.
Commented above about this contract function returning an OrderInfo struct, if it did it would also be typed in the generated contract wrappers and would bubble up here.
private static _calculateExpectedBalances( | ||
signedOrderLeft: SignedOrder, | ||
signedOrderRight: SignedOrder, | ||
feeTokenAddress: string, |
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.
Can't the feeTokenAddress
to retrieved from the SignedOrder
?
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.
Negative; the fee token address is not currently included the order struct.
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.
Ah yep, you're right. Isn't it always ZRX address? Why not hard-code it?
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.
Actually yeah that's a good point, we could just pass it into the constructor once rather than to each call. (Updated!)
expect(expectedBalancesMatchRealBalances).to.be.true(); | ||
return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; | ||
} | ||
|
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.
Nit: Omit newline
signedOrderLeft: SignedOrder, | ||
signedOrderRight: SignedOrder, | ||
expectedLeftOrderFillAmoutBeforeMatch: BigNumber, | ||
expectedRightOrderFillAmoutBeforeMatch: BigNumber, |
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.
Not sure I fully understand this variable name. So it's the expected fill amount but before the match?
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.
Yeah that is a confusing name... I've updated to simply orderFilledAmountLeft
and orderFilledAmountRight
. These seem more sensible and align with the naming scheme in the smart contracts.
/// @dev Fills the input order. | ||
/// @param order Order struct containing order specifications. | ||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell. | ||
/// @param takerAssetFillAmount Desired amount of takerToken to sell. |
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.
This should be takerAsset, maybe from the older PR?
Order memory order, | ||
address takerAddress, | ||
bytes32 orderHash, | ||
uint256 takerAssetFilledAmount, |
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 this naming confused me a bit, though the above comment does help.
How about orderFilledAmount to differentiate fillResults.takerAssetFilledAmount, that seems to match OrderInfo.
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.
Hmm yeah that is confusing. I've updated the wording here and elsewhere for consistency.
|
||
// Validate the order | ||
// Ensure order is valid | ||
// An order can only be cancelled if it is Status.FILLABLE; |
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.
We don't check balances in the contract so it should still be FILLABLE
even if the funds were moved.
For context @hysz in 0x.js we often determine the state based off two or more inputs, state(order,maker,taker
). So we do get the scenario where the order is fillable, but the maker/taker make it unfillable due to insufficient funds.
/// @return status Status of order. Statuses are defined in the LibStatus.Status struct. | ||
/// @return orderHash Keccak-256 EIP712 hash of the order. | ||
/// @return takerAssetFilledAmount Amount of order that has been filled. | ||
function getOrderInfo(Order memory order) |
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.
Yep either this or calculateFillResults
would be ideal. If it was calculateFillResults
it requires getOrderInfo
, but would save also save us duplicating this calculation (and and edge cases) in the forwarding contract.
bytes leftSignature, | ||
bytes rightSignature | ||
) | ||
public |
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 this can be external
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.
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.
ohh mannnnn
LibOrder.Order memory leftOrder, | ||
LibOrder.Order memory rightOrder, | ||
LibFillResults.MatchedFillResults memory matchedFillResults, | ||
address takerAddress |
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.
Can we refactor this to have a similar parameter order to settleOrder, so takerAddress before fillResults?
encodeERC20ProxyData(tokenAddress: string): string { | ||
const encodedAssetProxyId = assetProxyUtils.encodeAssetProxyId(AssetProxyId.ERC20); | ||
const encodedAddress = assetProxyUtils.encodeAddress(tokenAddress); | ||
const encodedMetadata = Buffer.concat([encodedAssetProxyId, encodedAddress]); | ||
const encodedMetadataHex = ethUtil.bufferToHex(encodedMetadata); | ||
return encodedMetadataHex; | ||
}, | ||
decodeERC20ProxyData(proxyData: string): string /* tokenAddress */ { |
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 would like if this had a type which includes the asset proxy Id. And also include a decodeProxyData
which returns id, token address (optional) and data (optional). Forwarding wrapper currently switches on the asset id and has to pull 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've updated decodeERC20ProxyData
& decodeERC721ProxyData
accordingly. Also see the newly created function decodeProxyData
, which uses the generalized form you requested.
function getOrderInfo(LibOrder.Order memory order) | ||
public | ||
view | ||
returns ( |
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 a reason this doesn't return an OrderInfo struct?
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.
That's a good idea. This struct was originally created as a workaround for the stack limit. But yeah, it totally makes sense to just return it rather than reinterpret the output.
@@ -225,6 +225,30 @@ export class ExchangeWrapper { | |||
const filledAmount = new BigNumber(await this._exchange.filled.callAsync(orderHashHex)); | |||
return filledAmount; | |||
} | |||
public async getOrderInfoAsync( | |||
signedOrder: SignedOrder, | |||
): Promise<[number /* orderStatus */, string /* orderHash */, BigNumber /* orderTakerAssetAmountFilled */]> { |
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.
Commented above about this contract function returning an OrderInfo struct, if it did it would also be typed in the generated contract wrappers and would bubble up here.
{ from }, | ||
); | ||
const tx = await this._getTxWithDecodedExchangeLogsAsync(txHash); | ||
tx.logs = _.filter(tx.logs, log => log.address === this._exchange.address); |
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.
this isn't needed as it is performed in _getTxWithDecodedExchangeLogsAsync
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.
Couple small changes, but this looks soooo clean overall.
if (cancelled[orderHash]) { | ||
emit ExchangeError(uint8(Errors.ORDER_CANCELLED), orderHash); | ||
// Compute proportional fill amounts | ||
uint8 status; |
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.
In 0.4.24, we can do (uint8 status, fillResult) = ...
Might just be worth updating to the newest version so that we don't have to adjust the styling again later.
takerAssetFillAmount | ||
); | ||
if (status != uint8(Status.SUCCESS)) { | ||
emit ExchangeStatus(uint8(status), orderInfo.orderHash); | ||
return fillResults; |
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.
Idea I just thought of - in order to be explicit here, maybe it's worth returning a null fillResults struct.
Would need something like this (until Solidity adds support for constant structs):
function getNullFillResults() internal returns (FillResults memory) {
// returns zeroed out FillResults instance
return FillResults({
...
});
}
internal | ||
returns (bool stateUpdated) | ||
{ | ||
// Ensure order is fillable (otherwise cancelling does nothing) |
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.
Couple reasons why we have this:
- Cheaper to not update state for an invalid cancel.
- Could see external contracts using the filled/cancelled mappings as on-chain proofs down the line, and having fake cancels could potentially complicate that.
Don't think it's really a big deal either way, but I'm in favor of leaving it in since it is a bit more efficient.
); | ||
|
||
// Compute proportional fill amounts | ||
uint8 status; |
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.
In Solidity 0.4.24, we can write (uint8 status, fillResults) = ...
Might as well upgrade so we don't have to change this later.
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 like this only works if we are declaring all variables simultaneously in the tuple.
|
||
// Fetch filled amount and validate order availability | ||
orderInfo.orderFilledAmount = filled[orderInfo.orderHash]; | ||
if (orderInfo.orderFilledAmount >= order.takerAssetAmount) { |
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 ever a case where orderInfo.orderFilledAmount > order.takerAssetAmount?
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.
In theory there should not be. But in practice there could be a rounding error amount.
|
||
/// @dev Validates matched fill results. Succeeds or throws. | ||
/// @param matchedFillResults Amounts to fill and fees to pay by maker and taker of matched orders. | ||
function assertValidMatch(MatchedFillResults memory matchedFillResults) |
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'd prefer not to overload this function. How about assertValidMatchOrders
and assertValidMatchResults
?
} | ||
|
||
// Calculate fill results for left order | ||
uint8 status; |
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.
Combine these lines with Solidity 0.4.24
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 like this only works if we are declaring all variables simultaneously in the tuple.
matchedFillResults.right.takerAssetFilledAmount, | ||
matchedFillResults.takerFillAmount | ||
); | ||
require( |
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.
What miscalculation needs to happen in order for this to evaluate to false? Is this something we expect to ever hit, or are we just being extra safe?
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 we expect this to sometimes be hit, we should add tests for that scenario.
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.
Just a sanity check. And it's actually covered by the subsequent rounding error test. I'll remove this.
function matchOrders( | ||
LibOrder.Order memory leftOrder, | ||
LibOrder.Order memory rightOrder, | ||
bytes leftSignature, |
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.
bytes memory
again
// Keccak-256 EIP712 hash of the order | ||
bytes32 orderHash; | ||
// Amount of order that has been filled | ||
uint256 orderFilledAmount; |
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 know it's verbose, but I prefer orderTakerAssetFilledAmount
here.
0aa81e4
to
cc16e2c
Compare
…ty check to order matching calculations
…ws pattern of fillOrder more closely.
…ults. I like this better than just logging an error and failing silently.
…stinguish between fill results and order state
…change inherits Mixins)
…, which should be useful for the forwarding contract code.
…nstant, we dont need to pass it in on each call.
…sed by the Forwarding Contract.
8b4565a
to
f4ebbfa
Compare
function assertValidCancel( | ||
Order memory order, | ||
uint8 orderStatus, | ||
bytes32 orderHash |
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.
assertValidFill takes in the taker address, thoughts on passing it via parameters for consistency in assertValidCancel
?
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.
That would be cleaner. It would also make the function pure. assertValidFill
is also pure, except for calling isValidSignature
.
…ppear to be used (it was from an old PR I merged in).
Description
Atomic Order Matching - Work in Progress.
Match two complementary orders that have a positive spread. Each order is filled at their respective price point. However, the calculations are carried out as though the orders are both being filled at the right order's price point. The profit made by the left order goes to the taker (who matched the two orders).
This PR is based on two earlier PR's by Remco:
In this PR:
Todo:
Motivation and Context
The exchange core functions were getting really long. It was good to refactor/split these up. The refactor was also necessary to write a clean implementation of order matching, since there's a lot of overlap between functions.
Atomic order matching is useful for arbitrage and exchanges that take profit from the spread.
How Has This Been Tested?
Test cases were created for new functionality. We did not change any existing functionality. Tests still pass.
Types of changes
Checklist: