Remove approval expirations, address other comments

This commit is contained in:
Michael Zhu 2019-10-04 17:58:37 -07:00
parent cf517b1459
commit 52fc7517f9
20 changed files with 164 additions and 562 deletions

View File

@ -67,11 +67,9 @@ jobs:
- restore_cache: - restore_cache:
keys: keys:
- repo-{{ .Environment.CIRCLE_SHA1 }} - repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-dev-utils @0x/contracts-staking - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-dev-utils @0x/contracts-staking @0x/contracts-coordinator
# TODO(dorothy-zbornak): Re-enable after updating this package for 3.0. # TODO(dorothy-zbornak): Re-enable after updating this package for 3.0.
# - run: yarn wsrun test:circleci @0x/contracts-extensions # - run: yarn wsrun test:circleci @0x/contracts-extensions
# TODO(abandeali): Re-enable after this package is complete.
# - run: yarn wsrun test:circleci @0x/contracts-coordinator
test-publish: test-publish:
resource_class: medium+ resource_class: medium+
docker: docker:

View File

@ -47,15 +47,12 @@ contract MixinCoordinatorApprovalVerifier is
/// @param transaction 0x transaction containing salt, signerAddress, and data. /// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function. /// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @param transactionSignature Proof that the transaction has been signed by the signer. /// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each
/// corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each
/// order in the transaction's Exchange calldata. /// order in the transaction's Exchange calldata.
function assertValidCoordinatorApprovals( function assertValidCoordinatorApprovals(
LibZeroExTransaction.ZeroExTransaction memory transaction, LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin, address txOrigin,
bytes memory transactionSignature, bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures bytes[] memory approvalSignatures
) )
public public
@ -72,7 +69,6 @@ contract MixinCoordinatorApprovalVerifier is
orders, orders,
txOrigin, txOrigin,
transactionSignature, transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures approvalSignatures
); );
} }
@ -136,15 +132,12 @@ contract MixinCoordinatorApprovalVerifier is
/// @param orders Array of order structs containing order specifications. /// @param orders Array of order structs containing order specifications.
/// @param txOrigin Required signer of Ethereum transaction calling this function. /// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @param transactionSignature Proof that the transaction has been signed by the signer. /// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each
/// corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order. /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
function _assertValidTransactionOrdersApproval( function _assertValidTransactionOrdersApproval(
LibZeroExTransaction.ZeroExTransaction memory transaction, LibZeroExTransaction.ZeroExTransaction memory transaction,
LibOrder.Order[] memory orders, LibOrder.Order[] memory orders,
address txOrigin, address txOrigin,
bytes memory transactionSignature, bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures bytes[] memory approvalSignatures
) )
internal internal
@ -164,23 +157,12 @@ contract MixinCoordinatorApprovalVerifier is
uint256 signaturesLength = approvalSignatures.length; uint256 signaturesLength = approvalSignatures.length;
for (uint256 i = 0; i != signaturesLength; i++) { for (uint256 i = 0; i != signaturesLength; i++) {
// Create approval message // Create approval message
uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];
CoordinatorApproval memory approval = CoordinatorApproval({ CoordinatorApproval memory approval = CoordinatorApproval({
txOrigin: txOrigin, txOrigin: txOrigin,
transactionHash: transactionHash, transactionHash: transactionHash,
transactionSignature: transactionSignature, transactionSignature: transactionSignature
approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds
}); });
// Ensure approval has not expired
// solhint-disable-next-line not-rely-on-time
if (currentApprovalExpirationTimeSeconds <= block.timestamp) {
LibRichErrors.rrevert(LibCoordinatorRichErrors.ApprovalExpiredError(
transactionHash,
currentApprovalExpirationTimeSeconds
));
}
// Hash approval message and recover signer address // Hash approval message and recover signer address
bytes32 approvalHash = getCoordinatorApprovalHash(approval); bytes32 approvalHash = getCoordinatorApprovalHash(approval);
address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]); address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]);

View File

@ -46,15 +46,12 @@ contract MixinCoordinatorCore is
/// @param transaction 0x transaction containing salt, signerAddress, and data. /// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function. /// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @param transactionSignature Proof that the transaction has been signed by the signer. /// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each
/// corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each
/// order in the transaction's Exchange calldata. /// order in the transaction's Exchange calldata.
function executeTransaction( function executeTransaction(
LibZeroExTransaction.ZeroExTransaction memory transaction, LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin, address txOrigin,
bytes memory transactionSignature, bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures bytes[] memory approvalSignatures
) )
public public
@ -66,7 +63,6 @@ contract MixinCoordinatorCore is
transaction, transaction,
txOrigin, txOrigin,
transactionSignature, transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures approvalSignatures
); );

View File

