Created LibAbiEncoder with fillOrderNoThrow
This commit is contained in:
parent
7fadba59e7
commit
5790ed7ba9
@ -22,12 +22,14 @@ pragma experimental ABIEncoderV2;
|
|||||||
import "./libs/LibMath.sol";
|
import "./libs/LibMath.sol";
|
||||||
import "./libs/LibOrder.sol";
|
import "./libs/LibOrder.sol";
|
||||||
import "./libs/LibFillResults.sol";
|
import "./libs/LibFillResults.sol";
|
||||||
|
import "./libs/LibAbiEncoder.sol";
|
||||||
import "./mixins/MExchangeCore.sol";
|
import "./mixins/MExchangeCore.sol";
|
||||||
|
|
||||||
|
|
||||||
contract MixinWrapperFunctions is
|
contract MixinWrapperFunctions is
|
||||||
LibMath,
|
LibMath,
|
||||||
LibFillResults,
|
LibFillResults,
|
||||||
|
LibAbiEncoder,
|
||||||
MExchangeCore
|
MExchangeCore
|
||||||
{
|
{
|
||||||
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
|
||||||
@ -68,177 +70,25 @@ contract MixinWrapperFunctions is
|
|||||||
public
|
public
|
||||||
returns (FillResults memory fillResults)
|
returns (FillResults memory fillResults)
|
||||||
{
|
{
|
||||||
// We need to call MExchangeCore.fillOrder using a delegatecall in
|
// ABI encode calldata for `fillOrder`
|
||||||
// assembly so that we can intercept a call that throws. For this, we
|
(
|
||||||
// need the input encoded in memory in the Ethereum ABIv2 format [1].
|
uint256 calldataBegin,
|
||||||
|
uint256 calldataLength
|
||||||
// | Area | Offset | Length | Contents |
|
) = abiEncodeFillOrder(
|
||||||
// | -------- |--------|---------|-------------------------------------------- |
|
order,
|
||||||
// | Header | 0x00 | 4 | function selector |
|
takerAssetFillAmount,
|
||||||
// | Params | | 3 * 32 | function parameters: |
|
signature,
|
||||||
// | | 0x00 | | 1. offset to order (*) |
|
this.fillOrder.selector
|
||||||
// | | 0x20 | | 2. takerAssetFillAmount |
|
);
|
||||||
// | | 0x40 | | 3. offset to signature (*) |
|
|
||||||
// | Data | | 12 * 32 | order: |
|
|
||||||
// | | 0x000 | | 1. senderAddress |
|
|
||||||
// | | 0x020 | | 2. makerAddress |
|
|
||||||
// | | 0x040 | | 3. takerAddress |
|
|
||||||
// | | 0x060 | | 4. feeRecipientAddress |
|
|
||||||
// | | 0x080 | | 5. makerAssetAmount |
|
|
||||||
// | | 0x0A0 | | 6. takerAssetAmount |
|
|
||||||
// | | 0x0C0 | | 7. makerFeeAmount |
|
|
||||||
// | | 0x0E0 | | 8. takerFeeAmount |
|
|
||||||
// | | 0x100 | | 9. expirationTimeSeconds |
|
|
||||||
// | | 0x120 | | 10. salt |
|
|
||||||
// | | 0x140 | | 11. Offset to makerAssetData (*) |
|
|
||||||
// | | 0x160 | | 12. Offset to takerAssetData (*) |
|
|
||||||
// | | 0x180 | 32 | makerAssetData Length |
|
|
||||||
// | | 0x1A0 | ** | makerAssetData Contents |
|
|
||||||
// | | 0x1C0 | 32 | takerAssetData Length |
|
|
||||||
// | | 0x1E0 | ** | takerAssetData Contents |
|
|
||||||
// | | 0x200 | 32 | signature Length |
|
|
||||||
// | | 0x220 | ** | signature Contents |
|
|
||||||
|
|
||||||
// * Offsets are calculated from the beginning of the current area: Header, Params, Data:
|
|
||||||
// An offset stored in the Params area is calculated from the beginning of the Params section.
|
|
||||||
// An offset stored in the Data area is calculated from the beginning of the Data section.
|
|
||||||
|
|
||||||
// ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
|
|
||||||
|
|
||||||
// [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
|
|
||||||
|
|
||||||
bytes4 fillOrderSelector = this.fillOrder.selector;
|
|
||||||
|
|
||||||
|
// Delegate to `fillOrder` and handle any exceptions gracefully
|
||||||
assembly {
|
assembly {
|
||||||
|
|
||||||
// Areas below may use the following variables:
|
|
||||||
// 1. <area>Start -- Start of this area in memory
|
|
||||||
// 2. <area>End -- End of this area in memory. This value may
|
|
||||||
// be precomputed (before writing contents),
|
|
||||||
// or it may be computed as contents are written.
|
|
||||||
// 3. <area>Offset -- Current offset into area. If an area's End
|
|
||||||
// is precomputed, this variable tracks the
|
|
||||||
// offsets of contents as they are written.
|
|
||||||
|
|
||||||
/////// Setup Header Area ///////
|
|
||||||
// Load free memory pointer
|
|
||||||
let headerAreaStart := mload(0x40)
|
|
||||||
mstore(headerAreaStart, fillOrderSelector)
|
|
||||||
let headerAreaEnd := add(headerAreaStart, 0x4)
|
|
||||||
|
|
||||||
/////// Setup Params Area ///////
|
|
||||||
// This area is preallocated and written to later.
|
|
||||||
// This is because we need to fill in offsets that have not yet been calculated.
|
|
||||||
let paramsAreaStart := headerAreaEnd
|
|
||||||
let paramsAreaEnd := add(paramsAreaStart, 0x60)
|
|
||||||
let paramsAreaOffset := paramsAreaStart
|
|
||||||
|
|
||||||
/////// Setup Data Area ///////
|
|
||||||
let dataAreaStart := paramsAreaEnd
|
|
||||||
let dataAreaEnd := dataAreaStart
|
|
||||||
|
|
||||||
// Offset from the source data we're reading from
|
|
||||||
let sourceOffset := order
|
|
||||||
// arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
|
|
||||||
let arrayLenBytes := 0
|
|
||||||
let arrayLenWords := 0
|
|
||||||
|
|
||||||
/////// Write order Struct ///////
|
|
||||||
// Write memory location of Order, relative to the start of the
|
|
||||||
// parameter list, then increment the paramsAreaOffset respectively.
|
|
||||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
|
||||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
|
||||||
|
|
||||||
// Write values for each field in the order
|
|
||||||
// It would be nice to use a loop, but we save on gas by writing
|
|
||||||
// the stores sequentially.
|
|
||||||
mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
|
|
||||||
mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
|
|
||||||
mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
|
|
||||||
mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
|
|
||||||
mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
|
|
||||||
mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
|
|
||||||
mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
|
|
||||||
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
|
|
||||||
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
|
|
||||||
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
|
|
||||||
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
|
|
||||||
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x180)
|
|
||||||
sourceOffset := add(sourceOffset, 0x180)
|
|
||||||
|
|
||||||
// Write offset to <order.makerAssetData>
|
|
||||||
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
|
||||||
|
|
||||||
// Calculate length of <order.makerAssetData>
|
|
||||||
sourceOffset := mload(add(order, 0x140)) // makerAssetData
|
|
||||||
arrayLenBytes := mload(sourceOffset)
|
|
||||||
sourceOffset := add(sourceOffset, 0x20)
|
|
||||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
|
||||||
|
|
||||||
// Write length of <order.makerAssetData>
|
|
||||||
mstore(dataAreaEnd, arrayLenBytes)
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
|
||||||
|
|
||||||
// Write contents of <order.makerAssetData>
|
|
||||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
|
||||||
mstore(dataAreaEnd, mload(sourceOffset))
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
|
||||||
sourceOffset := add(sourceOffset, 0x20)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write offset to <order.takerAssetData>
|
|
||||||
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
|
||||||
|
|
||||||
// Calculate length of <order.takerAssetData>
|
|
||||||
sourceOffset := mload(add(order, 0x160)) // takerAssetData
|
|
||||||
arrayLenBytes := mload(sourceOffset)
|
|
||||||
sourceOffset := add(sourceOffset, 0x20)
|
|
||||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
|
||||||
|
|
||||||
// Write length of <order.takerAssetData>
|
|
||||||
mstore(dataAreaEnd, arrayLenBytes)
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
|
||||||
|
|
||||||
// Write contents of <order.takerAssetData>
|
|
||||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
|
||||||
mstore(dataAreaEnd, mload(sourceOffset))
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
|
||||||
sourceOffset := add(sourceOffset, 0x20)
|
|
||||||
}
|
|
||||||
|
|
||||||
/////// Write takerAssetFillAmount ///////
|
|
||||||
mstore(paramsAreaOffset, takerAssetFillAmount)
|
|
||||||
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
|
||||||
|
|
||||||
/////// Write signature ///////
|
|
||||||
// Write offset to paramsArea
|
|
||||||
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
|
||||||
|
|
||||||
// Calculate length of signature
|
|
||||||
sourceOffset := signature
|
|
||||||
arrayLenBytes := mload(sourceOffset)
|
|
||||||
sourceOffset := add(sourceOffset, 0x20)
|
|
||||||
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
|
||||||
|
|
||||||
// Write length of signature
|
|
||||||
mstore(dataAreaEnd, arrayLenBytes)
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
|
||||||
|
|
||||||
// Write contents of signature
|
|
||||||
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
|
||||||
mstore(dataAreaEnd, mload(sourceOffset))
|
|
||||||
dataAreaEnd := add(dataAreaEnd, 0x20)
|
|
||||||
sourceOffset := add(sourceOffset, 0x20)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute delegatecall
|
|
||||||
let success := delegatecall(
|
let success := delegatecall(
|
||||||
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
gas, // forward all gas, TODO: look into gas consumption of assert/throw
|
||||||
address, // call address of this contract
|
address, // call address of this contract
|
||||||
headerAreaStart, // pointer to start of input
|
calldataBegin, // pointer to start of input
|
||||||
sub(dataAreaEnd, headerAreaStart), // length of input
|
calldataLength, // length of input
|
||||||
headerAreaStart, // write output over input
|
calldataBegin, // write output over input
|
||||||
128 // output size is 128 bytes
|
128 // output size is 128 bytes
|
||||||
)
|
)
|
||||||
switch success
|
switch success
|
||||||
@ -249,10 +99,10 @@ contract MixinWrapperFunctions is
|
|||||||
mstore(add(fillResults, 96), 0)
|
mstore(add(fillResults, 96), 0)
|
||||||
}
|
}
|
||||||
case 1 {
|
case 1 {
|
||||||
mstore(fillResults, mload(headerAreaStart))
|
mstore(fillResults, mload(calldataBegin))
|
||||||
mstore(add(fillResults, 32), mload(add(headerAreaStart, 32)))
|
mstore(add(fillResults, 32), mload(add(calldataBegin, 32)))
|
||||||
mstore(add(fillResults, 64), mload(add(headerAreaStart, 64)))
|
mstore(add(fillResults, 64), mload(add(calldataBegin, 64)))
|
||||||
mstore(add(fillResults, 96), mload(add(headerAreaStart, 96)))
|
mstore(add(fillResults, 96), mload(add(calldataBegin, 96)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fillResults;
|
return fillResults;
|
||||||
|
215
packages/contracts/src/2.0.0/protocol/Exchange/libs/LibAbiEncoder.sol
vendored
Normal file
215
packages/contracts/src/2.0.0/protocol/Exchange/libs/LibAbiEncoder.sol
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2018 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.4.24;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import "./LibOrder.sol";
|
||||||
|
|
||||||
|
|
||||||
|
contract LibAbiEncoder {
|
||||||
|
|
||||||
|
/// @dev ABI encodes calldata for `fillOrder` in memory and returns the address range.
|
||||||
|
/// This range can be passed into `call` or `delegatecall` to invoke an external
|
||||||
|
/// call to `fillOrder`.
|
||||||
|
/// @param order Order struct containing order specifications.
|
||||||
|
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||||
|
/// @param signature Proof that order has been created by maker.
|
||||||
|
/// @return calldataBegin Memory address of ABI encoded calldata.
|
||||||
|
/// @return calldataLength Lenfgth of ABI encoded calldata.
|
||||||
|
function abiEncodeFillOrder(
|
||||||
|
LibOrder.Order memory order,
|
||||||
|
uint256 takerAssetFillAmount,
|
||||||
|
bytes memory signature,
|
||||||
|
bytes4 fillOrderSelector
|
||||||
|
)
|
||||||
|
public
|
||||||
|
returns (
|
||||||
|
uint256 calldataBegin,
|
||||||
|
uint256 calldataLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// We need to call MExchangeCore.fillOrder using a delegatecall in
|
||||||
|
// assembly so that we can intercept a call that throws. For this, we
|
||||||
|
// need the input encoded in memory in the Ethereum ABIv2 format [1].
|
||||||
|
|
||||||
|
// | Area | Offset | Length | Contents |
|
||||||
|
// | -------- |--------|---------|-------------------------------------------- |
|
||||||
|
// | Header | 0x00 | 4 | function selector |
|
||||||
|
// | Params | | 3 * 32 | function parameters: |
|
||||||
|
// | | 0x00 | | 1. offset to order (*) |
|
||||||
|
// | | 0x20 | | 2. takerAssetFillAmount |
|
||||||
|
// | | 0x40 | | 3. offset to signature (*) |
|
||||||
|
// | Data | | 12 * 32 | order: |
|
||||||
|
// | | 0x000 | | 1. senderAddress |
|
||||||
|
// | | 0x020 | | 2. makerAddress |
|
||||||
|
// | | 0x040 | | 3. takerAddress |
|
||||||
|
// | | 0x060 | | 4. feeRecipientAddress |
|
||||||
|
// | | 0x080 | | 5. makerAssetAmount |
|
||||||
|
// | | 0x0A0 | | 6. takerAssetAmount |
|
||||||
|
// | | 0x0C0 | | 7. makerFeeAmount |
|
||||||
|
// | | 0x0E0 | | 8. takerFeeAmount |
|
||||||
|
// | | 0x100 | | 9. expirationTimeSeconds |
|
||||||
|
// | | 0x120 | | 10. salt |
|
||||||
|
// | | 0x140 | | 11. Offset to makerAssetData (*) |
|
||||||
|
// | | 0x160 | | 12. Offset to takerAssetData (*) |
|
||||||
|
// | | 0x180 | 32 | makerAssetData Length |
|
||||||
|
// | | 0x1A0 | ** | makerAssetData Contents |
|
||||||
|
// | | 0x1C0 | 32 | takerAssetData Length |
|
||||||
|
// | | 0x1E0 | ** | takerAssetData Contents |
|
||||||
|
// | | 0x200 | 32 | signature Length |
|
||||||
|
// | | 0x220 | ** | signature Contents |
|
||||||
|
|
||||||
|
// * Offsets are calculated from the beginning of the current area: Header, Params, Data:
|
||||||
|
// An offset stored in the Params area is calculated from the beginning of the Params section.
|
||||||
|
// An offset stored in the Data area is calculated from the beginning of the Data section.
|
||||||
|
|
||||||
|
// ** The length of dynamic array contents are stored in the field immediately preceeding the contents.
|
||||||
|
|
||||||
|
// [1]: https://solidity.readthedocs.io/en/develop/abi-spec.html
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
|
||||||
|
// Areas below may use the following variables:
|
||||||
|
// 1. <area>Start -- Start of this area in memory
|
||||||
|
// 2. <area>End -- End of this area in memory. This value may
|
||||||
|
// be precomputed (before writing contents),
|
||||||
|
// or it may be computed as contents are written.
|
||||||
|
// 3. <area>Offset -- Current offset into area. If an area's End
|
||||||
|
// is precomputed, this variable tracks the
|
||||||
|
// offsets of contents as they are written.
|
||||||
|
|
||||||
|
/////// Setup Header Area ///////
|
||||||
|
// Load free memory pointer
|
||||||
|
calldataBegin := mload(0x40)
|
||||||
|
mstore(calldataBegin, fillOrderSelector)
|
||||||
|
let headerAreaEnd := add(calldataBegin, 0x4)
|
||||||
|
|
||||||
|
/////// Setup Params Area ///////
|
||||||
|
// This area is preallocated and written to later.
|
||||||
|
// This is because we need to fill in offsets that have not yet been calculated.
|
||||||
|
let paramsAreaStart := headerAreaEnd
|
||||||
|
let paramsAreaEnd := add(paramsAreaStart, 0x60)
|
||||||
|
let paramsAreaOffset := paramsAreaStart
|
||||||
|
|
||||||
|
/////// Setup Data Area ///////
|
||||||
|
let dataAreaStart := paramsAreaEnd
|
||||||
|
let dataAreaEnd := dataAreaStart
|
||||||
|
|
||||||
|
// Offset from the source data we're reading from
|
||||||
|
let sourceOffset := order
|
||||||
|
// arrayLenBytes and arrayLenWords track the length of a dynamically-allocated bytes array.
|
||||||
|
let arrayLenBytes := 0
|
||||||
|
let arrayLenWords := 0
|
||||||
|
|
||||||
|
/////// Write order Struct ///////
|
||||||
|
// Write memory location of Order, relative to the start of the
|
||||||
|
// parameter list, then increment the paramsAreaOffset respectively.
|
||||||
|
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||||
|
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||||
|
|
||||||
|
// Write values for each field in the order
|
||||||
|
// It would be nice to use a loop, but we save on gas by writing
|
||||||
|
// the stores sequentially.
|
||||||
|
mstore(dataAreaEnd, mload(sourceOffset)) // makerAddress
|
||||||
|
mstore(add(dataAreaEnd, 0x20), mload(add(sourceOffset, 0x20))) // takerAddress
|
||||||
|
mstore(add(dataAreaEnd, 0x40), mload(add(sourceOffset, 0x40))) // feeRecipientAddress
|
||||||
|
mstore(add(dataAreaEnd, 0x60), mload(add(sourceOffset, 0x60))) // senderAddress
|
||||||
|
mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // makerAssetAmount
|
||||||
|
mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // takerAssetAmount
|
||||||
|
mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // makerFeeAmount
|
||||||
|
mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // takerFeeAmount
|
||||||
|
mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // expirationTimeSeconds
|
||||||
|
mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // salt
|
||||||
|
mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to makerAssetData
|
||||||
|
mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetData
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x180)
|
||||||
|
sourceOffset := add(sourceOffset, 0x180)
|
||||||
|
|
||||||
|
// Write offset to <order.makerAssetData>
|
||||||
|
mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||||
|
|
||||||
|
// Calculate length of <order.makerAssetData>
|
||||||
|
sourceOffset := mload(add(order, 0x140)) // makerAssetData
|
||||||
|
arrayLenBytes := mload(sourceOffset)
|
||||||
|
sourceOffset := add(sourceOffset, 0x20)
|
||||||
|
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||||
|
|
||||||
|
// Write length of <order.makerAssetData>
|
||||||
|
mstore(dataAreaEnd, arrayLenBytes)
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||||
|
|
||||||
|
// Write contents of <order.makerAssetData>
|
||||||
|
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||||
|
mstore(dataAreaEnd, mload(sourceOffset))
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||||
|
sourceOffset := add(sourceOffset, 0x20)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write offset to <order.takerAssetData>
|
||||||
|
mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
|
||||||
|
|
||||||
|
// Calculate length of <order.takerAssetData>
|
||||||
|
sourceOffset := mload(add(order, 0x160)) // takerAssetData
|
||||||
|
arrayLenBytes := mload(sourceOffset)
|
||||||
|
sourceOffset := add(sourceOffset, 0x20)
|
||||||
|
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||||
|
|
||||||
|
// Write length of <order.takerAssetData>
|
||||||
|
mstore(dataAreaEnd, arrayLenBytes)
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||||
|
|
||||||
|
// Write contents of <order.takerAssetData>
|
||||||
|
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||||
|
mstore(dataAreaEnd, mload(sourceOffset))
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||||
|
sourceOffset := add(sourceOffset, 0x20)
|
||||||
|
}
|
||||||
|
|
||||||
|
/////// Write takerAssetFillAmount ///////
|
||||||
|
mstore(paramsAreaOffset, takerAssetFillAmount)
|
||||||
|
paramsAreaOffset := add(paramsAreaOffset, 0x20)
|
||||||
|
|
||||||
|
/////// Write signature ///////
|
||||||
|
// Write offset to paramsArea
|
||||||
|
mstore(paramsAreaOffset, sub(dataAreaEnd, paramsAreaStart))
|
||||||
|
|
||||||
|
// Calculate length of signature
|
||||||
|
sourceOffset := signature
|
||||||
|
arrayLenBytes := mload(sourceOffset)
|
||||||
|
sourceOffset := add(sourceOffset, 0x20)
|
||||||
|
arrayLenWords := div(add(arrayLenBytes, 0x1F), 0x20)
|
||||||
|
|
||||||
|
// Write length of signature
|
||||||
|
mstore(dataAreaEnd, arrayLenBytes)
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||||
|
|
||||||
|
// Write contents of signature
|
||||||
|
for {let i := 0} lt(i, arrayLenWords) {i := add(i, 1)} {
|
||||||
|
mstore(dataAreaEnd, mload(sourceOffset))
|
||||||
|
dataAreaEnd := add(dataAreaEnd, 0x20)
|
||||||
|
sourceOffset := add(sourceOffset, 0x20)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set length of calldata
|
||||||
|
calldataLength := sub(dataAreaEnd, calldataBegin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (calldataBegin, calldataLength);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user