aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol5
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/LibOrder.sol3
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/MixinExchangeCore.sol61
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/MixinTransactions.sol85
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol62
-rw-r--r--packages/contracts/src/contracts/current/protocol/Exchange/mixins/MTransactions.sol41
6 files changed, 210 insertions, 47 deletions
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol b/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol
index 5ccb06b88..caf48bfca 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/Exchange.sol
@@ -24,13 +24,15 @@ import "./MixinSignatureValidator.sol";
import "./MixinSettlement.sol";
import "./MixinWrapperFunctions.sol";
import "./MixinAssetProxyDispatcher.sol";
+import "./MixinTransactions.sol";
contract Exchange is
MixinExchangeCore,
MixinSignatureValidator,
MixinSettlement,
MixinWrapperFunctions,
- MixinAssetProxyDispatcher
+ MixinAssetProxyDispatcher,
+ MixinTransactions
{
string constant public VERSION = "2.0.1-alpha";
@@ -42,5 +44,6 @@ contract Exchange is
MixinSettlement(_zrxProxyData)
MixinWrapperFunctions()
MixinAssetProxyDispatcher()
+ MixinTransactions()
{}
}
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/LibOrder.sol b/packages/contracts/src/contracts/current/protocol/Exchange/LibOrder.sol
index 61a4a382d..a98d7cbeb 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/LibOrder.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/LibOrder.sol
@@ -26,6 +26,7 @@ contract LibOrder {
"address makerAddress",
"address takerAddress",
"address feeRecipientAddress",
+ "address senderAddress",
"uint256 makerAssetAmount",
"uint256 takerAssetAmount",
"uint256 makerFee",
@@ -40,6 +41,7 @@ contract LibOrder {
address makerAddress;
address takerAddress;
address feeRecipientAddress;
+ address senderAddress;
uint256 makerAssetAmount;
uint256 takerAssetAmount;
uint256 makerFee;
@@ -66,6 +68,7 @@ contract LibOrder {
order.makerAddress,
order.takerAddress,
order.feeRecipientAddress,
+ order.senderAddress,
order.makerAssetAmount,
order.takerAssetAmount,
order.makerFee,
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinExchangeCore.sol
index 710315515..97c1f1541 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinExchangeCore.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinExchangeCore.sol
@@ -18,10 +18,12 @@
pragma solidity ^0.4.21;
pragma experimental ABIEncoderV2;
+pragma experimental "v0.5.0";
import "./mixins/MExchangeCore.sol";
import "./mixins/MSettlement.sol";
import "./mixins/MSignatureValidator.sol";
+import "./mixins/MTransactions.sol";
import "./LibOrder.sol";
import "./LibErrors.sol";
import "./LibPartialAmount.sol";
@@ -35,6 +37,7 @@ contract MixinExchangeCore is
MExchangeCore,
MSettlement,
MSignatureValidator,
+ MTransactions,
SafeMath,
LibErrors,
LibPartialAmount
@@ -113,10 +116,16 @@ contract MixinExchangeCore is
require(order.takerAssetAmount > 0);
require(isValidSignature(orderHash, order.makerAddress, signature));
}
+
+ // Validate sender
+ if (order.senderAddress != address(0)) {
+ require(order.senderAddress == msg.sender);
+ }
- // Validate taker
+ // Validate transaction signed by taker
+ address takerAddress = getSignerAddress();
if (order.takerAddress != address(0)) {
- require(order.takerAddress == msg.sender);
+ require(order.takerAddress == takerAddress);
}
require(takerAssetFillAmount > 0);
@@ -146,21 +155,10 @@ contract MixinExchangeCore is
// Settle order
(fillResults.makerAssetFilledAmount, fillResults.makerFeePaid, fillResults.takerFeePaid) =
- settleOrder(order, msg.sender, fillResults.takerAssetFilledAmount);
+ settleOrder(order, takerAddress, fillResults.takerAssetFilledAmount);
// Log order
- emit Fill(
- order.makerAddress,
- msg.sender,
- order.feeRecipientAddress,
- fillResults.makerAssetFilledAmount,
- fillResults.takerAssetFilledAmount,
- fillResults.makerFeePaid,
- fillResults.takerFeePaid,
- orderHash,
- order.makerAssetData,
- order.takerAssetData
- );
+ emitFillEvent(order, takerAddress, orderHash, fillResults);
return fillResults;
}
@@ -178,8 +176,16 @@ contract MixinExchangeCore is
// Validate the order
require(order.makerAssetAmount > 0);
require(order.takerAssetAmount > 0);
- require(order.makerAddress == msg.sender);
+ // Validate sender
+ if (order.senderAddress != address(0)) {
+ require(order.senderAddress == msg.sender);
+ }
+
+ // Validate transaction signed by maker
+ address makerAddress = getSignerAddress();
+ require(order.makerAddress == makerAddress);
+
if (block.timestamp >= order.expirationTimeSeconds) {
emit ExchangeError(uint8(Errors.ORDER_EXPIRED), orderHash);
return false;
@@ -233,4 +239,27 @@ contract MixinExchangeCore is
isError = errPercentageTimes1000000 > 1000;
return isError;
}
+
+ /// @dev Logs a Fill event with the given arguments.
+ /// The sole purpose of this function is to get around the stack variable limit.
+ function emitFillEvent(
+ Order memory order,
+ address takerAddress,
+ bytes32 orderHash,
+ FillResults memory fillResults)
+ internal
+ {
+ emit Fill(
+ order.makerAddress,
+ takerAddress,
+ order.feeRecipientAddress,
+ fillResults.makerAssetFilledAmount,
+ fillResults.takerAssetFilledAmount,
+ fillResults.makerFeePaid,
+ fillResults.takerFeePaid,
+ orderHash,
+ order.makerAssetData,
+ order.takerAssetData
+ );
+ }
}
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinTransactions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinTransactions.sol
new file mode 100644
index 000000000..e4fc4767b
--- /dev/null
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinTransactions.sol
@@ -0,0 +1,85 @@
+/*
+
+ 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.21;
+pragma experimental ABIEncoderV2;
+
+import "./mixins/MSignatureValidator.sol";
+import "./mixins/MTransactions.sol";
+
+contract MixinTransactions is
+ MSignatureValidator,
+ MTransactions
+{
+
+ // Mapping of transaction hash => executed
+ mapping (bytes32 => bool) public transactions;
+
+ // Address of current transaction signer
+ address currentSigner;
+
+ /// @dev Executes an exchange method call in the context of signer.
+ /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
+ /// @param signer Address of transaction signer.
+ /// @param data AbiV2 encoded calldata.
+ /// @param signature Proof of signer transaction by signer.
+ function executeTransaction(
+ uint256 salt,
+ address signer,
+ bytes data,
+ bytes signature)
+ external
+ {
+ // Prevent reentrancy
+ require(currentSigner == address(0));
+
+ // Calculate transaction hash
+ bytes32 transactionHash = keccak256(
+ address(this),
+ salt,
+ data
+ );
+
+ // Validate transaction has not been executed
+ require(!transactions[transactionHash]);
+
+ // TODO: is SignatureType.Caller necessary if we make this check?
+ if (signer != msg.sender) {
+ // Validate signature
+ require(isValidSignature(transactionHash, signer, signature));
+
+ // Set the current transaction signer
+ currentSigner = signer;
+ }
+
+ // Execute transaction
+ transactions[transactionHash] = true;
+ require(address(this).delegatecall(data));
+
+ // Reset current transaction signer
+ currentSigner = address(0);
+ }
+
+ function getSignerAddress()
+ internal
+ view
+ returns (address)
+ {
+ address signerAddress = currentSigner == address(0) ? msg.sender : currentSigner;
+ return signerAddress;
+ }
+}
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol
index 2c0fd0751..4d6ba17dd 100644
--- a/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/MixinWrapperFunctions.sol
@@ -75,24 +75,25 @@ contract MixinWrapperFunctions is
// | | 0x00 | | 1. offset to order (*) |
// | | 0x20 | | 2. takerAssetFillAmount |
// | | 0x40 | | 3. offset to signature (*) |
- // | Data | | 11 * 32 | order: |
- // | | 0x000 | | 1. makerAddress |
- // | | 0x020 | | 2. takerAddress |
- // | | 0x040 | | 3. feeRecipientAddress |
- // | | 0x060 | | 4. makerAssetAmount |
- // | | 0x080 | | 5. takerAssetAmount |
- // | | 0x0A0 | | 6. makerFeeAmount |
- // | | 0x0C0 | | 7. takerFeeAmount |
- // | | 0x0E0 | | 8. expirationTimeSeconds |
- // | | 0x100 | | 9. salt |
- // | | 0x120 | | 10. Offset to makerAssetProxyMetadata (*) |
- // | | 0x140 | | 11. Offset to takerAssetProxyMetadata (*) |
- // | | 0x160 | 32 | makerAssetProxyMetadata Length |
- // | | 0x180 | ** | makerAssetProxyMetadata Contents |
- // | | 0x1A0 | 32 | takerAssetProxyMetadata Length |
- // | | 0x1C0 | ** | takerAssetProxyMetadata Contents |
- // | | 0x1E0 | 32 | signature Length |
- // | | 0x200 | ** | signature Contents |
+ // | 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 makerAssetProxyMetadata (*) |
+ // | | 0x160 | | 12. Offset to takerAssetProxyMetadata (*) |
+ // | | 0x180 | 32 | makerAssetProxyMetadata Length |
+ // | | 0x1A0 | ** | makerAssetProxyMetadata Contents |
+ // | | 0x1C0 | 32 | takerAssetProxyMetadata Length |
+ // | | 0x1E0 | ** | takerAssetProxyMetadata 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.
@@ -150,19 +151,20 @@ contract MixinWrapperFunctions is
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))) // makerAssetAmount
- mstore(add(dataAreaEnd, 0x80), mload(add(sourceOffset, 0x80))) // takerAssetAmount
- mstore(add(dataAreaEnd, 0xA0), mload(add(sourceOffset, 0xA0))) // makerFeeAmount
- mstore(add(dataAreaEnd, 0xC0), mload(add(sourceOffset, 0xC0))) // takerFeeAmount
- mstore(add(dataAreaEnd, 0xE0), mload(add(sourceOffset, 0xE0))) // expirationTimeSeconds
- mstore(add(dataAreaEnd, 0x100), mload(add(sourceOffset, 0x100))) // salt
- mstore(add(dataAreaEnd, 0x120), mload(add(sourceOffset, 0x120))) // Offset to makerAssetProxyMetadata
- mstore(add(dataAreaEnd, 0x140), mload(add(sourceOffset, 0x140))) // Offset to takerAssetProxyMetadata
- dataAreaEnd := add(dataAreaEnd, 0x160)
- sourceOffset := add(sourceOffset, 0x160)
+ 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 makerAssetProxyMetadata
+ mstore(add(dataAreaEnd, 0x160), mload(add(sourceOffset, 0x160))) // Offset to takerAssetProxyMetadata
+ dataAreaEnd := add(dataAreaEnd, 0x180)
+ sourceOffset := add(sourceOffset, 0x180)
// Write offset to <order.makerAssetProxyMetadata>
- mstore(add(dataAreaStart, mul(9, 0x20)), sub(dataAreaEnd, dataAreaStart))
+ mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
// Calculate length of <order.makerAssetProxyMetadata>
arrayLenBytes := mload(sourceOffset)
@@ -181,7 +183,7 @@ contract MixinWrapperFunctions is
}
// Write offset to <order.takerAssetProxyMetadata>
- mstore(add(dataAreaStart, mul(10, 0x20)), sub(dataAreaEnd, dataAreaStart))
+ mstore(add(dataAreaStart, mul(11, 0x20)), sub(dataAreaEnd, dataAreaStart))
// Calculate length of <order.takerAssetProxyMetadata>
arrayLenBytes := mload(sourceOffset)
diff --git a/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MTransactions.sol b/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MTransactions.sol
new file mode 100644
index 000000000..31209de02
--- /dev/null
+++ b/packages/contracts/src/contracts/current/protocol/Exchange/mixins/MTransactions.sol
@@ -0,0 +1,41 @@
+/*
+
+ 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.21;
+pragma experimental ABIEncoderV2;
+
+import "./MSignatureValidator.sol";
+
+contract MTransactions is MSignatureValidator {
+
+ /// @dev Executes an exchange method call in the context of signer.
+ /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
+ /// @param signer Address of transaction signer.
+ /// @param data AbiV2 encoded calldata.
+ /// @param signature Proof of signer transaction by signer.
+ function executeTransaction(
+ uint256 salt,
+ address signer,
+ bytes data,
+ bytes signature)
+ external;
+
+ function getSignerAddress()
+ internal
+ view
+ returns (address);
+}