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:
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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')),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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'],
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -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,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export {
|
|||||||
ZeroExTransaction,
|
ZeroExTransaction,
|
||||||
SignedZeroExTransaction,
|
SignedZeroExTransaction,
|
||||||
} from '@0x/types';
|
} from '@0x/types';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
OrderError,
|
OrderError,
|
||||||
TradeSide,
|
TradeSide,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user