@ -30,15 +30,12 @@ contract ICoordinatorApprovalVerifier {
/// @param transaction 0x transaction containing salt, signerAddress, and data. /// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function. /// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @param transactionSignature Proof that the transaction has been signed by the signer. /// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each
/// corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each
/// order in the transaction's Exchange calldata. /// order in the transaction's Exchange calldata.
function assertValidCoordinatorApprovals( function assertValidCoordinatorApprovals(
LibZeroExTransaction.ZeroExTransaction memory transaction, LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin, address txOrigin,
bytes memory transactionSignature, bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures bytes[] memory approvalSignatures
) )
public public

View File

@ -29,15 +29,12 @@ contract ICoordinatorCore {
/// @param transaction 0x transaction containing salt, signerAddress, and data. /// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function. /// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @param transactionSignature Proof that the transaction has been signed by the signer. /// @param transactionSignature Proof that the transaction has been signed by the signer.
/// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each
/// corresponding approval signature expires.
/// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each
/// order in the transaction's Exchange calldata. /// order in the transaction's Exchange calldata.
function executeTransaction( function executeTransaction(
LibZeroExTransaction.ZeroExTransaction memory transaction, LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin, address txOrigin,
bytes memory transactionSignature, bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures bytes[] memory approvalSignatures
) )
public public

View File

@ -30,24 +30,22 @@ contract LibCoordinatorApproval is
// "CoordinatorApproval(", // "CoordinatorApproval(",
// "address txOrigin,", // "address txOrigin,",
// "bytes32 transactionHash,", // "bytes32 transactionHash,",
// "bytes transactionSignature,", // "bytes transactionSignature",
// "uint256 approvalExpirationTimeSeconds",
// ")" // ")"
// )); // ));
bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = bytes32 constant public EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH =
0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05; 0xa6511c04ca44625d50986f8c36bedc09366207a17b96e347094053a9f8507168;
struct CoordinatorApproval { struct CoordinatorApproval {
address txOrigin; // Required signer of Ethereum transaction that is submitting approval. address txOrigin; // Required signer of Ethereum transaction that is submitting approval.
bytes32 transactionHash; // EIP712 hash of the transaction. bytes32 transactionHash; // EIP712 hash of the transaction.
bytes transactionSignature; // Signature of the 0x transaction. bytes transactionSignature; // Signature of the 0x transaction.
uint256 approvalExpirationTimeSeconds; // Timestamp in seconds for which the approval expires.
} }
/// @dev Calculates the EIP712 hash of the Coordinator approval mesasage using the domain /// @dev Calculates the EIP712 hash of the Coordinator approval mesasage using the domain
/// separator of this contract. /// separator of this contract.
/// @param approval Coordinator approval message containing the transaction hash, transaction /// @param approval Coordinator approval message containing the transaction hash, and transaction
/// signature, and expiration of the approval. /// signature.
/// @return approvalHash EIP712 hash of the Coordinator approval message with the domain /// @return approvalHash EIP712 hash of the Coordinator approval message with the domain
/// separator of this contract. /// separator of this contract.
function getCoordinatorApprovalHash(CoordinatorApproval memory approval) function getCoordinatorApprovalHash(CoordinatorApproval memory approval)
@ -60,8 +58,8 @@ contract LibCoordinatorApproval is
} }
/// @dev Calculates the EIP712 hash of the Coordinator approval mesasage with no domain separator. /// @dev Calculates the EIP712 hash of the Coordinator approval mesasage with no domain separator.
/// @param approval Coordinator approval message containing the transaction hash, transaction /// @param approval Coordinator approval message containing the transaction hash, and transaction
// signature, and expiration of the approval. // signature.
/// @return result EIP712 hash of the Coordinator approval message with no domain separator. /// @return result EIP712 hash of the Coordinator approval message with no domain separator.
function _hashCoordinatorApproval(CoordinatorApproval memory approval) function _hashCoordinatorApproval(CoordinatorApproval memory approval)
internal internal
@ -72,7 +70,6 @@ contract LibCoordinatorApproval is
bytes memory transactionSignature = approval.transactionSignature; bytes memory transactionSignature = approval.transactionSignature;
address txOrigin = approval.txOrigin; address txOrigin = approval.txOrigin;
bytes32 transactionHash = approval.transactionHash; bytes32 transactionHash = approval.transactionHash;
uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;
// Assembly for more efficiently computing: // Assembly for more efficiently computing:
// keccak256(abi.encodePacked( // keccak256(abi.encodePacked(
@ -80,7 +77,6 @@ contract LibCoordinatorApproval is
// approval.txOrigin, // approval.txOrigin,
// approval.transactionHash, // approval.transactionHash,
// keccak256(approval.transactionSignature) // keccak256(approval.transactionSignature)
// approval.approvalExpirationTimeSeconds,
// )); // ));
assembly { assembly {
@ -94,9 +90,8 @@ contract LibCoordinatorApproval is
mstore(add(memPtr, 32), txOrigin) // txOrigin mstore(add(memPtr, 32), txOrigin) // txOrigin
mstore(add(memPtr, 64), transactionHash) // transactionHash mstore(add(memPtr, 64), transactionHash) // transactionHash
mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash mstore(add(memPtr, 96), transactionSignatureHash) // transactionSignatureHash
mstore(add(memPtr, 128), approvalExpirationTimeSeconds) // approvalExpirationTimeSeconds
// Compute hash // Compute hash
result := keccak256(memPtr, 160) result := keccak256(memPtr, 128)
} }
return result; return result;
} }

View File

