Merge pull request #1705 from merklejerk/feature/contracts/coordinator-tx-eip712-mixed-domains

Separate domains for Coordinator transactions and approvals
This commit is contained in:
Amir Bandeali
2019-03-16 16:21:01 -07:00
committed by GitHub
25 changed files with 226 additions and 238 deletions

View File

@@ -4,6 +4,14 @@
"changes": [ "changes": [
{ {
"note": "Created Coordinator package" "note": "Created Coordinator package"
},
{
"note": "Use separate EIP712 domains for transactions and approvals",
"pr": 1705
},
{
"note": "Add `SignatureType.Invalid`",
"pr": 1705
} }
] ]
} }

View File

@@ -59,6 +59,17 @@ contract MixinSignatureValidator is
if (signatureType == SignatureType.Illegal) { if (signatureType == SignatureType.Illegal) {
revert("SIGNATURE_ILLEGAL"); revert("SIGNATURE_ILLEGAL");
// Always invalid signature.
// Like Illegal, this is always implicitly available and therefore
// offered explicitly. It can be implicitly created by providing
// a correctly formatted but incorrect signature.
} else if (signatureType == SignatureType.Invalid) {
require(
signature.length == 0,
"LENGTH_0_REQUIRED"
);
revert("SIGNATURE_INVALID");
// Signature using EIP712 // Signature using EIP712
} else if (signatureType == SignatureType.EIP712) { } else if (signatureType == SignatureType.EIP712) {
require( require(

View File

@@ -50,7 +50,7 @@ contract LibCoordinatorApproval is
view view
returns (bytes32 approvalHash) returns (bytes32 approvalHash)
{ {
approvalHash = hashEIP712Message(hashCoordinatorApproval(approval)); approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));
return approvalHash; return approvalHash;
} }

View File

@@ -18,17 +18,27 @@
pragma solidity ^0.5.5; pragma solidity ^0.5.5;
import "./LibConstants.sol";
contract LibEIP712Domain {
contract LibEIP712Domain is
LibConstants
{
// EIP191 header for EIP712 prefix // EIP191 header for EIP712 prefix
string constant internal EIP191_HEADER = "\x19\x01"; string constant internal EIP191_HEADER = "\x19\x01";
// EIP712 Domain Name value // EIP712 Domain Name value for the Coordinator
string constant internal EIP712_DOMAIN_NAME = "0x Protocol Coordinator"; string constant internal EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator";
// EIP712 Domain Version value // EIP712 Domain Version value for the Coordinator
string constant internal EIP712_DOMAIN_VERSION = "1.0.0"; string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = "1.0.0";
// EIP712 Domain Name value for the Exchange
string constant internal EIP712_EXCHANGE_DOMAIN_NAME = "0x Protocol";
// EIP712 Domain Version value for the Exchange
string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = "2";
// Hash of the EIP712 Domain Separator Schema // Hash of the EIP712 Domain Separator Schema
bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked( bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
@@ -39,31 +49,65 @@ contract LibEIP712Domain {
")" ")"
)); ));
// Hash of the EIP712 Domain Separator data // Hash of the EIP712 Domain Separator data for the Coordinator
// solhint-disable-next-line var-name-mixedcase // solhint-disable-next-line var-name-mixedcase
bytes32 public EIP712_DOMAIN_HASH; bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;
// Hash of the EIP712 Domain Separator data for the Exchange
// solhint-disable-next-line var-name-mixedcase
bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;
constructor () constructor ()
public public
{ {
EIP712_DOMAIN_HASH = keccak256(abi.encodePacked( EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH, EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(bytes(EIP712_DOMAIN_NAME)), keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),
keccak256(bytes(EIP712_DOMAIN_VERSION)), keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),
uint256(address(this)) uint256(address(this))
)); ));
EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(
EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),
keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),
uint256(address(EXCHANGE))
));
} }
/// @dev Calculates EIP712 encoding for a hash struct in this EIP712 Domain. /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
/// of this contract.
/// @param hashStruct The EIP712 hash struct. /// @param hashStruct The EIP712 hash struct.
/// @return EIP712 hash applied to this EIP712 Domain. /// @return EIP712 hash applied to this EIP712 Domain.
function hashEIP712Message(bytes32 hashStruct) function hashEIP712CoordinatorMessage(bytes32 hashStruct)
internal internal
view view
returns (bytes32 result) returns (bytes32 result)
{ {
bytes32 eip712DomainHash = EIP712_DOMAIN_HASH; return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);
}
/// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
/// of the Exchange contract.
/// @param hashStruct The EIP712 hash struct.
/// @return EIP712 hash applied to the Exchange EIP712 Domain.
function hashEIP712ExchangeMessage(bytes32 hashStruct)
internal
view
returns (bytes32 result)
{
return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);
}
/// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.
/// @param eip712DomainHash Hash of the domain domain separator data.
/// @param hashStruct The EIP712 hash struct.
/// @return EIP712 hash applied to the Exchange EIP712 Domain.
function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)
internal
pure
returns (bytes32 result)
{
// Assembly for more efficient computing: // Assembly for more efficient computing:
// keccak256(abi.encodePacked( // keccak256(abi.encodePacked(
// EIP191_HEADER, // EIP191_HEADER,

View File

@@ -48,8 +48,8 @@ contract LibZeroExTransaction is
view view
returns (bytes32 transactionHash) returns (bytes32 transactionHash)
{ {
// Note: this transaction hash will differ from the hash produced by the Exchange contract because it utilizes a different domain hash. // Hash the transaction with the domain separator of the Exchange contract.
transactionHash = hashEIP712Message(hashZeroExTransaction(transaction)); transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));
return transactionHash; return transactionHash;
} }

