Reorder Fill event args to get around stack limit
This commit is contained in:
committed by
Alex Towle
parent
2c970a0466
commit
5ee7c2f9dc
@@ -278,128 +278,23 @@ contract MixinExchangeCore is
|
||||
// Update state
|
||||
filled[orderHash] = orderTakerAssetFilledAmount.safeAdd(fillResults.takerAssetFilledAmount);
|
||||
|
||||
// Emit a Fill() event THE HARD WAY to avoid a stack overflow.
|
||||
// All this logic is equivalent to:
|
||||
// emit Fill(
|
||||
// order.makerAddress,
|
||||
// order.feeRecipientAddress,
|
||||
// orderHash,
|
||||
// takerAddress,
|
||||
// msg.sender,
|
||||
// fillResults.makerAssetFilledAmount,
|
||||
// fillResults.takerAssetFilledAmount,
|
||||
// fillResults.makerFeePaid,
|
||||
// fillResults.takerFeePaid,
|
||||
// fillResults.protocolFeePaid,
|
||||
// msg.value >= fillResults.protocolFeePaid,
|
||||
// order.makerAssetData,
|
||||
// order.takerAssetData,
|
||||
// order.makerFeeAssetData,
|
||||
// order.takerFeeAssetData
|
||||
// );
|
||||
|
||||
// There are 15 total fields in the `Fill()` event. Out of all of these fields,
|
||||
// 3 are indexed fields. Due to the evm semantics of event logging, the 12 non-indexed
|
||||
// fields will be abi-encoded into a bytes structure and then put into the `data` slot
|
||||
// of the event logs.
|
||||
//
|
||||
// Since there are 12 fields, we will need 12 * 32 = 384 bytes to store the fields. Due
|
||||
// to the fact that 4 of the fields are of type `bytes`, there is added complexity in that
|
||||
// these fields in the log data are actually byte offsets to the length-prefaced `bytes`
|
||||
// of the field. This means that we also need to account for 4 length slots -- 4 * 32 = 128
|
||||
// more bytes in the log data -- and for the length of the bytes themselves -- total_length =
|
||||
// order.makerAssetData.length + order.takerAssetData.length + order.makerFeeAssetData.length
|
||||
// + order.takerFeeAssetData.length.
|
||||
//
|
||||
// Altogether, the log data will be 384 + 128 + total_length = 512 + total_length bytes long,
|
||||
// which explains the memory allocation of the bytes below:
|
||||
bytes memory logData = new bytes(
|
||||
512
|
||||
+ order.makerAssetData.length
|
||||
+ order.takerAssetData.length
|
||||
+ order.makerFeeAssetData.length
|
||||
+ order.takerFeeAssetData.length
|
||||
emit Fill(
|
||||
order.makerAddress,
|
||||
order.feeRecipientAddress,
|
||||
order.makerAssetData,
|
||||
order.takerAssetData,
|
||||
order.makerFeeAssetData,
|
||||
order.takerFeeAssetData,
|
||||
orderHash,
|
||||
takerAddress,
|
||||
msg.sender,
|
||||
fillResults.makerAssetFilledAmount,
|
||||
fillResults.takerAssetFilledAmount,
|
||||
fillResults.makerFeePaid,
|
||||
fillResults.takerFeePaid,
|
||||
fillResults.protocolFeePaid,
|
||||
msg.value >= fillResults.protocolFeePaid
|
||||
);
|
||||
|
||||
uint256 argOffset = 0;
|
||||
|
||||
// Push takerAddress to logData
|
||||
logData.writeAddress(argOffset, takerAddress);
|
||||
argOffset += 32;
|
||||
|
||||
// Push senderAddress to logData
|
||||
logData.writeAddress(argOffset, msg.sender);
|
||||
argOffset += 32;
|
||||
|
||||
// Push makerAssetFilledAmount to logData
|
||||
logData.writeUint256(argOffset, fillResults.makerAssetFilledAmount);
|
||||
argOffset += 32;
|
||||
|
||||
// Push takerAssetFilledAmount to logData
|
||||
logData.writeUint256(argOffset, fillResults.takerAssetFilledAmount);
|
||||
argOffset += 32;
|
||||
|
||||
// Push makerFeePaid to logData
|
||||
logData.writeUint256(argOffset, fillResults.makerFeePaid);
|
||||
argOffset += 32;
|
||||
|
||||
// Push takerFeePaid to logData
|
||||
logData.writeUint256(argOffset, fillResults.takerFeePaid);
|
||||
argOffset += 32;
|
||||
|
||||
// Push protocolFeePaid to logData
|
||||
logData.writeUint256(argOffset, fillResults.protocolFeePaid);
|
||||
argOffset += 32;
|
||||
|
||||
// Push isProtocolFeePaidInEth to logData
|
||||
logData.writeUint256(argOffset, msg.value >= fillResults.protocolFeePaid ? 1 : 0);
|
||||
argOffset += 32;
|
||||
|
||||
// The next four fields are `bytes` fields. Constructing the logData for these fields
|
||||
// entails storing a byte offset in their respective memory slots and then storing their
|
||||
// length and contents in the location pointed to by the byte offset.
|
||||
//
|
||||
// With this in mind, the `dataOffset` will initially be set to the thirteenth memory slot
|
||||
// in logData and will be incremented by the length of every assetData `bytes` that is placed
|
||||
// and 32 bytes that reflects the slot that stores the length of the array.
|
||||
uint256 dataOffset = argOffset + 128;
|
||||
|
||||
// Push makerAssetData to logData
|
||||
logData.writeUint256(argOffset, dataOffset);
|
||||
logData.writeBytesWithLength(dataOffset, order.makerAssetData);
|
||||
argOffset += 32;
|
||||
dataOffset += order.makerAssetData.length;
|
||||
|
||||
// Push takerAssetData to logData
|
||||
logData.writeUint256(argOffset, dataOffset);
|
||||
logData.writeBytesWithLength(dataOffset, order.takerAssetData);
|
||||
argOffset += 32;
|
||||
dataOffset += order.takerAssetData.length;
|
||||
|
||||
// Push makerFeeAssetData to logData
|
||||
logData.writeUint256(argOffset, dataOffset);
|
||||
logData.writeBytesWithLength(dataOffset, order.makerFeeAssetData);
|
||||
argOffset += 32;
|
||||
dataOffset += order.makerFeeAssetData.length;
|
||||
|
||||
// Push takerFeeAssetData to logData
|
||||
logData.writeUint256(argOffset, dataOffset);
|
||||
logData.writeBytesWithLength(dataOffset, order.takerFeeAssetData);
|
||||
argOffset += 32;
|
||||
dataOffset += order.takerFeeAssetData.length;
|
||||
|
||||
// Add the event topics and log the event.
|
||||
bytes32 fillTopic = FILL_EVENT_TOPIC;
|
||||
assembly {
|
||||
log4(
|
||||
add(logData, 0x20), // A pointer to the log data
|
||||
mload(logData), // The size of the log data
|
||||
fillTopic, // The `Fill()` event's name topic
|
||||
mload(order), // address indexed makerAddress
|
||||
mload(add(order, 0x40)), // address indexed feeRecipientAddress
|
||||
orderHash // bytes32 indexed orderHash
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Updates state with results of cancelling an order.
|
||||
|
@@ -25,13 +25,14 @@ import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
|
||||
|
||||
contract IExchangeCore {
|
||||
|
||||
// keccak256("Fill(address,address,bytes32,address,address,uint256,uint256,uint256,uint256,uint256,bool,bytes,bytes,bytes,bytes)")
|
||||
bytes32 internal constant FILL_EVENT_TOPIC = 0x266de417a663e51231ccdf89b2794cea06fde5e2c433d76473160b32d31fd867;
|
||||
|
||||
// Fill event is emitted whenever an order is filled.
|
||||
event Fill(
|
||||
address indexed makerAddress, // Address that created the order.
|
||||
address indexed feeRecipientAddress, // Address that received fees.
|
||||
bytes makerAssetData, // Encoded data specific to makerAsset.
|
||||
bytes takerAssetData, // Encoded data specific to takerAsset.
|
||||
bytes makerFeeAssetData, // Encoded data specific to makerFeeAsset.
|
||||
bytes takerFeeAssetData, // Encoded data specific to takerFeeAsset.
|
||||
bytes32 indexed orderHash, // EIP712 hash of order (see LibOrder.getTypedDataHash).
|
||||
address takerAddress, // Address that filled the order.
|
||||
address senderAddress, // Address that called the Exchange contract (msg.sender).
|
||||
@@ -40,11 +41,7 @@ contract IExchangeCore {
|
||||
uint256 makerFeePaid, // Amount of makerFeeAssetData paid to feeRecipient by maker.
|
||||
uint256 takerFeePaid, // Amount of takerFeeAssetData paid to feeRecipient by taker.
|
||||
uint256 protocolFeePaid, // Amount of eth or weth paid to the staking contract.
|
||||
bool isProtocolFeePaidInEth, // Indicates whether the protocol fee is paid in ETH or WETH.
|
||||
bytes makerAssetData, // Encoded data specific to makerAsset.
|
||||
bytes takerAssetData, // Encoded data specific to takerAsset.
|
||||
bytes makerFeeAssetData, // Encoded data specific to makerFeeAsset.
|
||||
bytes takerFeeAssetData // Encoded data specific to takerFeeAsset.
|
||||
bool isProtocolFeePaidInWei // Indicates whether the protocol fee is paid in Wei (ETH) or WETH.
|
||||
);
|
||||
|
||||
// Cancel event is emitted whenever an individual order is cancelled.
|
||||
|
Reference in New Issue
Block a user