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:
keys:
- 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.
# - 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:
resource_class: medium+
docker:
@ -82,7 +80,7 @@ jobs:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
- run:
command: yarn test:publish:circleci
no_output_timeout: 1800
test-doc-generation:

View File

@ -47,15 +47,12 @@ contract MixinCoordinatorApprovalVerifier is
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @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 in the transaction's Exchange calldata.
function assertValidCoordinatorApprovals(
LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
public
@ -72,7 +69,6 @@ contract MixinCoordinatorApprovalVerifier is
orders,
txOrigin,
transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures
);
}
@ -127,7 +123,7 @@ contract MixinCoordinatorApprovalVerifier is
orders = new LibOrder.Order[](2);
orders[0] = leftOrder;
orders[1] = rightOrder;
}
}
return orders;
}
@ -136,15 +132,12 @@ contract MixinCoordinatorApprovalVerifier is
/// @param orders Array of order structs containing order specifications.
/// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @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.
function _assertValidTransactionOrdersApproval(
LibZeroExTransaction.ZeroExTransaction memory transaction,
LibOrder.Order[] memory orders,
address txOrigin,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
internal
@ -164,23 +157,12 @@ contract MixinCoordinatorApprovalVerifier is
uint256 signaturesLength = approvalSignatures.length;
for (uint256 i = 0; i != signaturesLength; i++) {
// Create approval message
uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];
CoordinatorApproval memory approval = CoordinatorApproval({
txOrigin: txOrigin,
transactionHash: transactionHash,
transactionSignature: transactionSignature,
approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds
transactionSignature: transactionSignature
});
// 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
bytes32 approvalHash = getCoordinatorApprovalHash(approval);
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 txOrigin Required signer of Ethereum transaction calling this function.
/// @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 in the transaction's Exchange calldata.
function executeTransaction(
LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
public
@ -66,7 +63,6 @@ contract MixinCoordinatorCore is
transaction,
txOrigin,
transactionSignature,
approvalExpirationTimeSeconds,
approvalSignatures
);

View File

@ -30,15 +30,12 @@ contract ICoordinatorApprovalVerifier {
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @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 in the transaction's Exchange calldata.
function assertValidCoordinatorApprovals(
LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
public

View File

@ -29,15 +29,12 @@ contract ICoordinatorCore {
/// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @param txOrigin Required signer of Ethereum transaction calling this function.
/// @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 in the transaction's Exchange calldata.
function executeTransaction(
LibZeroExTransaction.ZeroExTransaction memory transaction,
address txOrigin,
bytes memory transactionSignature,
uint256[] memory approvalExpirationTimeSeconds,
bytes[] memory approvalSignatures
)
public

View File

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

View File

@ -35,10 +35,6 @@ library LibCoordinatorRichErrors {
bytes4 internal constant INVALID_ORIGIN_ERROR_SELECTOR =
0xa458d7ff;
// bytes4(keccak256("ApprovalExpiredError(bytes32,uint256)"))
bytes4 internal constant APPROVAL_EXPIRED_ERROR_SELECTOR =
0x677b712d;
// bytes4(keccak256("InvalidApprovalSignatureError(bytes32,address)"))
bytes4 internal constant INVALID_APPROVAL_SIGNATURE_ERROR_SELECTOR =
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(
bytes32 transactionHash,
address approverAddress

View File

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

View File

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

View File

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

View File

@ -3,14 +3,14 @@ import {
blockchainTests,
constants,
expect,
getLatestBlockTimestampAsync,
hexConcat,
hexSlice,
randomAddress,
TransactionFactory,
} from '@0x/contracts-test-utils';
import { CoordinatorRevertErrors, transactionHashUtils } from '@0x/order-utils';
import { SignatureType, SignedOrder } from '@0x/types';
import { BigNumber, LibBytesRevertErrors } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util';
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 () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const illegalSignatureByte = ethUtil.toBuffer(SignatureType.Illegal).toString('hex');
transaction.signature = `${transaction.signature.slice(
0,
transaction.signature.length - 2,
)}${illegalSignatureByte}`;
transaction.signature = hexConcat(
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
SignatureType.Illegal,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
new CoordinatorRevertErrors.SignatureError(
@ -100,8 +99,7 @@ blockchainTests.resets('Mixins tests', env => {
it('should revert with with the Invalid signature type', async () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex');
transaction.signature = `0x${invalidSignatureByte}`;
transaction.signature = hexConcat(SignatureType.Invalid);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
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 transaction = await transactionFactory.newSignedTransactionAsync({ data });
const invalidSignatureByte = '04';
transaction.signature = `${transaction.signature.slice(
0,
transaction.signature.length - 2,
)}${invalidSignatureByte}`;
transaction.signature = hexConcat(
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
SignatureType.NSignatureTypes,
);
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);
expect(mixins.getSignerAddress.callAsync(transactionHash, transaction.signature)).to.revertWith(
new CoordinatorRevertErrors.SignatureError(
@ -215,27 +228,20 @@ blockchainTests.resets('Mixins tests', env => {
describe('Single order approvals', () => {
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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ 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 = {
...defaultOrder,
senderAddress: constants.NULL_ADDRESS,
@ -243,23 +249,16 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [order];
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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ 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 data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -268,33 +267,25 @@ blockchainTests.resets('Mixins tests', env => {
approvalSignerAddress1,
transaction.signature,
[],
[],
{
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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
approvalSignerAddress1,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ 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 data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -303,29 +294,25 @@ blockchainTests.resets('Mixins tests', env => {
approvalSignerAddress1,
transaction.signature,
[],
[],
{
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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const signature = hexConcat(
hexSlice(approval.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval.signature, 6),
);
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[signature],
{ from: transactionSignerAddress },
);
@ -335,48 +322,16 @@ blockchainTests.resets('Mixins tests', env => {
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 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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ from: approvalSignerAddress2 },
);
@ -390,50 +345,36 @@ blockchainTests.resets('Mixins tests', env => {
...exchangeConstants.MARKET_FILL_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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ 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 => ({
...order,
senderAddress: constants.NULL_ADDRESS,
}));
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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ 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 => ({
...order,
senderAddress: constants.NULL_ADDRESS,
@ -445,56 +386,37 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress,
transaction.signature,
[],
[],
{ 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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval.signature],
{ 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 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 approval1 = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
await mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
[approval1.signature, approval2.signature],
{ 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 data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -503,33 +425,25 @@ blockchainTests.resets('Mixins tests', env => {
approvalSignerAddress1,
transaction.signature,
[],
[],
{ 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 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 approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval2.signature],
{ from: approvalSignerAddress1 },
);
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 data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
@ -538,7 +452,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress,
transaction.signature,
[],
[],
{ from: transactionSignerAddress },
);
@ -547,23 +460,20 @@ blockchainTests.resets('Mixins tests', env => {
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 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const signature = hexConcat(
hexSlice(approval.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval.signature, 6),
);
const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[signature],
{ from: transactionSignerAddress },
);
@ -573,28 +483,21 @@ blockchainTests.resets('Mixins tests', env => {
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 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 approval1 = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const approvalSignature2 = hexConcat(
hexSlice(approval2.signature, 0, 2),
'0xFFFFFFFF',
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(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
[approval1.signature, approvalSignature2],
{ from: transactionSignerAddress },
);
@ -604,23 +507,20 @@ blockchainTests.resets('Mixins tests', env => {
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 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 approval2 = approvalFactory2.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const approvalSignature2 = hexConcat(
hexSlice(approval2.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval2.signature, 6),
);
const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
approvalSignerAddress1,
transaction.signature,
[approvalExpirationTimeSeconds],
[approvalSignature2],
{ from: approvalSignerAddress1 },
);
@ -630,79 +530,16 @@ blockchainTests.resets('Mixins tests', env => {
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 () => {
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 () => {
it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid]`, async () => {
const orders = [defaultOrder, 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 approval1 = approvalFactory1.newSignedApproval(
transaction,
transactionSignerAddress,
approvalExpirationTimeSeconds,
);
const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const tx = mixins.assertValidCoordinatorApprovals.callAsync(
transaction,
transactionSignerAddress,
transaction.signature,
[approvalExpirationTimeSeconds],
[approval1.signature],
{ from: approvalSignerAddress2 },
);
@ -720,7 +557,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress,
transaction.signature,
[],
[],
{ from: transactionSignerAddress },
);
});
@ -733,7 +569,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress,
transaction.signature,
[],
[],
{ from: transactionSignerAddress },
);
});
@ -745,7 +580,6 @@ blockchainTests.resets('Mixins tests', env => {
transactionSignerAddress,
transaction.signature,
[],
[],
{ 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 { BigNumber } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util';
import { hashUtils, SignedCoordinatorApproval } from './index';
@ -17,21 +15,14 @@ export class ApprovalFactory {
public newSignedApproval(
transaction: SignedZeroExTransaction,
txOrigin: string,
approvalExpirationTimeSeconds: BigNumber,
signatureType: SignatureType = SignatureType.EthSign,
): SignedCoordinatorApproval {
const approvalHashBuff = hashUtils.getApprovalHashBuffer(
transaction,
this._verifyingContractAddress,
txOrigin,
approvalExpirationTimeSeconds,
);
const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, this._verifyingContractAddress, txOrigin);
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
const signedApproval = {
txOrigin,
transaction,
approvalExpirationTimeSeconds,
signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
signature: hexConcat(signatureBuff),
};
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[],
transaction: SignedZeroExTransaction,
txOrigin: string,
approvalExpirationTimeSeconds: BigNumber[],
approvalSignatures: string[],
txData: Partial<TxData>,
revertError?: RevertError,
@ -81,7 +80,6 @@ export class CoordinatorTestFactory {
transaction,
txOrigin,
transaction.signature,
approvalExpirationTimeSeconds,
approvalSignatures,
txData,
);
@ -106,7 +104,6 @@ export class CoordinatorTestFactory {
orders: SignedOrder[],
transaction: SignedZeroExTransaction,
txOrigin: string,
approvalExpirationTimeSeconds: BigNumber[],
approvalSignatures: string[],
txData: Partial<TxData>,
): Promise<void> {
@ -114,7 +111,6 @@ export class CoordinatorTestFactory {
transaction,
txOrigin,
transaction.signature,
approvalExpirationTimeSeconds,
approvalSignatures,
txData,
);

View File

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

View File

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

View File

@ -53,7 +53,10 @@ contract TestProtocolFeeCollector {
payable
{
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.
IEtherToken(_wethAddress).transferFrom(

View File

@ -25,8 +25,8 @@
"install:all": "yarn install",
"wsrun": "wsrun",
"lerna": "lerna",
"build": "lerna link && wsrun build $PKG -r --stages --fast-exit --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 --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",
"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:ts": "tsc -b",
@ -51,7 +51,7 @@
"lint:contracts": "wsrun lint -p ${npm_package_config_contractsPackages} -c --fast-exit --stages --exclude-missing"
},
"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",
"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",

View File

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

View File

@ -9,7 +9,6 @@ import {
SignedZeroExTransaction,
ZeroExTransaction,
} from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { constants } from './constants';
@ -99,14 +98,12 @@ export const eip712Utils = {
* @param transaction A 0x transaction
* @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 approvalExpirationTimeSeconds The approvals expiration time
* @return A typed data object
*/
createCoordinatorApprovalTypedData: (
transaction: SignedZeroExTransaction,
verifyingContract: string,
txOrigin: string,
approvalExpirationTimeSeconds: BigNumber,
): EIP712TypedData => {
const domain = {
...transaction.domain,
@ -119,7 +116,6 @@ export const eip712Utils = {
txOrigin,
transactionHash,
transactionSignature: transaction.signature,
approvalExpirationTimeSeconds: approvalExpirationTimeSeconds.toString(),
};
const typedData = eip712Utils.createTypedData(
constants.COORDINATOR_APPROVAL_SCHEMA.name,