View File

@@ -27,8 +27,9 @@ contract MSignatureValidator is
// Allowed signature types. // Allowed signature types.
enum SignatureType { enum SignatureType {
Illegal, // 0x00, default value Illegal, // 0x00, default value
EIP712, // 0x01 Invalid, // 0x01
EthSign, // 0x02 EIP712, // 0x02
NSignatureTypes // 0x03, number of signature types. Always leave at end. EthSign, // 0x03
NSignatureTypes // 0x04, number of signature types. Always leave at end.
} }
} }

View File

@@ -19,14 +19,22 @@
pragma solidity ^0.5.5; pragma solidity ^0.5.5;
pragma experimental "ABIEncoderV2"; pragma experimental "ABIEncoderV2";
import "../src/libs/LibConstants.sol";
import "../src/libs/LibCoordinatorApproval.sol"; import "../src/libs/LibCoordinatorApproval.sol";
import "../src/libs/LibZeroExTransaction.sol"; import "../src/libs/LibZeroExTransaction.sol";
// solhint-disable no-empty-blocks
contract TestLibs is contract TestLibs is
LibConstants,
LibCoordinatorApproval, LibCoordinatorApproval,
LibZeroExTransaction LibZeroExTransaction
{ {
constructor (address _exchange)
public
LibConstants(_exchange)
{}
/// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract. /// @dev Calculated 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, transaction signature, and expiration of the approval.
/// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract. /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.
@@ -39,9 +47,9 @@ contract TestLibs is
return approvalHash; return approvalHash;
} }
/// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of this contract. /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.
/// @param transaction 0x transaction containing salt, signerAddress, and data. /// @param transaction 0x transaction containing salt, signerAddress, and data.
/// @return EIP712 hash of the transaction with the domain separator of this contract. /// @return EIP712 hash of the transaction with the domain separator of the Exchange contract.
function publicGetTransactionHash(ZeroExTransaction memory transaction) function publicGetTransactionHash(ZeroExTransaction memory transaction)
public public
view view

View File

@@ -19,12 +19,19 @@
pragma solidity ^0.5.5; pragma solidity ^0.5.5;
pragma experimental "ABIEncoderV2"; pragma experimental "ABIEncoderV2";
import "../src/libs/LibConstants.sol";
import "../src/MixinSignatureValidator.sol"; import "../src/MixinSignatureValidator.sol";
import "../src/MixinCoordinatorApprovalVerifier.sol"; import "../src/MixinCoordinatorApprovalVerifier.sol";
// solhint-disable no-empty-blocks // solhint-disable no-empty-blocks
contract TestMixins is contract TestMixins is
LibConstants,
MixinSignatureValidator, MixinSignatureValidator,
MixinCoordinatorApprovalVerifier MixinCoordinatorApprovalVerifier
{} {
constructor (address _exchange)
public
LibConstants(_exchange)
{}
}

View File