@ -35,10 +35,6 @@ library LibCoordinatorRichErrors {
bytes4 internal constant INVALID_ORIGIN_ERROR_SELECTOR = bytes4 internal constant INVALID_ORIGIN_ERROR_SELECTOR =
0xa458d7ff; 0xa458d7ff;
// bytes4(keccak256("ApprovalExpiredError(bytes32,uint256)"))
bytes4 internal constant APPROVAL_EXPIRED_ERROR_SELECTOR =
0x677b712d;
// bytes4(keccak256("InvalidApprovalSignatureError(bytes32,address)")) // bytes4(keccak256("InvalidApprovalSignatureError(bytes32,address)"))
bytes4 internal constant INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR = bytes4 internal constant INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR =
0xd789b640; 0xd789b640;
@ -74,21 +70,6 @@ library LibCoordinatorRichErrors {
); );
} }
function ApprovalExpiredError(
bytes32 transactionHash,
uint256 approvalExpirationTime
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
APPROVAL_EXPIRED_ERROR_SELECTOR,
transactionHash,
approvalExpirationTime
);
}
function InvalidApprovalSignatureError( function InvalidApprovalSignatureError(
bytes32 transactionHash, bytes32 transactionHash,
address approverAddress address approverAddress

View File

@ -11,7 +11,8 @@ import {
import { import {
blockchainTests, blockchainTests,
constants, constants,
getLatestBlockTimestampAsync, hexConcat,
hexSlice,
OrderFactory, OrderFactory,
TransactionFactory, TransactionFactory,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
@ -46,7 +47,7 @@ blockchainTests.resets('Coordinator tests', env => {
let testFactory: CoordinatorTestFactory; let testFactory: CoordinatorTestFactory;
const GAS_PRICE = new BigNumber(env.txDefaults.gasPrice || constants.DEFAULT_GAS_PRICE); const GAS_PRICE = new BigNumber(env.txDefaults.gasPrice || constants.DEFAULT_GAS_PRICE);
const PROTOCOL_FEE_MULTIPLIER = new BigNumber(150); const PROTOCOL_FEE_MULTIPLIER = new BigNumber(150000);
const PROTOCOL_FEE = GAS_PRICE.times(PROTOCOL_FEE_MULTIPLIER); const PROTOCOL_FEE = GAS_PRICE.times(PROTOCOL_FEE_MULTIPLIER);
before(async () => { before(async () => {
@ -164,19 +165,12 @@ blockchainTests.resets('Coordinator tests', env => {
const order = await orderFactory.newSignedOrderAsync(); const order = await orderFactory.newSignedOrderAsync();
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, [order]);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory.newSignedApproval(transaction, takerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory.newSignedApproval(
transaction,
takerAddress,
approvalExpirationTimeSeconds,
);
const txData = { from: takerAddress, value: PROTOCOL_FEE }; const txData = { from: takerAddress, value: PROTOCOL_FEE };
await testFactory.executeFillTransactionTestAsync( await testFactory.executeFillTransactionTestAsync(
[order], [order],
transaction, transaction,
takerAddress, takerAddress,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
txData, txData,
); );
@ -191,7 +185,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
feeRecipientAddress, feeRecipientAddress,
[], [],
[],
txData, txData,
); );
}); });
@ -205,7 +198,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
feeRecipientAddress, feeRecipientAddress,
[], [],
[],
txData, txData,
); );
}); });
@ -219,7 +211,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
feeRecipientAddress, feeRecipientAddress,
[], [],
[],
txData, txData,
); );
}); });
@ -233,7 +224,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
feeRecipientAddress, feeRecipientAddress,
[], [],
[],
txData, txData,
); );
}); });
@ -247,7 +237,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
feeRecipientAddress, feeRecipientAddress,
[], [],
[],
txData, txData,
); );
}); });
@ -261,7 +250,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
takerAddress, takerAddress,
[], [],
[],
{ {
from: takerAddress, from: takerAddress,
gas: constants.MAX_EXECUTE_TRANSACTION_GAS, gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
@ -274,63 +262,31 @@ blockchainTests.resets('Coordinator tests', env => {
const orders = [await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory.newSignedApproval(transaction, takerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const signature = hexConcat(
const approval = approvalFactory.newSignedApproval( hexSlice(approval.signature, 0, 2),
transaction, '0xFFFFFFFF',
takerAddress, hexSlice(approval.signature, 6),
approvalExpirationTimeSeconds,
); );
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
await testFactory.executeFillTransactionTestAsync( await testFactory.executeFillTransactionTestAsync(
orders, orders,
transaction, transaction,
takerAddress, takerAddress,
[approvalExpirationTimeSeconds],
[signature], [signature],
{ from: takerAddress, value: PROTOCOL_FEE }, { from: takerAddress, value: PROTOCOL_FEE },
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress),
); );
}); });
it(`${fnName} should revert with an expired approval`, async () => {
const orders = [await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval = approvalFactory.newSignedApproval(
transaction,
takerAddress,
approvalExpirationTimeSeconds,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
await testFactory.executeFillTransactionTestAsync(
orders,
transaction,
takerAddress,
[approvalExpirationTimeSeconds],
[approval.signature],
{ from: takerAddress, value: PROTOCOL_FEE },
new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds),
);
});
it(`${fnName} should revert if not called by tx signer or approver`, async () => { it(`${fnName} should revert if not called by tx signer or approver`, async () => {
const orders = [await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory.newSignedApproval(transaction, takerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory.newSignedApproval(
transaction,
takerAddress,
approvalExpirationTimeSeconds,
);
await testFactory.executeFillTransactionTestAsync( await testFactory.executeFillTransactionTestAsync(
orders, orders,
transaction, transaction,
takerAddress, takerAddress,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: owner, value: PROTOCOL_FEE }, { from: owner, value: PROTOCOL_FEE },
new CoordinatorRevertErrors.InvalidOriginError(takerAddress), new CoordinatorRevertErrors.InvalidOriginError(takerAddress),
@ -344,18 +300,11 @@ blockchainTests.resets('Coordinator tests', env => {
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory.newSignedApproval(transaction, takerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory.newSignedApproval(
transaction,
takerAddress,
approvalExpirationTimeSeconds,
);
await testFactory.executeFillTransactionTestAsync( await testFactory.executeFillTransactionTestAsync(
orders, orders,
transaction, transaction,
takerAddress, takerAddress,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ {
from: takerAddress, from: takerAddress,
@ -368,7 +317,7 @@ blockchainTests.resets('Coordinator tests', env => {
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
await testFactory.executeFillTransactionTestAsync(orders, transaction, feeRecipientAddress, [], [], { await testFactory.executeFillTransactionTestAsync(orders, transaction, feeRecipientAddress, [], {
from: feeRecipientAddress, from: feeRecipientAddress,
gas: constants.MAX_EXECUTE_TRANSACTION_GAS, gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
value: PROTOCOL_FEE.times(orders.length), value: PROTOCOL_FEE.times(orders.length),
@ -378,7 +327,7 @@ blockchainTests.resets('Coordinator tests', env => {
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
await testFactory.executeFillTransactionTestAsync(orders, transaction, feeRecipientAddress, [], [], { await testFactory.executeFillTransactionTestAsync(orders, transaction, feeRecipientAddress, [], {
from: feeRecipientAddress, from: feeRecipientAddress,
gas: constants.MAX_EXECUTE_TRANSACTION_GAS, gas: constants.MAX_EXECUTE_TRANSACTION_GAS,
value: PROTOCOL_FEE.times(orders.length).plus(1), value: PROTOCOL_FEE.times(orders.length).plus(1),
@ -388,63 +337,31 @@ blockchainTests.resets('Coordinator tests', env => {
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory.newSignedApproval(transaction, takerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const signature = hexConcat(
const approval = approvalFactory.newSignedApproval( hexSlice(approval.signature, 0, 2),
transaction, '0xFFFFFFFF',
takerAddress, hexSlice(approval.signature, 6),
approvalExpirationTimeSeconds,
); );
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
await testFactory.executeFillTransactionTestAsync( await testFactory.executeFillTransactionTestAsync(
orders, orders,
transaction, transaction,
takerAddress, takerAddress,
[approvalExpirationTimeSeconds],
[signature], [signature],
{ from: takerAddress, value: PROTOCOL_FEE.times(orders.length) }, { from: takerAddress, value: PROTOCOL_FEE.times(orders.length) },
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, feeRecipientAddress),
); );
}); });
it(`${fnName} should revert with an expired approval`, async () => {
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval = approvalFactory.newSignedApproval(
transaction,
takerAddress,
approvalExpirationTimeSeconds,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
await testFactory.executeFillTransactionTestAsync(
orders,
transaction,
takerAddress,
[approvalExpirationTimeSeconds],
[approval.signature],
{ from: takerAddress, value: PROTOCOL_FEE.times(orders.length) },
new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds),
);
});
it(`${fnName} should revert if not called by tx signer or approver`, async () => { it(`${fnName} should revert if not called by tx signer or approver`, async () => {
const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()]; const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data }); const transaction = await takerTransactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory.newSignedApproval(transaction, takerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory.newSignedApproval(
transaction,
takerAddress,
approvalExpirationTimeSeconds,
);
await testFactory.executeFillTransactionTestAsync( await testFactory.executeFillTransactionTestAsync(
orders, orders,
transaction, transaction,
takerAddress, takerAddress,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: owner, value: PROTOCOL_FEE.times(orders.length) }, { from: owner, value: PROTOCOL_FEE.times(orders.length) },
new CoordinatorRevertErrors.InvalidOriginError(takerAddress), new CoordinatorRevertErrors.InvalidOriginError(takerAddress),
@ -463,7 +380,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
makerAddress, makerAddress,
[], [],
[],
{ {
from: makerAddress, from: makerAddress,
}, },
@ -479,7 +395,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
makerAddress, makerAddress,
[], [],
[],
{ {
from: makerAddress, from: makerAddress,
}, },
@ -494,7 +409,6 @@ blockchainTests.resets('Coordinator tests', env => {
transaction, transaction,
makerAddress, makerAddress,
[], [],
[],
{ {
from: makerAddress, from: makerAddress,
}, },

View File

@ -1,62 +1,77 @@
import { blockchainTests, expect } from '@0x/contracts-test-utils'; import { blockchainTests, expect } from '@0x/contracts-test-utils';
import { LogWithDecodedArgs } from 'ethereum-types';
import { CoordinatorRegistryCoordinatorEndpointSetEventArgs } from '../src'; import {
artifacts,
import { CoordinatorRegistryWrapper } from './utils/coordinator_registry_wrapper'; CoordinatorRegistryContract,
CoordinatorRegistryCoordinatorEndpointSetEventArgs,
CoordinatorTestFactory,
} from '../src';
// tslint:disable:no-unnecessary-type-assertion // tslint:disable:no-unnecessary-type-assertion
blockchainTests.resets('Coordinator Registry tests', env => { blockchainTests.resets('Coordinator Registry tests', env => {
let coordinatorRegistry: CoordinatorRegistryContract;
let coordinatorOperator: string; let coordinatorOperator: string;
const coordinatorEndpoint = 'http://sometec.0x.org'; const coordinatorEndpoint = 'http://sometec.0x.org';
const nilCoordinatorEndpoint = ''; const nilCoordinatorEndpoint = '';
let coordinatorRegistryWrapper: CoordinatorRegistryWrapper;
// tests // tests
before(async () => { before(async () => {
// setup accounts (skip owner) // setup accounts (skip owner)
const accounts = await env.getAccountAddressesAsync(); const accounts = await env.getAccountAddressesAsync();
[, coordinatorOperator] = accounts; [, coordinatorOperator] = accounts;
// deploy coordinator registry // deploy coordinator registry
coordinatorRegistryWrapper = new CoordinatorRegistryWrapper(env.provider); coordinatorRegistry = await CoordinatorRegistryContract.deployFrom0xArtifactAsync(
await coordinatorRegistryWrapper.deployCoordinatorRegistryAsync(); artifacts.CoordinatorRegistry,
env.provider,
env.txDefaults,
artifacts,
);
}); });
describe('core', () => { describe('core', () => {
it('Should successfully set a Coordinator endpoint', async () => { it('Should successfully set a Coordinator endpoint', async () => {
await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint); await coordinatorRegistry.setCoordinatorEndpoint.awaitTransactionSuccessAsync(coordinatorEndpoint, {
const recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( from: coordinatorOperator,
});
const recordedCoordinatorEndpoint = await coordinatorRegistry.getCoordinatorEndpoint.callAsync(
coordinatorOperator, coordinatorOperator,
); );
expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint);
}); });
it('Should successfully unset a Coordinator endpoint', async () => { it('Should successfully unset a Coordinator endpoint', async () => {
// set Coordinator endpoint // set Coordinator endpoint
await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint); await coordinatorRegistry.setCoordinatorEndpoint.awaitTransactionSuccessAsync(coordinatorEndpoint, {
let recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( from: coordinatorOperator,
});
let recordedCoordinatorEndpoint = await coordinatorRegistry.getCoordinatorEndpoint.callAsync(
coordinatorOperator, coordinatorOperator,
); );
expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint);
// unset Coordinator endpoint // unset Coordinator endpoint
await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, nilCoordinatorEndpoint); await coordinatorRegistry.setCoordinatorEndpoint.awaitTransactionSuccessAsync(nilCoordinatorEndpoint, {
recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( from: coordinatorOperator,
});
recordedCoordinatorEndpoint = await coordinatorRegistry.getCoordinatorEndpoint.callAsync(
coordinatorOperator, coordinatorOperator,
); );
expect(recordedCoordinatorEndpoint).to.be.equal(nilCoordinatorEndpoint); expect(recordedCoordinatorEndpoint).to.be.equal(nilCoordinatorEndpoint);
}); });
it('Should emit an event when setting Coordinator endpoint', async () => { it('Should emit an event when setting Coordinator endpoint', async () => {
// set Coordinator endpoint // set Coordinator endpoint
const txReceipt = await coordinatorRegistryWrapper.setCoordinatorEndpointAsync( const txReceipt = await coordinatorRegistry.setCoordinatorEndpoint.awaitTransactionSuccessAsync(
coordinatorOperator,
coordinatorEndpoint, coordinatorEndpoint,
{
from: coordinatorOperator,
},
); );
const recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync( const recordedCoordinatorEndpoint = await coordinatorRegistry.getCoordinatorEndpoint.callAsync(
coordinatorOperator, coordinatorOperator,
); );
expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint); expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint);
// validate event // validate event
expect(txReceipt.logs.length).to.be.equal(1); const expectedEvent: CoordinatorRegistryCoordinatorEndpointSetEventArgs = {
const log = txReceipt.logs[0] as LogWithDecodedArgs<CoordinatorRegistryCoordinatorEndpointSetEventArgs>; coordinatorOperator,
expect(log.args.coordinatorOperator).to.be.equal(coordinatorOperator); coordinatorEndpoint,
expect(log.args.coordinatorEndpoint).to.be.equal(coordinatorEndpoint); };
CoordinatorTestFactory.verifyEvents(txReceipt, [expectedEvent], 'CoordinatorEndpointSet');
}); });
}); });
}); });

View File

@ -24,9 +24,9 @@ blockchainTests.resets('Libs tests', env => {
describe('getApprovalHash', () => { describe('getApprovalHash', () => {
it('should return the correct approval hash', async () => { it('should return the correct approval hash', async () => {
const signedTx = { const signedTx = {
salt: new BigNumber(0), salt: constants.ZERO_AMOUNT,
gasPrice: new BigNumber(0), gasPrice: constants.ZERO_AMOUNT,
expirationTimeSeconds: new BigNumber(0), expirationTimeSeconds: constants.ZERO_AMOUNT,
signerAddress: constants.NULL_ADDRESS, signerAddress: constants.NULL_ADDRESS,
data: '0x1234', data: '0x1234',
signature: '0x5678', signature: '0x5678',
@ -35,20 +35,13 @@ blockchainTests.resets('Libs tests', env => {
chainId, chainId,
}, },
}; };
const approvalExpirationTimeSeconds = new BigNumber(0);
const txOrigin = constants.NULL_ADDRESS; const txOrigin = constants.NULL_ADDRESS;
const approval = { const approval = {
txOrigin, txOrigin,
transactionHash: transactionHashUtils.getTransactionHashHex(signedTx), transactionHash: transactionHashUtils.getTransactionHashHex(signedTx),
transactionSignature: signedTx.signature, transactionSignature: signedTx.signature,
approvalExpirationTimeSeconds,
}; };
const expectedApprovalHash = hashUtils.getApprovalHashHex( const expectedApprovalHash = hashUtils.getApprovalHashHex(signedTx, coordinatorContract.address, txOrigin);
signedTx,
coordinatorContract.address,
txOrigin,
approvalExpirationTimeSeconds,
);
const approvalHash = await coordinatorContract.getCoordinatorApprovalHash.callAsync(approval); const approvalHash = await coordinatorContract.getCoordinatorApprovalHash.callAsync(approval);
expect(expectedApprovalHash).to.eq(approvalHash); expect(expectedApprovalHash).to.eq(approvalHash);
}); });

View File

@ -3,14 +3,14 @@ import {
blockchainTests, blockchainTests,
constants, constants,
expect, expect,
getLatestBlockTimestampAsync, hexConcat,
hexSlice,
randomAddress, randomAddress,
TransactionFactory, TransactionFactory,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { CoordinatorRevertErrors, transactionHashUtils } from '@0x/order-utils'; import { CoordinatorRevertErrors, transactionHashUtils } from '@0x/order-utils';
import { SignatureType, SignedOrder } from '@0x/types'; import { SignatureType, SignedOrder } from '@0x/types';
import { BigNumber, LibBytesRevertErrors } from '@0x/utils'; import { BigNumber, LibBytesRevertErrors } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util';
import { ApprovalFactory, artifacts, CoordinatorContract } from '../src'; import { ApprovalFactory, artifacts, CoordinatorContract } from '../src';
@ -83,11 +83,10 @@ blockchainTests.resets('Mixins tests', env => {
it('should revert with with the Illegal signature type', async () => { it('should revert with with the Illegal signature type', async () => {
const data = constants.NULL_BYTES; const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const illegalSignatureByte = ethUtil.toBuffer(SignatureType.Illegal).toString('hex'); transaction.signature = hexConcat(
transaction.signature = `${transaction.signature.slice( hexSlice(transaction.signature, 0, transaction.signature.length - 1),
0, SignatureType.Illegal,
transaction.signature.length - 2, );
)}${illegalSignatureByte}`;
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith( expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
new CoordinatorRevertErrors.SignatureError( new CoordinatorRevertErrors.SignatureError(
@ -100,8 +99,7 @@ blockchainTests.resets('Mixins tests', env => {
it('should revert with with the Invalid signature type', async () => { it('should revert with with the Invalid signature type', async () => {
const data = constants.NULL_BYTES; const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex'); transaction.signature = hexConcat(SignatureType.Invalid);
transaction.signature = `0x${invalidSignatureByte}`;
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith( expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
new CoordinatorRevertErrors.SignatureError( new CoordinatorRevertErrors.SignatureError(
@ -111,14 +109,29 @@ blockchainTests.resets('Mixins tests', env => {
), ),
); );
}); });
it("should revert with with a signature type that doesn't exist", async () => { it('should revert with with a signature type that equals `NSignatureTypes`', async () => {
const data = constants.NULL_BYTES; const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const invalidSignatureByte = '04'; transaction.signature = hexConcat(
transaction.signature = `${transaction.signature.slice( hexSlice(transaction.signature, 0, transaction.signature.length - 1),
0, SignatureType.NSignatureTypes,
transaction.signature.length - 2, );
)}${invalidSignatureByte}`; const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
new CoordinatorRevertErrors.SignatureError(
CoordinatorRevertErrors.SignatureErrorCodes.Unsupported,
transactionHash,
transaction.signature,
),
);
});
it("should revert with with a signature type that isn't supported", async () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
transaction.signature = hexConcat(
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
SignatureType.Wallet,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith( expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
new CoordinatorRevertErrors.SignatureError( new CoordinatorRevertErrors.SignatureError(
@ -215,27 +228,20 @@ blockchainTests.resets('Mixins tests', env => {
describe('Single order approvals', () => { describe('Single order approvals', () => {
for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) { for (const fnName of exchangeConstants.SINGLE_FILL_FN_NAMES) {
it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1], expiration=[valid]`, async () => { it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1]`, async () => {
const order = { const order = {
...defaultOrder, ...defaultOrder,
senderAddress: constants.NULL_ADDRESS, senderAddress: constants.NULL_ADDRESS,
@ -243,23 +249,16 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [order]; const orders = [order];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -268,33 +267,25 @@ blockchainTests.resets('Mixins tests', env => {
approvalSignerAddress1, approvalSignerAddress1,
transaction.signature, transaction.signature,
[], [],
[],
{ {
from: approvalSignerAddress1, from: approvalSignerAddress1,
}, },
); );
}); });
it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
approvalSignerAddress1, approvalSignerAddress1,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: approvalSignerAddress1 }, { from: approvalSignerAddress1 },
); );
}); });
it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => { it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -303,29 +294,25 @@ blockchainTests.resets('Mixins tests', env => {
approvalSignerAddress1, approvalSignerAddress1,
transaction.signature, transaction.signature,
[], [],
[],
{ {
from: approvalSignerAddress1, from: approvalSignerAddress1,
}, },
); );
}); });
it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid], expiration=[valid]`, async () => { it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const signature = hexConcat(
const approval = approvalFactory1.newSignedApproval( hexSlice(approval.signature, 0, 2),
transaction, '0xFFFFFFFF',
transactionSignerAddress, hexSlice(approval.signature, 6),
approvalExpirationTimeSeconds,
); );
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[signature], [signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
@ -335,48 +322,16 @@ blockchainTests.resets('Mixins tests', env => {
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1),
); );
}); });
it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ from: transactionSignerAddress },
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(tx).to.revertWith(
new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds),
);
});
it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: approvalSignerAddress2 }, { from: approvalSignerAddress2 },
); );
@ -390,50 +345,36 @@ blockchainTests.resets('Mixins tests', env => {
...exchangeConstants.MARKET_FILL_FN_NAMES, ...exchangeConstants.MARKET_FILL_FN_NAMES,
...exchangeConstants.MATCH_ORDER_FN_NAMES, ...exchangeConstants.MATCH_ORDER_FN_NAMES,
]) { ]) {
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => {
const orders = [defaultOrder, defaultOrder].map(order => ({ const orders = [defaultOrder, defaultOrder].map(order => ({
...order, ...order,
senderAddress: constants.NULL_ADDRESS, senderAddress: constants.NULL_ADDRESS,
})); }));
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => {
const orders = [defaultOrder, defaultOrder].map(order => ({ const orders = [defaultOrder, defaultOrder].map(order => ({
...order, ...order,
senderAddress: constants.NULL_ADDRESS, senderAddress: constants.NULL_ADDRESS,
@ -445,56 +386,37 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[], [],
[],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => { it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }]; const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature], [approval.signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => { it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const approval1 = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
[approval1.signature, approval2.signature], [approval1.signature, approval2.signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => { it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -503,33 +425,25 @@ blockchainTests.resets('Mixins tests', env => {
approvalSignerAddress1, approvalSignerAddress1,
transaction.signature, transaction.signature,
[], [],
[],
{ from: approvalSignerAddress1 }, { from: approvalSignerAddress1 },
); );
}); });
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => { it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval2.signature], [approval2.signature],
{ from: approvalSignerAddress1 }, { from: approvalSignerAddress1 },
); );
expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress)); expect(tx).to.revertWith(new CoordinatorRevertErrors.InvalidOriginError(transactionSignerAddress));
}); });
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => { it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -538,7 +452,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[], [],
[],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
@ -547,23 +460,20 @@ blockchainTests.resets('Mixins tests', env => {
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1),
); );
}); });
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => { it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const signature = hexConcat(
const approval = approvalFactory1.newSignedApproval( hexSlice(approval.signature, 0, 2),
transaction, '0xFFFFFFFF',
transactionSignerAddress, hexSlice(approval.signature, 6),
approvalExpirationTimeSeconds,
); );
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[signature], [signature],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
@ -573,28 +483,21 @@ blockchainTests.resets('Mixins tests', env => {
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress1),
); );
}); });
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => { it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const approval1 = approvalFactory1.newSignedApproval( const approvalSignature2 = hexConcat(
transaction, hexSlice(approval2.signature, 0, 2),
transactionSignerAddress, '0xFFFFFFFF',
approvalExpirationTimeSeconds, hexSlice(approval2.signature, 6),
); );
const approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
[approval1.signature, approvalSignature2], [approval1.signature, approvalSignature2],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
@ -604,23 +507,20 @@ blockchainTests.resets('Mixins tests', env => {
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2),
); );
}); });
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => { it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }]; const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalSignature2 = hexConcat(
const approval2 = approvalFactory2.newSignedApproval( hexSlice(approval2.signature, 0, 2),
transaction, '0xFFFFFFFF',
transactionSignerAddress, hexSlice(approval2.signature, 6),
approvalExpirationTimeSeconds,
); );
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
approvalSignerAddress1, approvalSignerAddress1,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approvalSignature2], [approvalSignature2],
{ from: approvalSignerAddress1 }, { from: approvalSignerAddress1 },
); );
@ -630,79 +530,16 @@ blockchainTests.resets('Mixins tests', env => {
new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2), new CoordinatorRevertErrors.InvalidApprovalSignatureError(transactionHash, approvalSignerAddress2),
); );
}); });
it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[valid,invalid]`, async () => { it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval1 = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds1,
);
const approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds2,
);
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2],
[approval1.signature, approval2.signature],
{ from: transactionSignerAddress },
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(tx).to.revertWith(
new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds2),
);
});
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
approvalSignerAddress1,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval2.signature],
{ from: approvalSignerAddress1 },
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(tx).to.revertWith(
new CoordinatorRevertErrors.ApprovalExpiredError(transactionHash, approvalExpirationTimeSeconds),
);
});
it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data }); const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const currentTimestamp = await getLatestBlockTimestampAsync(); const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval1 = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const tx = mixins.assertValidCoordinatorApprovals.callAsync( const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[approvalExpirationTimeSeconds],
[approval1.signature], [approval1.signature],
{ from: approvalSignerAddress2 }, { from: approvalSignerAddress2 },
); );
@ -720,7 +557,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[], [],
[],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
@ -733,7 +569,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[], [],
[],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });
@ -745,7 +580,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress, transactionSignerAddress,
transaction.signature, transaction.signature,
[], [],
[],
{ from: transactionSignerAddress }, { from: transactionSignerAddress },
); );
}); });

View File

@ -1,7 +1,5 @@
import { signingUtils } from '@0x/contracts-test-utils'; import { hexConcat, signingUtils } from '@0x/contracts-test-utils';
import { SignatureType, SignedZeroExTransaction } from '@0x/types'; import { SignatureType, SignedZeroExTransaction } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util';
import { hashUtils, SignedCoordinatorApproval } from './index'; import { hashUtils, SignedCoordinatorApproval } from './index';
@ -17,21 +15,14 @@ export class ApprovalFactory {
public newSignedApproval( public newSignedApproval(
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber,
signatureType: SignatureType = SignatureType.EthSign, signatureType: SignatureType = SignatureType.EthSign,
): SignedCoordinatorApproval { ): SignedCoordinatorApproval {
const approvalHashBuff = hashUtils.getApprovalHashBuffer( const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, this._verifyingContractAddress, txOrigin);
transaction,
this._verifyingContractAddress,
txOrigin,
approvalExpirationTimeSeconds,
);
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType); const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
const signedApproval = { const signedApproval = {
txOrigin, txOrigin,
transaction, transaction,
approvalExpirationTimeSeconds, signature: hexConcat(signatureBuff),
signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
}; };
return signedApproval; return signedApproval;
} }

View File

@ -1,66 +0,0 @@
import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange';
import { LogDecoder, txDefaults } from '@0x/contracts-test-utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
import { artifacts, CoordinatorRegistryContract } from '../../src';
export class CoordinatorRegistryWrapper {
private readonly _web3Wrapper: Web3Wrapper;
private readonly _provider: ZeroExProvider;
private readonly _logDecoder: LogDecoder;
private _coordinatorRegistryContract?: CoordinatorRegistryContract;
/**
* Instanitates an CoordinatorRegistryWrapper
* @param provider Web3 provider to use for all JSON RPC requests
* Instance of CoordinatorRegistryWrapper
*/
constructor(provider: ZeroExProvider) {
this._web3Wrapper = new Web3Wrapper(provider);
this._provider = provider;
this._logDecoder = new LogDecoder(this._web3Wrapper, { ...exchangeArtifacts, ...artifacts });
}
public async deployCoordinatorRegistryAsync(): Promise<CoordinatorRegistryContract> {
this._coordinatorRegistryContract = await CoordinatorRegistryContract.deployFrom0xArtifactAsync(
artifacts.CoordinatorRegistry,
this._provider,
txDefaults,
artifacts,
);
if (this._coordinatorRegistryContract === undefined) {
throw new Error(`Failed to deploy Coordinator Registry contract.`);
}
return this._coordinatorRegistryContract;
}
public async setCoordinatorEndpointAsync(
coordinatorOperator: string,
coordinatorEndpoint: string,
): Promise<TransactionReceiptWithDecodedLogs> {
this._assertCoordinatorRegistryDeployed();
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(
await (this
._coordinatorRegistryContract as CoordinatorRegistryContract).setCoordinatorEndpoint.sendTransactionAsync(
coordinatorEndpoint,
{
from: coordinatorOperator,
},
),
);
return txReceipt;
}
public async getCoordinatorEndpointAsync(coordinatorOperator: string): Promise<string> {
this._assertCoordinatorRegistryDeployed();
const coordinatorEndpoint = await (this
._coordinatorRegistryContract as CoordinatorRegistryContract).getCoordinatorEndpoint.callAsync(
coordinatorOperator,
);
return coordinatorEndpoint;
}
private _assertCoordinatorRegistryDeployed(): void {
if (this._coordinatorRegistryContract === undefined) {
throw new Error(
'The Coordinator Registry contract was not deployed through the CoordinatorRegistryWrapper. Call `deployCoordinatorRegistryAsync` to deploy.',
);
}
}
}

View File

@ -71,7 +71,6 @@ export class CoordinatorTestFactory {
orders: SignedOrder[], orders: SignedOrder[],
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber[],
approvalSignatures: string[], approvalSignatures: string[],
txData: Partial<TxData>, txData: Partial<TxData>,
revertError?: RevertError, revertError?: RevertError,
@ -81,7 +80,6 @@ export class CoordinatorTestFactory {
transaction, transaction,
txOrigin, txOrigin,
transaction.signature, transaction.signature,
approvalExpirationTimeSeconds,
approvalSignatures, approvalSignatures,
txData, txData,
); );
@ -106,7 +104,6 @@ export class CoordinatorTestFactory {
orders: SignedOrder[], orders: SignedOrder[],
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber[],
approvalSignatures: string[], approvalSignatures: string[],
txData: Partial<TxData>, txData: Partial<TxData>,
): Promise<void> { ): Promise<void> {
@ -114,7 +111,6 @@ export class CoordinatorTestFactory {
transaction, transaction,
txOrigin, txOrigin,
transaction.signature, transaction.signature,
approvalExpirationTimeSeconds,
approvalSignatures, approvalSignatures,
txData, txData,
); );

View File

@ -1,33 +1,16 @@
import { hexConcat } from '@0x/contracts-test-utils';
import { eip712Utils } from '@0x/order-utils'; import { eip712Utils } from '@0x/order-utils';
import { SignedZeroExTransaction } from '@0x/types'; import { SignedZeroExTransaction } from '@0x/types';
import { BigNumber, signTypedDataUtils } from '@0x/utils'; import { signTypedDataUtils } from '@0x/utils';
import * as _ from 'lodash';
export const hashUtils = { export const hashUtils = {
getApprovalHashBuffer( getApprovalHashBuffer(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): Buffer {
transaction: SignedZeroExTransaction, const typedData = eip712Utils.createCoordinatorApprovalTypedData(transaction, verifyingContract, txOrigin);
verifyingContract: string,
txOrigin: string,
approvalExpirationTimeSeconds: BigNumber,
): Buffer {
const typedData = eip712Utils.createCoordinatorApprovalTypedData(
transaction,
verifyingContract,
txOrigin,
approvalExpirationTimeSeconds,
);
const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData); const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
return hashBuffer; return hashBuffer;
}, },
getApprovalHashHex( getApprovalHashHex(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): string {
transaction: SignedZeroExTransaction, const hashHex = hexConcat(hashUtils.getApprovalHashBuffer(transaction, verifyingContract, txOrigin));
verifyingContract: string,
txOrigin: string,
approvalExpirationTimeSeconds: BigNumber,
): string {
const hashHex = `0x${hashUtils
.getApprovalHashBuffer(transaction, verifyingContract, txOrigin, approvalExpirationTimeSeconds)
.toString('hex')}`;
return hashHex; return hashHex;
}, },
}; };

View File

@ -1,10 +1,8 @@
import { SignedZeroExTransaction } from '@0x/types'; import { SignedZeroExTransaction } from '@0x/types';
import { BigNumber } from '@0x/utils';
export interface CoordinatorApproval { export interface CoordinatorApproval {
transaction: SignedZeroExTransaction; transaction: SignedZeroExTransaction;
txOrigin: string; txOrigin: string;
approvalExpirationTimeSeconds: BigNumber;
} }
export interface SignedCoordinatorApproval extends CoordinatorApproval { export interface SignedCoordinatorApproval extends CoordinatorApproval {

View File

@ -53,7 +53,10 @@ contract TestProtocolFeeCollector {
payable payable
{ {
if (msg.value != protocolFeePaid) { if (msg.value != protocolFeePaid) {
assert(msg.value == 0); require(
msg.value == 0,
"No value should be forwarded to collector when paying fee in WETH"
);
// Transfer the protocol fee to this address in WETH. // Transfer the protocol fee to this address in WETH.
IEtherToken(_wethAddress).transferFrom( IEtherToken(_wethAddress).transferFrom(

View File

@ -25,8 +25,8 @@
"install:all": "yarn install", "install:all": "yarn install",
"wsrun": "wsrun", "wsrun": "wsrun",
"lerna": "lerna", "lerna": "lerna",
"build": "lerna link && wsrun build $PKG -r --stages --fast-exit --exclude-missing --exclude @0x/contracts-extensions --exclude @0x/contracts-coordinator", "build": "lerna link && wsrun build $PKG -r --stages --fast-exit --exclude-missing --exclude @0x/contracts-extensions",
"build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing --exclude @0x/contracts-extensions --exclude @0x/contracts-coordinator", "build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing --exclude @0x/contracts-extensions",
"build:contracts": "lerna link && wsrun build -p ${npm_package_config_contractsPackages} -c --fast-exit -r --stages --exclude-missing", "build:contracts": "lerna link && wsrun build -p ${npm_package_config_contractsPackages} -c --fast-exit -r --stages --exclude-missing",
"build:monorepo_scripts": "PKG=@0x/monorepo-scripts yarn build", "build:monorepo_scripts": "PKG=@0x/monorepo-scripts yarn build",
"build:ts": "tsc -b", "build:ts": "tsc -b",
@ -51,7 +51,7 @@
"lint:contracts": "wsrun lint -p ${npm_package_config_contractsPackages} -c --fast-exit --stages --exclude-missing" "lint:contracts": "wsrun lint -p ${npm_package_config_contractsPackages} -c --fast-exit --stages --exclude-missing"
}, },
"config": { "config": {
"contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils", "contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-dev-utils @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-integrations @0x/contracts-multisig @0x/contracts-staking @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator",
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic", "mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic",
"packagesWithDocPages": "contract-wrappers 0x.js connect json-schemas subproviders web3-wrapper order-utils sol-compiler sol-coverage sol-profiler sol-trace ethereum-types asset-buyer asset-swapper migrations", "packagesWithDocPages": "contract-wrappers 0x.js connect json-schemas subproviders web3-wrapper order-utils sol-compiler sol-coverage sol-profiler sol-trace ethereum-types asset-buyer asset-swapper migrations",
"ignoreDependencyVersions": "@types/styled-components @types/node", "ignoreDependencyVersions": "@types/styled-components @types/node",

View File

@ -147,7 +147,6 @@ export const constants = {
{ name: 'txOrigin', type: 'address' }, { name: 'txOrigin', type: 'address' },
{ name: 'transactionHash', type: 'bytes32' }, { name: 'transactionHash', type: 'bytes32' },
{ name: 'transactionSignature', type: 'bytes' }, { name: 'transactionSignature', type: 'bytes' },
{ name: 'approvalExpirationTimeSeconds', type: 'uint256' },
], ],
}, },
ERC20_METHOD_ABI, ERC20_METHOD_ABI,

View File

@ -9,7 +9,6 @@ import {
SignedZeroExTransaction, SignedZeroExTransaction,
ZeroExTransaction, ZeroExTransaction,
} from '@0x/types'; } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { constants } from './constants'; import { constants } from './constants';
@ -99,14 +98,12 @@ export const eip712Utils = {
* @param transaction A 0x transaction * @param transaction A 0x transaction
* @param verifyingContract The coordinator extension contract address that will be verifying the typedData * @param verifyingContract The coordinator extension contract address that will be verifying the typedData
* @param txOrigin The desired `tx.origin` that should be able to submit an Ethereum txn involving this 0x transaction * @param txOrigin The desired `tx.origin` that should be able to submit an Ethereum txn involving this 0x transaction
* @param approvalExpirationTimeSeconds The approvals expiration time
* @return A typed data object * @return A typed data object
*/ */
createCoordinatorApprovalTypedData: ( createCoordinatorApprovalTypedData: (
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
verifyingContract: string, verifyingContract: string,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber,
): EIP712TypedData => { ): EIP712TypedData => {
const domain = { const domain = {
...transaction.domain, ...transaction.domain,
@ -119,7 +116,6 @@ export const eip712Utils = {
txOrigin, txOrigin,
transactionHash, transactionHash,
transactionSignature: transaction.signature, transactionSignature: transaction.signature,
approvalExpirationTimeSeconds: approvalExpirationTimeSeconds.toString(),
}; };
const typedData = eip712Utils.createTypedData( const typedData = eip712Utils.createTypedData(
constants.COORDINATOR_APPROVAL_SCHEMA.name, constants.COORDINATOR_APPROVAL_SCHEMA.name,