Abstract signature to opaque bytearray

This commit is contained in:
Remco Bloemen
2018-02-09 17:43:35 -08:00
committed by Amir Bandeali
parent a7f4701698
commit 2fe4e380d1
7 changed files with 148 additions and 161 deletions

View File

@@ -17,15 +17,16 @@
*/
pragma solidity ^0.4.19;
pragma experimental ABIEncoderV2;
import "./MixinExchangeCore.sol";
import "./MixinSignatureValidatorEcrecover.sol";
import "./MixinSignatureValidator.sol";
import "./MixinSettlementProxy.sol";
import "./MixinWrapperFunctions.sol";
contract Exchange is
MixinExchangeCore,
MixinSignatureValidatorEcrecover,
MixinSignatureValidator,
MixinSettlementProxy,
MixinWrapperFunctions
{
@@ -37,7 +38,7 @@ contract Exchange is
)
public
MixinExchangeCore()
MixinSignatureValidatorEcrecover()
MixinSignatureValidator()
MixinSettlementProxy(_tokenTransferProxy, _zrxToken)
MixinWrapperFunctions()
{

View File

@@ -73,19 +73,15 @@ contract MixinExchangeCore is
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerTokenFillAmount Desired amount of takerToken to fill.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
/// @param signature Proof of signing order by maker.
/// @return Total amount of takerToken filled in trade.
function fillOrder(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerTokenFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
public
returns (uint256 takerTokenFilledAmount)
address[5] orderAddresses,
uint[6] orderValues,
uint takerTokenFillAmount,
bytes signature)
public
returns (uint256 takerTokenFilledAmount)
{
Order memory order = Order({
maker: orderAddresses[0],
@@ -100,29 +96,37 @@ contract MixinExchangeCore is
expirationTimestampInSec: orderValues[4],
orderHash: getOrderHash(orderAddresses, orderValues)
});
require(order.taker == address(0) || order.taker == msg.sender);
require(order.makerTokenAmount > 0 && order.takerTokenAmount > 0 && takerTokenFillAmount > 0);
// Validate maker
require(order.makerTokenAmount > 0);
require(order.takerTokenAmount > 0);
require(isValidSignature(
order.maker,
order.orderHash,
v,
r,
s
order.maker,
signature
));
// Validate taker
if (order.taker != address(0)) {
require(order.taker == msg.sender);
}
require(takerTokenFillAmount > 0);
// Validate order expiration
if (block.timestamp >= order.expirationTimestampInSec) {
LogError(uint8(Errors.ORDER_EXPIRED), order.orderHash);
return 0;
}
// Validate order availability
uint256 remainingTakerTokenAmount = safeSub(order.takerTokenAmount, getUnavailableTakerTokenAmount(order.orderHash));
takerTokenFilledAmount = min256(takerTokenFillAmount, remainingTakerTokenAmount);
if (takerTokenFilledAmount == 0) {
LogError(uint8(Errors.ORDER_FULLY_FILLED_OR_CANCELLED), order.orderHash);
return 0;
}
// Validate fill order rounding
if (isRoundingError(takerTokenFilledAmount, order.takerTokenAmount, order.makerTokenAmount)) {
LogError(uint8(Errors.ROUNDING_ERROR_TOO_LARGE), order.orderHash);
return 0;

View File

@@ -0,0 +1,77 @@
/*
Copyright 2017 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.19;
import "./mixins/MSignatureValidator.sol";
/// @dev Provides MSignatureValidator
contract MixinSignatureValidator is
MSignatureValidator
{
enum SignatureType {
Invalid,
Ecrecover
}
function isValidSignature(
bytes32 hash,
address signer,
bytes signature)
public view
returns (bool isValid)
{
require(signature.length >= 1);
// Select signature type
SignatureType signatureType = SignatureType(uint8(signature[0]));
if (signatureType != SignatureType.Ecrecover) {
valid = false;
return;
}
// Verify using ecrecover
require(signature.length == 66);
uint8 v = uint8(signature[1]);
bytes32 r = get32(signature, 2);
bytes32 s = get32(signature, 34);
address recovered = ecrecover(
keccak256("\x19Ethereum Signed Message:\n32", hash),
v,
r,
s
);
isValid = signer == recovered;
}
function get32(bytes b, uint256 index)
private pure
returns (bytes32 result)
{
require(b.length >= index + 32);
// Arrays are prefixed by a 256 bit length parameter
index += 32;
// Read the bytes32 from array memory
assembly {
result := mload(add(b, index))
}
}
}

View File

@@ -1,45 +0,0 @@
/*
Copyright 2017 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.19;
import "./mixins/MSignatureValidator.sol";
/// @dev Provides MSignatureValidator
contract MixinSignatureValidatorEcrecover is
MSignatureValidator
{
function isValidSignature(
address signer,
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s)
public
constant
returns (bool isValid)
{
isValid = signer == ecrecover(
keccak256("\x19Ethereum Signed Message:\n32", hash),
v,
r,
s
);
return isValid;
}
}

View File

@@ -17,6 +17,7 @@
*/
pragma solidity ^0.4.19;
pragma experimental ABIEncoderV2;
import './mixins/MExchangeCore.sol';
import "../../utils/SafeMath/SafeMath.sol";
@@ -27,29 +28,18 @@ contract MixinWrapperFunctions is
SafeMath
{
/// @dev Fills an order with specified parameters and ECDSA signature. Throws if specified amount not filled entirely.
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerTokenFillAmount Desired amount of takerToken to fill.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
function fillOrKillOrder(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerTokenFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
uint[6] orderValues,
uint takerTokenFillAmount,
bytes signature)
public
{
require(fillOrder(
orderAddresses,
orderValues,
takerTokenFillAmount,
v,
r,
s
signature
) == takerTokenFillAmount);
}
@@ -57,18 +47,13 @@ contract MixinWrapperFunctions is
/// @param orderAddresses Array of order's maker, taker, makerToken, takerToken, and feeRecipient.
/// @param orderValues Array of order's makerTokenAmount, takerTokenAmount, makerFee, takerFee, expirationTimestampInSec, and salt.
/// @param takerTokenFillAmount Desired amount of takerToken to fill.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
/// @return Success if the transaction did not revert.
/// @return Total amount of takerToken filled in trade.
function fillOrderNoThrow(
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerTokenFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
bytes signature)
public
returns (bool success, uint256 takerTokenFilledAmount)
{
@@ -91,9 +76,16 @@ contract MixinWrapperFunctions is
mstore(add(x, 292), add(orderValues, 160)) // expirationTimestampInSec
mstore(add(x, 324), add(orderValues, 192)) // salt
mstore(add(x, 356), takerTokenFillAmount)
mstore(add(x, 388), v)
mstore(add(x, 420), r)
mstore(add(x, 452), s)
for {
let src := signature
let dst := add(x, 388)
let end := add(add(src, mload(signature)), 32)
} lt(src, end) {
src := add(src, 32)
dst := add(dst, 32)
} {
mstore(dst, mload(src))
}
success := delegatecall(
gas, // TODO: don't send all gas, save some for returning is case of throw
@@ -113,16 +105,11 @@ contract MixinWrapperFunctions is
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerTokenFillAmounts Array of desired amounts of takerToken to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
function batchFillOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerTokenFillAmounts,
uint8[] v,
bytes32[] r,
bytes32[] s)
bytes[] signatures)
external
{
for (uint256 i = 0; i < orderAddresses.length; i++) {
@@ -130,9 +117,7 @@ contract MixinWrapperFunctions is
orderAddresses[i],
orderValues[i],
takerTokenFillAmounts[i],
v[i],
r[i],
s[i]
signatures[i]
);
}
}
@@ -141,54 +126,38 @@ contract MixinWrapperFunctions is
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerTokenFillAmounts Array of desired amounts of takerToken to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
function batchFillOrKillOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerTokenFillAmounts,
uint8[] v,
bytes32[] r,
bytes32[] s)
external
uint[6][] orderValues,
uint[] takerTokenFillAmounts,
bytes[] signatures)
public /// Compiler crash when set to external
{
for (uint256 i = 0; i < orderAddresses.length; i++) {
fillOrKillOrder(
orderAddresses[i],
orderValues[i],
takerTokenFillAmounts[i],
v[i],
r[i],
s[i]
signatures[i]
);
}
}
/// @dev Synchronously executes multiple calls of fillOrderNoThrow in a single transaction.
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerTokenFillAmounts Array of desired amounts of takerToken to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
function batchFillOrdersNoThrow(
function fillOrdersUpTo(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256[] takerTokenFillAmounts,
uint8[] v,
bytes32[] r,
bytes32[] s)
external
uint[6][] orderValues,
uint[] takerTokenFillAmounts,
bytes[] signatures)
public /// Stack to deep when set to external
returns (uint)
{
for (uint256 i = 0; i < orderAddresses.length; i++) {
fillOrderNoThrow(
orderAddresses[i],
orderValues[i],
takerTokenFillAmounts[i],
v[i],
r[i],
s[i]
signatures[i]
);
}
}
@@ -197,17 +166,12 @@ contract MixinWrapperFunctions is
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerTokenFillAmount Desired total amount of takerToken to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
/// @return Total amount of takerTokenFillAmount filled in orders.
function marketFillOrders(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256 takerTokenFillAmount,
uint8[] v,
bytes32[] r,
bytes32[] s)
bytes[] signatures)
external
returns (uint256 totalTakerTokenFilledAmount)
{
@@ -217,9 +181,7 @@ contract MixinWrapperFunctions is
orderAddresses[i],
orderValues[i],
safeSub(takerTokenFillAmount, totalTakerTokenFilledAmount),
v[i],
r[i],
s[i]
signatures[i]
));
if (totalTakerTokenFilledAmount == takerTokenFillAmount) break;
}
@@ -230,17 +192,12 @@ contract MixinWrapperFunctions is
/// @param orderAddresses Array of address arrays containing individual order addresses.
/// @param orderValues Array of uint256 arrays containing individual order values.
/// @param takerTokenFillAmount Desired total amount of takerToken to fill in orders.
/// @param v Array ECDSA signature v parameters.
/// @param r Array of ECDSA signature r parameters.
/// @param s Array of ECDSA signature s parameters.
/// @return Total amount of takerTokenFillAmount filled in orders.
function marketFillOrdersNoThrow(
address[5][] orderAddresses,
uint256[6][] orderValues,
uint256 takerTokenFillAmount,
uint8[] v,
bytes32[] r,
bytes32[] s)
bytes[] signatures)
external
returns (uint256 totalTakerTokenFilledAmount)
{
@@ -250,9 +207,7 @@ contract MixinWrapperFunctions is
orderAddresses[i],
orderValues[i],
safeSub(takerTokenFillAmount, totalTakerTokenFilledAmount),
v[i],
r[i],
s[i]
signatures[i]
);
totalTakerTokenFilledAmount = safeAdd(totalTakerTokenFilledAmount, takerTokenFilledAmount);
if (totalTakerTokenFilledAmount == takerTokenFillAmount) break;
@@ -278,4 +233,5 @@ contract MixinWrapperFunctions is
);
}
}
}

View File

@@ -24,9 +24,7 @@ contract MExchangeCore {
address[5] orderAddresses,
uint256[6] orderValues,
uint256 takerTokenFillAmount,
uint8 v,
bytes32 r,
bytes32 s)
bytes signature)
public
returns (uint256 takerTokenFilledAmount);

View File

@@ -20,19 +20,15 @@ pragma solidity ^0.4.19;
contract MSignatureValidator {
/// @dev Verifies that an order signature is valid.
/// @param signer address of signer.
/// @param hash Signed Keccak-256 hash.
/// @param v ECDSA signature parameter v.
/// @param r ECDSA signature parameters r.
/// @param s ECDSA signature parameters s.
/// @dev Verifies that a signature is valid.
/// @param digest Message digest that is signed.
/// @param signer Address of signer.
/// @param signature Proof of signing.
/// @return Validity of order signature.
function isValidSignature(
bytes32 digest,
address signer,
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s)
bytes signature)
public view
returns (bool isValid);
}