@@ -1,5 +1,6 @@
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; import { addressUtils, chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils'; import { BlockchainLifecycle } from '@0x/dev-utils';
import { transactionHashUtils } from '@0x/order-utils';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as chai from 'chai'; import * as chai from 'chai';
@@ -11,6 +12,7 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('Libs tests', () => { describe('Libs tests', () => {
let testLibs: TestLibsContract; let testLibs: TestLibsContract;
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
before(async () => { before(async () => {
await blockchainLifecycle.startAsync(); await blockchainLifecycle.startAsync();
@@ -19,7 +21,12 @@ describe('Libs tests', () => {
await blockchainLifecycle.revertAsync(); await blockchainLifecycle.revertAsync();
}); });
before(async () => { before(async () => {
testLibs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); testLibs = await TestLibsContract.deployFrom0xArtifactAsync(
artifacts.TestLibs,
provider,
txDefaults,
exchangeAddress,
);
}); });
beforeEach(async () => { beforeEach(async () => {
await blockchainLifecycle.startAsync(); await blockchainLifecycle.startAsync();
@@ -31,12 +38,12 @@ describe('Libs tests', () => {
describe('getTransactionHash', () => { describe('getTransactionHash', () => {
it('should return the correct transaction hash', async () => { it('should return the correct transaction hash', async () => {
const tx = { const tx = {
verifyingContractAddress: testLibs.address, verifyingContractAddress: exchangeAddress,
salt: new BigNumber(0), salt: new BigNumber(0),
signerAddress: constants.NULL_ADDRESS, signerAddress: constants.NULL_ADDRESS,
data: '0x1234', data: '0x1234',
}; };
const expectedTxHash = hashUtils.getTransactionHashHex(tx); const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx);
const txHash = await testLibs.publicGetTransactionHash.callAsync(tx); const txHash = await testLibs.publicGetTransactionHash.callAsync(tx);
expect(expectedTxHash).to.eq(txHash); expect(expectedTxHash).to.eq(txHash);
}); });
@@ -45,7 +52,7 @@ describe('Libs tests', () => {
describe('getApprovalHash', () => { describe('getApprovalHash', () => {
it('should return the correct approval hash', async () => { it('should return the correct approval hash', async () => {
const signedTx = { const signedTx = {
verifyingContractAddress: testLibs.address, verifyingContractAddress: exchangeAddress,
salt: new BigNumber(0), salt: new BigNumber(0),
signerAddress: constants.NULL_ADDRESS, signerAddress: constants.NULL_ADDRESS,
data: '0x1234', data: '0x1234',
@@ -55,12 +62,13 @@ describe('Libs tests', () => {
const txOrigin = constants.NULL_ADDRESS; const txOrigin = constants.NULL_ADDRESS;
const approval = { const approval = {
txOrigin, txOrigin,
transactionHash: hashUtils.getTransactionHashHex(signedTx), transactionHash: transactionHashUtils.getTransactionHashHex(signedTx),
transactionSignature: signedTx.signature, transactionSignature: signedTx.signature,
approvalExpirationTimeSeconds, approvalExpirationTimeSeconds,
}; };
const expectedApprovalHash = hashUtils.getApprovalHashHex( const expectedApprovalHash = hashUtils.getApprovalHashHex(
signedTx, signedTx,
testLibs.address,
txOrigin, txOrigin,
approvalExpirationTimeSeconds, approvalExpirationTimeSeconds,
); );

View File

@@ -1,28 +1,22 @@
import { import {
addressUtils,
chaiSetup, chaiSetup,
constants as devConstants, constants as devConstants,
expectContractCallFailedAsync, expectContractCallFailedAsync,
getLatestBlockTimestampAsync, getLatestBlockTimestampAsync,
provider, provider,
TransactionFactory,
txDefaults, txDefaults,
web3Wrapper, web3Wrapper,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils'; import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason, SignedOrder } from '@0x/types'; import { transactionHashUtils } from '@0x/order-utils';
import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as chai from 'chai'; import * as chai from 'chai';
import * as ethUtil from 'ethereumjs-util'; import * as ethUtil from 'ethereumjs-util';
import { import { ApprovalFactory, artifacts, constants, exchangeDataEncoder, TestMixinsContract } from '../src';
ApprovalFactory,
artifacts,
constants,
CoordinatorSignatureType,
CoordinatorTransactionFactory,
exchangeDataEncoder,
hashUtils,
TestMixinsContract,
} from '../src';
chaiSetup.configure(); chaiSetup.configure();
const expect = chai.expect; const expect = chai.expect;
@@ -33,10 +27,12 @@ describe('Mixins tests', () => {
let approvalSignerAddress1: string; let approvalSignerAddress1: string;
let approvalSignerAddress2: string; let approvalSignerAddress2: string;
let mixins: TestMixinsContract; let mixins: TestMixinsContract;
let transactionFactory: CoordinatorTransactionFactory; let transactionFactory: TransactionFactory;
let approvalFactory1: ApprovalFactory; let approvalFactory1: ApprovalFactory;
let approvalFactory2: ApprovalFactory; let approvalFactory2: ApprovalFactory;
let defaultOrder: SignedOrder; let defaultOrder: SignedOrder;
const exchangeAddress = addressUtils.generatePseudoRandomAddress();
before(async () => { before(async () => {
await blockchainLifecycle.startAsync(); await blockchainLifecycle.startAsync();
}); });
@@ -44,7 +40,12 @@ describe('Mixins tests', () => {
await blockchainLifecycle.revertAsync(); await blockchainLifecycle.revertAsync();
}); });
before(async () => { before(async () => {
mixins = await TestMixinsContract.deployFrom0xArtifactAsync(artifacts.TestMixins, provider, txDefaults); mixins = await TestMixinsContract.deployFrom0xArtifactAsync(
artifacts.TestMixins,
provider,
txDefaults,
exchangeAddress,
);
const accounts = await web3Wrapper.getAvailableAddressesAsync(); const accounts = await web3Wrapper.getAvailableAddressesAsync();
[transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3); [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3);
defaultOrder = { defaultOrder = {
@@ -67,7 +68,7 @@ describe('Mixins tests', () => {
devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)]; devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)];
const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)]; const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)];
const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)]; const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)];
transactionFactory = new CoordinatorTransactionFactory(transactionSignerPrivateKey, mixins.address); transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress);
approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address); approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address);
approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address); approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address);
}); });
@@ -81,47 +82,52 @@ describe('Mixins tests', () => {
describe('getSignerAddress', () => { describe('getSignerAddress', () => {
it('should return the correct address using the EthSign signature type', async () => { it('should return the correct address using the EthSign signature type', async () => {
const data = devConstants.NULL_BYTES; const data = devConstants.NULL_BYTES;
const transaction = transactionFactory.newSignedCoordinatorTransaction( const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EthSign);
data, const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
CoordinatorSignatureType.EthSign,
);
const transactionHash = hashUtils.getTransactionHashHex(transaction);
const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature); const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
expect(transaction.signerAddress).to.eq(signerAddress); expect(transaction.signerAddress).to.eq(signerAddress);
}); });
it('should return the correct address using the EIP712 signature type', async () => { it('should return the correct address using the EIP712 signature type', async () => {
const data = devConstants.NULL_BYTES; const data = devConstants.NULL_BYTES;
const transaction = transactionFactory.newSignedCoordinatorTransaction( const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EIP712);
data, const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
CoordinatorSignatureType.EIP712,
);
const transactionHash = hashUtils.getTransactionHashHex(transaction);
const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature); const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
expect(transaction.signerAddress).to.eq(signerAddress); expect(transaction.signerAddress).to.eq(signerAddress);
}); });
it('should revert with with the Illegal signature type', async () => { it('should revert with with the Illegal signature type', async () => {
const data = devConstants.NULL_BYTES; const data = devConstants.NULL_BYTES;
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const illegalSignatureByte = ethUtil.toBuffer(CoordinatorSignatureType.Illegal).toString('hex'); const illegalSignatureByte = ethUtil.toBuffer(SignatureType.Illegal).toString('hex');
transaction.signature = `${transaction.signature.slice( transaction.signature = `${transaction.signature.slice(
0, 0,
transaction.signature.length - 2, transaction.signature.length - 2,
)}${illegalSignatureByte}`; )}${illegalSignatureByte}`;
const transactionHash = hashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expectContractCallFailedAsync( expectContractCallFailedAsync(
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature), mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
RevertReason.SignatureIllegal, RevertReason.SignatureIllegal,
); );
}); });
it('should revert with with the Invalid signature type', async () => {
const data = devConstants.NULL_BYTES;
const transaction = transactionFactory.newSignedTransaction(data);
const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex');
transaction.signature = `0x${invalidSignatureByte}`;
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expectContractCallFailedAsync(
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
RevertReason.SignatureInvalid,
);
});
it("should revert with with a signature type that doesn't exist", async () => { it("should revert with with a signature type that doesn't exist", async () => {
const data = devConstants.NULL_BYTES; const data = devConstants.NULL_BYTES;
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const invalidSignatureByte = '03'; const invalidSignatureByte = '04';
transaction.signature = `${transaction.signature.slice( transaction.signature = `${transaction.signature.slice(
0, 0,
transaction.signature.length - 2, transaction.signature.length - 2,
)}${invalidSignatureByte}`; )}${invalidSignatureByte}`;
const transactionHash = hashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expectContractCallFailedAsync( expectContractCallFailedAsync(
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature), mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
RevertReason.SignatureUnsupported, RevertReason.SignatureUnsupported,
@@ -134,7 +140,7 @@ describe('Mixins tests', () => {
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], expiration=[valid]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -167,7 +173,7 @@ describe('Mixins tests', () => {
}; };
const orders = [order]; const orders = [order];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -196,7 +202,7 @@ describe('Mixins tests', () => {
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=[], expiration=[]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidTransactionOrdersApproval.callAsync( await mixins.assertValidTransactionOrdersApproval.callAsync(
transaction, transaction,
orders, orders,
@@ -220,7 +226,7 @@ describe('Mixins tests', () => {
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], expiration=[invalid]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -249,7 +255,7 @@ describe('Mixins tests', () => {
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=[], expiration=[]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidTransactionOrdersApproval.callAsync( await mixins.assertValidTransactionOrdersApproval.callAsync(
transaction, transaction,
orders, orders,
@@ -273,7 +279,7 @@ describe('Mixins tests', () => {
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], expiration=[valid]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -309,7 +315,7 @@ describe('Mixins tests', () => {
it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => { it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -344,7 +350,7 @@ describe('Mixins tests', () => {
it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => { it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -387,7 +393,7 @@ describe('Mixins tests', () => {
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], 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -419,7 +425,7 @@ describe('Mixins tests', () => {
senderAddress: devConstants.NULL_ADDRESS, senderAddress: devConstants.NULL_ADDRESS,
})); }));
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -451,7 +457,7 @@ describe('Mixins tests', () => {
senderAddress: devConstants.NULL_ADDRESS, senderAddress: devConstants.NULL_ADDRESS,
})); }));
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidTransactionOrdersApproval.callAsync( await mixins.assertValidTransactionOrdersApproval.callAsync(
transaction, transaction,
orders, orders,
@@ -473,7 +479,7 @@ describe('Mixins tests', () => {
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], expiration=[valid]`, async () => {
const orders = [defaultOrder, { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS }]; const orders = [defaultOrder, { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -502,7 +508,7 @@ describe('Mixins tests', () => {
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], expiration=[valid,valid]`, 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval1 = approvalFactory1.newSignedApproval( const approval1 = approvalFactory1.newSignedApproval(
@@ -536,7 +542,7 @@ describe('Mixins tests', () => {
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=[], expiration=[]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidTransactionOrdersApproval.callAsync( await mixins.assertValidTransactionOrdersApproval.callAsync(
transaction, transaction,
orders, orders,
@@ -558,7 +564,7 @@ describe('Mixins tests', () => {
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], expiration=[valid]`, 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval2 = approvalFactory2.newSignedApproval( const approval2 = approvalFactory2.newSignedApproval(
@@ -593,7 +599,7 @@ describe('Mixins tests', () => {
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=[], expiration=[]`, async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
expectContractCallFailedAsync( expectContractCallFailedAsync(
mixins.assertValidTransactionOrdersApproval.callAsync( mixins.assertValidTransactionOrdersApproval.callAsync(
transaction, transaction,
@@ -621,7 +627,7 @@ describe('Mixins tests', () => {
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], 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval = approvalFactory1.newSignedApproval( const approval = approvalFactory1.newSignedApproval(
@@ -657,7 +663,7 @@ describe('Mixins tests', () => {
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], expiration=[valid,valid]`, 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval1 = approvalFactory1.newSignedApproval( const approval1 = approvalFactory1.newSignedApproval(
@@ -698,7 +704,7 @@ describe('Mixins tests', () => {
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], expiration=[valid]`, 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval2 = approvalFactory2.newSignedApproval( const approval2 = approvalFactory2.newSignedApproval(
@@ -734,7 +740,7 @@ describe('Mixins tests', () => {
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=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
@@ -775,7 +781,7 @@ describe('Mixins tests', () => {
it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => { 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 orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
const approval2 = approvalFactory2.newSignedApproval( const approval2 = approvalFactory2.newSignedApproval(
@@ -810,7 +816,7 @@ describe('Mixins tests', () => {
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], 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 = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
const currentTimestamp = await getLatestBlockTimestampAsync(); const currentTimestamp = await getLatestBlockTimestampAsync();
const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER); const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
const approval1 = approvalFactory1.newSignedApproval( const approval1 = approvalFactory1.newSignedApproval(
@@ -848,7 +854,7 @@ describe('Mixins tests', () => {
it('should allow the tx signer to call `cancelOrders` without approval', async () => { it('should allow the tx signer to call `cancelOrders` without approval', async () => {
const orders = [defaultOrder]; const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
@@ -861,7 +867,7 @@ describe('Mixins tests', () => {
it('should allow the tx signer to call `batchCancelOrders` without approval', async () => { it('should allow the tx signer to call `batchCancelOrders` without approval', async () => {
const orders = [defaultOrder, defaultOrder]; const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,
@@ -874,7 +880,7 @@ describe('Mixins tests', () => {
it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => { it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => {
const orders: SignedOrder[] = []; const orders: SignedOrder[] = [];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders); const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders);
const transaction = transactionFactory.newSignedCoordinatorTransaction(data); const transaction = transactionFactory.newSignedTransaction(data);
await mixins.assertValidCoordinatorApprovals.callAsync( await mixins.assertValidCoordinatorApprovals.callAsync(
transaction, transaction,
transactionSignerAddress, transactionSignerAddress,

View File

@@ -1,35 +1,35 @@
import { SignedZeroExTransaction } from '@0x/types'; import { signingUtils } from '@0x/contracts-test-utils';
import { SignatureType, SignedZeroExTransaction } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util'; import * as ethUtil from 'ethereumjs-util';
import { CoordinatorSignatureType, hashUtils, SignedCoordinatorApproval, signingUtils } from './index'; import { hashUtils, SignedCoordinatorApproval } from './index';
export class ApprovalFactory { export class ApprovalFactory {
private readonly _privateKey: Buffer; private readonly _privateKey: Buffer;
private readonly _verifyingContractAddress: string; private readonly _verifyingContractAddress: string;
constructor(privateKey: Buffer, verifyingContractAddress: string) { constructor(privateKey: Buffer, verifyingContractAddress: string) {
this._privateKey = privateKey; this._privateKey = privateKey;
this._verifyingContractAddress = verifyingContractAddress; this._verifyingContractAddress = verifyingContractAddress;
} }
public newSignedApproval( public newSignedApproval(
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber, approvalExpirationTimeSeconds: BigNumber,
signatureType: CoordinatorSignatureType = CoordinatorSignatureType.EthSign, signatureType: SignatureType = SignatureType.EthSign,
): SignedCoordinatorApproval { ): SignedCoordinatorApproval {
const coordinatorTransaction = {
...transaction,
verifyingContractAddress: this._verifyingContractAddress,
};
const approvalHashBuff = hashUtils.getApprovalHashBuffer( const approvalHashBuff = hashUtils.getApprovalHashBuffer(
coordinatorTransaction, transaction,
this._verifyingContractAddress,
txOrigin, txOrigin,
approvalExpirationTimeSeconds, approvalExpirationTimeSeconds,
); );
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType); const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
const signedApproval = { const signedApproval = {
txOrigin, txOrigin,
transaction: coordinatorTransaction, transaction,
approvalExpirationTimeSeconds, approvalExpirationTimeSeconds,
signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')), signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
}; };

View File

@@ -1,17 +1,6 @@
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
export const constants = { export const constants = {
COORDINATOR_DOMAIN_NAME: '0x Protocol Coordinator',
COORDINATOR_DOMAIN_VERSION: '1.0.0',
COORDINATOR_APPROVAL_SCHEMA: {
name: 'CoordinatorApproval',
parameters: [
{ name: 'txOrigin', type: 'address' },
{ name: 'transactionHash', type: 'bytes32' },
{ name: 'transactionSignature', type: 'bytes' },
{ name: 'approvalExpirationTimeSeconds', type: 'uint256' },
],
},
SINGLE_FILL_FN_NAMES: ['fillOrder', 'fillOrKillOrder', 'fillOrderNoThrow'], SINGLE_FILL_FN_NAMES: ['fillOrder', 'fillOrKillOrder', 'fillOrderNoThrow'],
BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'], BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'],
MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'], MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'],

View File

@@ -1,34 +0,0 @@
import { generatePseudoRandomSalt } from '@0x/order-utils';
import { SignedZeroExTransaction } from '@0x/types';
import * as ethUtil from 'ethereumjs-util';
import { CoordinatorSignatureType, hashUtils, signingUtils } from './index';
export class CoordinatorTransactionFactory {
private readonly _signerBuff: Buffer;
private readonly _verifyingContractAddress: string;
private readonly _privateKey: Buffer;
constructor(privateKey: Buffer, verifyingContractAddress: string) {
this._privateKey = privateKey;
this._verifyingContractAddress = verifyingContractAddress;
this._signerBuff = ethUtil.privateToAddress(this._privateKey);
}
public newSignedCoordinatorTransaction(
data: string,
signatureType: CoordinatorSignatureType = CoordinatorSignatureType.EthSign,
): SignedZeroExTransaction {
const transaction = {
verifyingContractAddress: this._verifyingContractAddress,
signerAddress: ethUtil.addHexPrefix(this._signerBuff.toString('hex')),
salt: generatePseudoRandomSalt(),
data,
};
const transactionHashBuff = hashUtils.getTransactionHashBuffer(transaction);
const signatureBuff = signingUtils.signMessage(transactionHashBuff, this._privateKey, signatureType);
const signedTransaction = {
...transaction,
signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
};
return signedTransaction;
}
}

View File

@@ -1,23 +1,22 @@
import { eip712Utils } from '@0x/order-utils'; import { eip712Utils, transactionHashUtils } from '@0x/order-utils';
import { constants as orderUtilsConstants } from '@0x/order-utils/lib/src/constants'; import { constants } from '@0x/order-utils/lib/src/constants';
import { SignedZeroExTransaction, ZeroExTransaction } from '@0x/types'; import { SignedZeroExTransaction } from '@0x/types';
import { BigNumber, signTypedDataUtils } from '@0x/utils'; import { BigNumber, signTypedDataUtils } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { constants } from './index';
export const hashUtils = { export const hashUtils = {
getApprovalHashBuffer( getApprovalHashBuffer(
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
verifyingContractAddress: string,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber, approvalExpirationTimeSeconds: BigNumber,
): Buffer { ): Buffer {
const domain = { const domain = {
name: constants.COORDINATOR_DOMAIN_NAME, name: constants.COORDINATOR_DOMAIN_NAME,
version: constants.COORDINATOR_DOMAIN_VERSION, version: constants.COORDINATOR_DOMAIN_VERSION,
verifyingContractAddress: transaction.verifyingContractAddress, verifyingContractAddress,
}; };
const transactionHash = hashUtils.getTransactionHashHex(transaction); const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
const approval = { const approval = {
txOrigin, txOrigin,
transactionHash, transactionHash,
@@ -37,34 +36,13 @@ export const hashUtils = {
}, },
getApprovalHashHex( getApprovalHashHex(
transaction: SignedZeroExTransaction, transaction: SignedZeroExTransaction,
verifyingContractAddress: string,
txOrigin: string, txOrigin: string,
approvalExpirationTimeSeconds: BigNumber, approvalExpirationTimeSeconds: BigNumber,
): string { ): string {
const hashHex = `0x${hashUtils const hashHex = `0x${hashUtils
.getApprovalHashBuffer(transaction, txOrigin, approvalExpirationTimeSeconds) .getApprovalHashBuffer(transaction, verifyingContractAddress, txOrigin, approvalExpirationTimeSeconds)
.toString('hex')}`; .toString('hex')}`;
return hashHex; return hashHex;
}, },
getTransactionHashBuffer(transaction: ZeroExTransaction | SignedZeroExTransaction): Buffer {
const domain = {
name: constants.COORDINATOR_DOMAIN_NAME,
version: constants.COORDINATOR_DOMAIN_VERSION,
verifyingContractAddress: transaction.verifyingContractAddress,
};
const normalizedTransaction = _.mapValues(transaction, value => {
return !_.isString(value) ? value.toString() : value;
});
const typedData = eip712Utils.createTypedData(
orderUtilsConstants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.name,
{ ZeroExTransaction: orderUtilsConstants.EXCHANGE_ZEROEX_TRANSACTION_SCHEMA.parameters },
normalizedTransaction,
domain,
);
const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
return hashBuffer;
},
getTransactionHashHex(transaction: ZeroExTransaction | SignedZeroExTransaction): string {
const hashHex = `0x${hashUtils.getTransactionHashBuffer(transaction).toString('hex')}`;
return hashHex;
},
}; };

View File

@@ -1,6 +1,4 @@
export { hashUtils } from './hash_utils'; export { hashUtils } from './hash_utils';
export { signingUtils } from './signing_utils';
export { CoordinatorTransactionFactory } from './coordinator_transaction_factory';
export { ApprovalFactory } from './approval_factory'; export { ApprovalFactory } from './approval_factory';
export { constants } from './constants'; export { constants } from './constants';
export { exchangeDataEncoder } from './exchange_data_encoder'; export { exchangeDataEncoder } from './exchange_data_encoder';

View File

@@ -1,30 +0,0 @@
import * as ethUtil from 'ethereumjs-util';
import { CoordinatorSignatureType } from './types';
export const signingUtils = {
signMessage(message: Buffer, privateKey: Buffer, signatureType: CoordinatorSignatureType): Buffer {
if (signatureType === CoordinatorSignatureType.EthSign) {
const prefixedMessage = ethUtil.hashPersonalMessage(message);
const ecSignature = ethUtil.ecsign(prefixedMessage, privateKey);
const signature = Buffer.concat([
ethUtil.toBuffer(ecSignature.v),
ecSignature.r,
ecSignature.s,
ethUtil.toBuffer(signatureType),
]);
return signature;
} else if (signatureType === CoordinatorSignatureType.EIP712) {
const ecSignature = ethUtil.ecsign(message, privateKey);
const signature = Buffer.concat([
ethUtil.toBuffer(ecSignature.v),
ecSignature.r,
ecSignature.s,
ethUtil.toBuffer(signatureType),
]);
return signature;
} else {
throw new Error(`${signatureType} is not a valid signature type`);
}
},
};

View File

@@ -10,10 +10,3 @@ export interface CoordinatorApproval {
export interface SignedCoordinatorApproval extends CoordinatorApproval { export interface SignedCoordinatorApproval extends CoordinatorApproval {
signature: string; signature: string;
} }
export enum CoordinatorSignatureType {
Illegal,
EIP712,
EthSign,
NSignatureTypes,
}

View File

@@ -14,6 +14,10 @@
{ {
"note": "Set evmVersion to byzantium", "note": "Set evmVersion to byzantium",
"pr": 1678 "pr": 1678
},
{
"note": "Remove Coordinator EIP712 constants. They're now in the `order-utils` package.",
"pr": 1705
} }
] ]
}, },

View File

@@ -70,14 +70,4 @@ export const constants = {
'CANCEL_ORDERS_UP_TO', 'CANCEL_ORDERS_UP_TO',
'SET_SIGNATURE_VALIDATOR_APPROVAL', 'SET_SIGNATURE_VALIDATOR_APPROVAL',
], ],
COORDINATOR_DOMAIN_NAME: '0x Protocol Trade Execution Coordinator',
COORDINATOR_DOMAIN_VERSION: '1.0.0',
COORDINATOR_APPROVAL_SCHEMA: {
name: 'COORDINATORApproval',
parameters: [
{ name: 'transactionHash', type: 'bytes32' },
{ name: 'transactionSignature', type: 'bytes' },
{ name: 'approvalExpirationTimeSeconds', type: 'uint256' },
],
},
}; };

View File

@@ -2,6 +2,10 @@
{ {
"version": "7.1.0", "version": "7.1.0",
"changes": [ "changes": [
{
"note": "Add Coordinator EIP712 constants",
"pr": 1705
},
{ {
"note": "Added encoding/decoding fdor ERC1155 asset data", "note": "Added encoding/decoding fdor ERC1155 asset data",
"pr": 1661 "pr": 1661

View File

@@ -103,6 +103,17 @@ export const constants = {
{ name: 'data', type: 'bytes' }, { name: 'data', type: 'bytes' },
], ],
}, },
COORDINATOR_DOMAIN_NAME: '0x Protocol Coordinator',
COORDINATOR_DOMAIN_VERSION: '1.0.0',
COORDINATOR_APPROVAL_SCHEMA: {
name: 'CoordinatorApproval',
parameters: [
{ name: 'txOrigin', type: 'address' },
{ name: 'transactionHash', type: 'bytes32' },
{ name: 'transactionSignature', type: 'bytes' },
{ name: 'approvalExpirationTimeSeconds', type: 'uint256' },
],
},
ERC20_METHOD_ABI, ERC20_METHOD_ABI,
ERC721_METHOD_ABI, ERC721_METHOD_ABI,
MULTI_ASSET_METHOD_ABI, MULTI_ASSET_METHOD_ABI,

View File

@@ -65,6 +65,7 @@ export {
ZeroExTransaction, ZeroExTransaction,
SignedZeroExTransaction, SignedZeroExTransaction,
} from '@0x/types'; } from '@0x/types';
export { export {
OrderError, OrderError,
TradeSide, TradeSide,

View File

@@ -1,6 +1,6 @@
[ [
{ {
"version": "2.2.2", "version": "2.2.0",
"changes": [ "changes": [
{ {
"note": "Added ERC1155 revert reasons", "note": "Added ERC1155 revert reasons",
@@ -9,24 +9,14 @@
{ {
"note": "Added `ERC1155AssetData`, `ERC1155AssetDataNoProxyId`, and `ERC1155AssetDataAbi`", "note": "Added `ERC1155AssetData`, `ERC1155AssetDataNoProxyId`, and `ERC1155AssetDataAbi`",
"pr": 1661 "pr": 1661
} },
]
},
{
"version": "2.2.1",
"changes": [
{
"note": "Added ERC1155 revert reasons",
"pr": 1657
}
]
},
{
"version": "2.2.0",
"changes": [
{ {
"note": "Add `InvalidOrigin` revert reason", "note": "Add `InvalidOrigin` revert reason",
"pr": 1668 "pr": 1668
},
{
"note": "Add `RevertReason.SignatureInvalid` thrown by Coordinator",
"pr": 1705
} }
] ]
}, },

View File

@@ -227,6 +227,7 @@ export enum RevertReason {
RoundingError = 'ROUNDING_ERROR', RoundingError = 'ROUNDING_ERROR',
InvalidSignature = 'INVALID_SIGNATURE', InvalidSignature = 'INVALID_SIGNATURE',
SignatureIllegal = 'SIGNATURE_ILLEGAL', SignatureIllegal = 'SIGNATURE_ILLEGAL',
SignatureInvalid = 'SIGNATURE_INVALID',
SignatureUnsupported = 'SIGNATURE_UNSUPPORTED', SignatureUnsupported = 'SIGNATURE_UNSUPPORTED',
TakerOverpay = 'TAKER_OVERPAY', TakerOverpay = 'TAKER_OVERPAY',
OrderOverfill = 'ORDER_OVERFILL', OrderOverfill = 'ORDER_OVERFILL',