Add ApprovalFactory class
This commit is contained in:
parent
bebcd99b3b
commit
f409780455
@ -16,5 +16,5 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"contracts": ["src/MixinSignatureValidator.sol", "src/TEC.sol", "test/TestLibs.sol"]
|
||||
"contracts": ["src/TEC.sol", "test/TestLibs.sol", "test/TestMixins.sol"]
|
||||
}
|
||||
|
29
contracts/tec/contracts/test/TestMixins.sol
Normal file
29
contracts/tec/contracts/test/TestMixins.sol
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
|
||||
Copyright 2018 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity 0.5.3;
|
||||
pragma experimental "ABIEncoderV2";
|
||||
|
||||
import "../src/MixinSignatureValidator.sol";
|
||||
import "../src/MixinTECApprovalVerifier.sol";
|
||||
|
||||
|
||||
contract TestMixins is
|
||||
MixinSignatureValidator,
|
||||
MixinTECApprovalVerifier
|
||||
{}
|
@ -33,7 +33,7 @@
|
||||
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
|
||||
},
|
||||
"config": {
|
||||
"abis": "./generated-artifacts/@(MixinSignatureValidator|TEC|TestLibs).json",
|
||||
"abis": "./generated-artifacts/@(IExchange|TEC|TestLibs|TestMixins).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
|
@ -5,11 +5,11 @@
|
||||
*/
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as MixinSignatureValidator from '../generated-artifacts/MixinSignatureValidator.json';
|
||||
import * as TEC from '../generated-artifacts/TEC.json';
|
||||
import * as TestLibs from '../generated-artifacts/TestLibs.json';
|
||||
import * as TestMixins from '../generated-artifacts/TestMixins.json';
|
||||
export const artifacts = {
|
||||
TestMixins: TestMixins as ContractArtifact,
|
||||
TEC: TEC as ContractArtifact,
|
||||
TestLibs: TestLibs as ContractArtifact,
|
||||
MixinSignatureValidator: MixinSignatureValidator as ContractArtifact,
|
||||
};
|
||||
|
@ -3,6 +3,6 @@
|
||||
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/mixin_signature_validator';
|
||||
export * from '../generated-wrappers/tec';
|
||||
export * from '../generated-wrappers/test_libs';
|
||||
export * from '../generated-wrappers/test_mixins';
|
||||
|
@ -3,7 +3,7 @@ import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { approvalHashUtils, artifacts, TestLibsContract } from '../src';
|
||||
import { artifacts, hashUtils, TestLibsContract } from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@ -36,7 +36,7 @@ describe('Libs tests', () => {
|
||||
signerAddress: constants.NULL_ADDRESS,
|
||||
data: '0x1234',
|
||||
};
|
||||
const expectedTxHash = approvalHashUtils._getTransactionHashHex(tx);
|
||||
const expectedTxHash = hashUtils.getTransactionHashHex(tx);
|
||||
const txHash = await testLibs.publicGetTransactionHash.callAsync(tx);
|
||||
expect(expectedTxHash).to.eq(txHash);
|
||||
});
|
||||
@ -53,11 +53,11 @@ describe('Libs tests', () => {
|
||||
};
|
||||
const approvalExpirationTimeSeconds = new BigNumber(0);
|
||||
const approval = {
|
||||
transactionHash: approvalHashUtils._getTransactionHashHex(signedTx),
|
||||
transactionHash: hashUtils.getTransactionHashHex(signedTx),
|
||||
transactionSignature: signedTx.signature,
|
||||
approvalExpirationTimeSeconds,
|
||||
};
|
||||
const expectedApprovalHash = approvalHashUtils.getApprovalHashHex(signedTx, approvalExpirationTimeSeconds);
|
||||
const expectedApprovalHash = hashUtils.getApprovalHashHex(signedTx, approvalExpirationTimeSeconds);
|
||||
const approvalHash = await testLibs.publicGetTECApprovalHash.callAsync(approval);
|
||||
expect(expectedApprovalHash).to.eq(approvalHash);
|
||||
});
|
||||
|
@ -7,13 +7,19 @@ import {
|
||||
web3Wrapper,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BlockchainLifecycle } from '@0x/dev-utils';
|
||||
import { transactionHashUtils } from '@0x/order-utils';
|
||||
import { RevertReason } from '@0x/types';
|
||||
import { RevertReason, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { artifacts, MixinSignatureValidatorContract, TECSignatureType, TECTransactionFactory } from '../src';
|
||||
import {
|
||||
ApprovalFactory,
|
||||
artifacts,
|
||||
hashUtils,
|
||||
TECSignatureType,
|
||||
TECTransactionFactory,
|
||||
TestMixinsContract,
|
||||
} from '../src';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
@ -22,8 +28,10 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
|
||||
describe('Mixins tests', () => {
|
||||
let transactionSignerAddress: string;
|
||||
let approvalSignerAddress: string;
|
||||
let signatureValidator: MixinSignatureValidatorContract;
|
||||
let mixins: TestMixinsContract;
|
||||
let transactionFactory: TECTransactionFactory;
|
||||
let approvalFactory: ApprovalFactory;
|
||||
let defaultOrder: SignedOrder;
|
||||
|
||||
before(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@ -32,16 +40,29 @@ describe('Mixins tests', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
before(async () => {
|
||||
signatureValidator = await MixinSignatureValidatorContract.deployFrom0xArtifactAsync(
|
||||
artifacts.MixinSignatureValidator,
|
||||
provider,
|
||||
txDefaults,
|
||||
);
|
||||
mixins = await TestMixinsContract.deployFrom0xArtifactAsync(artifacts.TestMixins, provider, txDefaults);
|
||||
const accounts = await web3Wrapper.getAvailableAddressesAsync();
|
||||
[transactionSignerAddress, approvalSignerAddress] = accounts.slice(0, 2);
|
||||
defaultOrder = {
|
||||
exchangeAddress: constants.NULL_ADDRESS,
|
||||
makerAddress: constants.NULL_ADDRESS,
|
||||
takerAddress: constants.NULL_ADDRESS,
|
||||
senderAddress: mixins.address,
|
||||
feeRecipientAddress: approvalSignerAddress,
|
||||
makerAssetData: constants.NULL_BYTES,
|
||||
takerAssetData: constants.NULL_BYTES,
|
||||
makerAssetAmount: constants.ZERO_AMOUNT,
|
||||
takerAssetAmount: constants.ZERO_AMOUNT,
|
||||
makerFee: constants.ZERO_AMOUNT,
|
||||
takerFee: constants.ZERO_AMOUNT,
|
||||
expirationTimeSeconds: constants.ZERO_AMOUNT,
|
||||
salt: constants.ZERO_AMOUNT,
|
||||
signature: constants.NULL_BYTES,
|
||||
};
|
||||
const transactionSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[0];
|
||||
const approvalSignerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[1];
|
||||
transactionFactory = new TECTransactionFactory(transactionSignerPrivateKey, signatureValidator.address);
|
||||
transactionFactory = new TECTransactionFactory(transactionSignerPrivateKey, mixins.address);
|
||||
approvalFactory = new ApprovalFactory(approvalSignerPrivateKey);
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await blockchainLifecycle.startAsync();
|
||||
@ -54,21 +75,15 @@ describe('Mixins tests', () => {
|
||||
it('should return the correct address using the EthSign signature type', async () => {
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data, TECSignatureType.EthSign);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const signerAddress = await signatureValidator.getSignerAddress.callAsync(
|
||||
transactionHash,
|
||||
transaction.signature,
|
||||
);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
|
||||
expect(transaction.signerAddress).to.eq(signerAddress);
|
||||
});
|
||||
it('should return the correct address using the EIP712 signature type', async () => {
|
||||
const data = constants.NULL_BYTES;
|
||||
const transaction = transactionFactory.newSignedTECTransaction(data, TECSignatureType.EIP712);
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const signerAddress = await signatureValidator.getSignerAddress.callAsync(
|
||||
transactionHash,
|
||||
transaction.signature,
|
||||
);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
|
||||
expect(transaction.signerAddress).to.eq(signerAddress);
|
||||
});
|
||||
it('should revert with with the Illegal signature type', async () => {
|
||||
@ -79,9 +94,9 @@ describe('Mixins tests', () => {
|
||||
0,
|
||||
transaction.signature.length - 2,
|
||||
)}${illegalSignatureByte}`;
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
expectContractCallFailedAsync(
|
||||
signatureValidator.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
RevertReason.SignatureIllegal,
|
||||
);
|
||||
});
|
||||
@ -93,11 +108,15 @@ describe('Mixins tests', () => {
|
||||
0,
|
||||
transaction.signature.length - 2,
|
||||
)}${invalidSignatureByte}`;
|
||||
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
expectContractCallFailedAsync(
|
||||
signatureValidator.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
|
||||
RevertReason.SignatureUnsupported,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assertValidSingleOrderApproval', () => {});
|
||||
describe('assertValidBatchOrderApproval', () => {});
|
||||
describe('assertValidTECApproval', () => {});
|
||||
});
|
||||
|
@ -0,0 +1,28 @@
|
||||
import { SignedZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { hashUtils, SignedTECApproval, signingUtils, TECSignatureType } from './index';
|
||||
|
||||
export class ApprovalFactory {
|
||||
private readonly _privateKey: Buffer;
|
||||
constructor(privateKey: Buffer) {
|
||||
this._privateKey = privateKey;
|
||||
}
|
||||
public newSignedApproval(
|
||||
transaction: SignedZeroExTransaction,
|
||||
approvalExpirationTimeSeconds: BigNumber,
|
||||
signatureType: TECSignatureType = TECSignatureType.EthSign,
|
||||
): SignedTECApproval {
|
||||
const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, approvalExpirationTimeSeconds);
|
||||
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
const signedApproval = {
|
||||
transactionHash,
|
||||
approvalExpirationTimeSeconds,
|
||||
transactionSignature: transaction.signature,
|
||||
approvalSignature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
|
||||
};
|
||||
return signedApproval;
|
||||
}
|
||||
}
|
@ -4,16 +4,16 @@ import { SignedZeroExTransaction, ZeroExTransaction } from '@0x/types';
|
||||
import { BigNumber, signTypedDataUtils } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { constants } from './index';
|
||||
|
||||
export const approvalHashUtils = {
|
||||
export const hashUtils = {
|
||||
getApprovalHashBuffer(transaction: SignedZeroExTransaction, approvalExpirationTimeSeconds: BigNumber): Buffer {
|
||||
const domain = {
|
||||
name: constants.TEC_DOMAIN_NAME,
|
||||
version: constants.TEC_DOMAIN_VERSION,
|
||||
verifyingContractAddress: transaction.verifyingContractAddress,
|
||||
};
|
||||
const transactionHash = approvalHashUtils._getTransactionHashHex(transaction);
|
||||
const transactionHash = hashUtils.getTransactionHashHex(transaction);
|
||||
const approval = {
|
||||
transactionHash,
|
||||
transactionSignature: transaction.signature,
|
||||
@ -31,12 +31,12 @@ export const approvalHashUtils = {
|
||||
return hashBuffer;
|
||||
},
|
||||
getApprovalHashHex(transaction: SignedZeroExTransaction, approvalExpirationTimeSeconds: BigNumber): string {
|
||||
const hashHex = `0x${approvalHashUtils
|
||||
const hashHex = `0x${hashUtils
|
||||
.getApprovalHashBuffer(transaction, approvalExpirationTimeSeconds)
|
||||
.toString('hex')}`;
|
||||
return hashHex;
|
||||
},
|
||||
_getTransactionHashBuffer(transaction: ZeroExTransaction | SignedZeroExTransaction): Buffer {
|
||||
getTransactionHashBuffer(transaction: ZeroExTransaction | SignedZeroExTransaction): Buffer {
|
||||
const domain = {
|
||||
name: constants.TEC_DOMAIN_NAME,
|
||||
version: constants.TEC_DOMAIN_VERSION,
|
||||
@ -54,8 +54,8 @@ export const approvalHashUtils = {
|
||||
const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
|
||||
return hashBuffer;
|
||||
},
|
||||
_getTransactionHashHex(transaction: ZeroExTransaction | SignedZeroExTransaction): string {
|
||||
const hashHex = `0x${approvalHashUtils._getTransactionHashBuffer(transaction).toString('hex')}`;
|
||||
getTransactionHashHex(transaction: ZeroExTransaction | SignedZeroExTransaction): string {
|
||||
const hashHex = `0x${hashUtils.getTransactionHashBuffer(transaction).toString('hex')}`;
|
||||
return hashHex;
|
||||
},
|
||||
};
|
@ -1,3 +1,6 @@
|
||||
export { approvalHashUtils } from './approval_hash';
|
||||
export { hashUtils } from './hash_utils';
|
||||
export { signingUtils } from './signing_utils';
|
||||
export { TECTransactionFactory } from './tec_transaction_factory';
|
||||
export { ApprovalFactory } from './approval_factory';
|
||||
export { constants } from './constants';
|
||||
export * from './types';
|
||||
|
30
contracts/tec/test/utils/signing_utils.ts
Normal file
30
contracts/tec/test/utils/signing_utils.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { TECSignatureType } from './types';
|
||||
|
||||
export const signingUtils = {
|
||||
signMessage(message: Buffer, privateKey: Buffer, signatureType: TECSignatureType): Buffer {
|
||||
if (signatureType === TECSignatureType.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 === TECSignatureType.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`);
|
||||
}
|
||||
},
|
||||
};
|
@ -1,31 +1,34 @@
|
||||
import { TransactionFactory } from '@0x/contracts-test-utils';
|
||||
import { SignatureType, SignedZeroExTransaction } from '@0x/types';
|
||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { SignedZeroExTransaction } from '@0x/types';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
|
||||
import { TECSignatureType } from './types';
|
||||
import { hashUtils, signingUtils, TECSignatureType } from './index';
|
||||
|
||||
export class TECTransactionFactory extends TransactionFactory {
|
||||
constructor(privateKey: Buffer, exchangeAddress: string) {
|
||||
super(privateKey, exchangeAddress);
|
||||
export class TECTransactionFactory {
|
||||
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 newSignedTECTransaction(
|
||||
data: string,
|
||||
signatureType: TECSignatureType = TECSignatureType.EthSign,
|
||||
): SignedZeroExTransaction {
|
||||
let exchangeSignatureType;
|
||||
if (signatureType === TECSignatureType.EthSign) {
|
||||
exchangeSignatureType = SignatureType.EthSign;
|
||||
} else if (signatureType === TECSignatureType.EIP712) {
|
||||
exchangeSignatureType = SignatureType.EIP712;
|
||||
} else {
|
||||
throw new Error(`Error: ${signatureType} not a valid signature type`);
|
||||
}
|
||||
const signedTransaction = super.newSignedTransaction(data, exchangeSignatureType);
|
||||
const tecSignatureTypeByte = ethUtil.toBuffer(signatureType).toString('hex');
|
||||
signedTransaction.signature = `${signedTransaction.signature.slice(
|
||||
0,
|
||||
signedTransaction.signature.length - 2,
|
||||
)}${tecSignatureTypeByte}`;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,10 @@ export interface TECApproval {
|
||||
approvalExpirationTimeSeconds: BigNumber;
|
||||
}
|
||||
|
||||
export interface SignedTECApproval extends TECApproval {
|
||||
approvalSignature: string;
|
||||
}
|
||||
|
||||
export enum TECSignatureType {
|
||||
Illegal,
|
||||
EIP712,
|
||||
|
@ -3,9 +3,9 @@
|
||||
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/MixinSignatureValidator.json",
|
||||
"generated-artifacts/TEC.json",
|
||||
"generated-artifacts/TestLibs.json"
|
||||
"generated-artifacts/TestLibs.json",
|
||||
"generated-artifacts/TestMixins.json"
|
||||
],
|
||||
"exclude": ["./deploy/solc/solc_bin"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user