Skip to content
This repository has been archived by the owner on Mar 16, 2023. It is now read-only.

Commit

Permalink
feat(aztec.js): add permit signing function
Browse files Browse the repository at this point in the history
add associated test
tidy up other MetaMask comparison tests
  • Loading branch information
thomas-waite committed Feb 20, 2020
1 parent 20973d5 commit ee9eea2
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 44 deletions.
28 changes: 28 additions & 0 deletions packages/aztec.js/src/signer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,34 @@ signer.signNoteACEDomain = (verifyingContract, spender, privateKey) => {
return { signature, encodedTypedData };
};

/**
* Allows a user to create a signature for use in the DAI.permit() function. Creates an EIP712 ECDSA
* signature
*
* @method signPermit
* @param {Object} holderAccount - address that owns the tokens, which is approving a spender to spend
* @param {Address} spender - address being approved to spend the tokens
* @param {Number} nonce - nonce of the transaction. Used for replay protection in the DAI token contract
* @param {Number} expiry - unix timestamp corresponding to the upper boundary for when the permit is valid
* @param {Bool} allowed - whether approval is being granted or revoked
*/
signer.signPermit = (verifyingContract, holderAccount, spender, nonce, expiry, allowed) => {
const { address: holder, privateKey } = holderAccount;
const domain = signer.generateAccountRegistryDomainParams(verifyingContract);
const schema = constants.eip712.PERMIT_SIGNATURE;

const message = {
holder,
spender,
nonce,
expiry,
allowed,
};

const { unformattedSignature } = signer.signTypedData(domain, schema, message, privateKey);
return `0x${unformattedSignature.slice(0, 130)}`;
};

/**
* Create an EIP712 ECDSA signature over structured data. This is a low level function that returns the signature parameters
* in an unstructured form - `r`, `s` and `v` are all 32 bytes in size.
Expand Down
88 changes: 44 additions & 44 deletions packages/aztec.js/test/signer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,25 +235,12 @@ describe('Signer', () => {
const testNoteValue = 10;
const testNote = await note.create(aztecAccount.publicKey, testNoteValue);

const domain = signer.generateZKAssetDomainParams(verifyingContract);
const { types, primaryType } = constants.eip712.NOTE_SIGNATURE;
const metaMaskTypedData = {
domain: {
name: 'ZK_ASSET',
version: '1',
verifyingContract,
},
types: {
NoteSignature: [
{ name: 'noteHash', type: 'bytes32' },
{ name: 'spender', type: 'address' },
{ name: 'spenderApproval', type: 'bool' },
],
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'verifyingContract', type: 'address' },
],
},
primaryType: 'NoteSignature',
domain,
types,
primaryType,
message: {
noteHash: testNote.noteHash,
spender,
Expand All @@ -280,8 +267,8 @@ describe('Signer', () => {
const aztecAccount = secp256k1.generateAccount();
const spender = randomHex(20);
const verifyingContract = randomHex(20);

const joinSplitProof = randomHex(20);
const proofHash = keccak256(joinSplitProof);

const aztecSignature = signer.signApprovalForProof(
verifyingContract,
Expand All @@ -291,41 +278,54 @@ describe('Signer', () => {
aztecAccount.privateKey,
);

const proofHash = keccak256(joinSplitProof);

const message = {
proofHash,
spender,
approval: true,
};

const domain = signer.generateZKAssetDomainParams(verifyingContract);
const { types, primaryType } = constants.eip712.PROOF_SIGNATURE;
const metaMaskTypedData = {
domain: {
name: 'ZK_ASSET',
version: '1',
verifyingContract,
},
types: {
ProofSignature: [
{ name: 'proofHash', type: 'bytes32' },
{ name: 'spender', type: 'address' },
{ name: 'approval', type: 'bool' },
],
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'verifyingContract', type: 'address' },
],
domain,
types,
primaryType,
message: {
proofHash,
spender,
approval: true,
},
primaryType: 'ProofSignature',
message,
};

// eth-sig-util is the MetaMask signing package
const metaMaskSignature = ethSigUtil.signTypedData_v4(Buffer.from(aztecAccount.privateKey.slice(2), 'hex'), {
data: metaMaskTypedData,
});
expect(aztecSignature).to.equal(metaMaskSignature);
});

it('signPermit() should produce same signature as MetaMask signing function', async () => {
const verifyingContract = randomHex(20);
const holderAccount = secp256k1.generateAccount();
const spender = randomHex(20);
const nonce = 5;
const expiry = 10;
const allowed = true;
const aztecSignature = signer.signPermit(verifyingContract, holderAccount, spender, nonce, expiry, allowed);

const domain = signer.generateAccountRegistryDomainParams(verifyingContract);
const { types, primaryType } = constants.eip712.PERMIT_SIGNATURE;
const metaMaskTypedData = {
domain,
types,
primaryType,
message: {
holder: holderAccount.address,
spender,
nonce,
expiry,
allowed,
},
};
// eth-sig-util is the MetaMask signing package
const metaMaskSignature = ethSigUtil.signTypedData_v4(Buffer.from(holderAccount.privateKey.slice(2), 'hex'), {
data: metaMaskTypedData,
});
expect(aztecSignature).to.equal(metaMaskSignature);
});
});
Expand Down

0 comments on commit ee9eea2

Please sign in to comment.