Migrate utils-cryptography to ethers (#4749)

Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Co-authored-by: ernestognw <ernestognw@gmail.com>
pull/4750/head
Renan Souza 1 year ago committed by GitHub
parent e473bcf859
commit 9702b67ce1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      test/helpers/eip712.js
  2. 63
      test/helpers/sign.js
  3. 249
      test/utils/cryptography/ECDSA.test.js
  4. 1
      test/utils/cryptography/EIP712.test.js
  5. 75
      test/utils/cryptography/MessageHashUtils.test.js
  6. 82
      test/utils/cryptography/SignatureChecker.test.js

@ -46,8 +46,9 @@ function domainType(domain) {
}
function hashTypedData(domain, structHash) {
return ethers.keccak256(
Buffer.concat(['0x1901', ethers.TypedDataEncoder.hashDomain(domain), structHash].map(ethers.toBeArray)),
return ethers.solidityPackedKeccak256(
['bytes', 'bytes32', 'bytes32'],
['0x1901', ethers.TypedDataEncoder.hashDomain(domain), structHash],
);
}

@ -1,63 +0,0 @@
function toEthSignedMessageHash(messageHex) {
const messageBuffer = Buffer.from(messageHex.substring(2), 'hex');
const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`);
return web3.utils.sha3(Buffer.concat([prefix, messageBuffer]));
}
/**
* Create a signed data with intended validator according to the version 0 of EIP-191
* @param validatorAddress The address of the validator
* @param dataHex The data to be concatenated with the prefix and signed
*/
function toDataWithIntendedValidatorHash(validatorAddress, dataHex) {
const validatorBuffer = Buffer.from(web3.utils.hexToBytes(validatorAddress));
const dataBuffer = Buffer.from(web3.utils.hexToBytes(dataHex));
const preambleBuffer = Buffer.from('\x19');
const versionBuffer = Buffer.from('\x00');
const ethMessage = Buffer.concat([preambleBuffer, versionBuffer, validatorBuffer, dataBuffer]);
return web3.utils.sha3(ethMessage);
}
/**
* Create a signer between a contract and a signer for a voucher of method, args, and redeemer
* Note that `method` is the web3 method, not the truffle-contract method
* @param contract TruffleContract
* @param signer address
* @param redeemer address
* @param methodName string
* @param methodArgs any[]
*/
const getSignFor =
(contract, signer) =>
(redeemer, methodName, methodArgs = []) => {
const parts = [contract.address, redeemer];
const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string length
const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length
const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`;
// if we have a method, add it to the parts that we're signing
if (methodName) {
if (methodArgs.length > 0) {
parts.push(
contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE]))
.encodeABI()
.slice(0, -1 * PADDED_SIGNATURE_SIZE),
);
} else {
const abi = contract.abi.find(abi => abi.name === methodName);
parts.push(abi.signature);
}
}
// return the signature of the "Ethereum Signed Message" hash of the hash of `parts`
const messageHex = web3.utils.soliditySha3(...parts);
return web3.eth.sign(messageHex, signer);
};
module.exports = {
toEthSignedMessageHash,
toDataWithIntendedValidatorHash,
getSignFor,
};

@ -1,104 +1,81 @@
require('@openzeppelin/test-helpers');
const { expectRevertCustomError } = require('../../helpers/customError');
const { toEthSignedMessageHash } = require('../../helpers/sign');
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const ECDSA = artifacts.require('$ECDSA');
const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin');
const WRONG_MESSAGE = web3.utils.sha3('Nope');
const NON_HASH_MESSAGE = '0x' + Buffer.from('abcd').toString('hex');
function to2098Format(signature) {
const long = web3.utils.hexToBytes(signature);
if (long.length !== 65) {
throw new Error('invalid signature length (expected long format)');
}
if (long[32] >> 7 === 1) {
throw new Error("invalid signature 's' value");
}
const short = long.slice(0, 64);
short[32] |= long[64] % 27 << 7; // set the first bit of the 32nd byte to the v parity bit
return web3.utils.bytesToHex(short);
}
const TEST_MESSAGE = ethers.id('OpenZeppelin');
const WRONG_MESSAGE = ethers.id('Nope');
const NON_HASH_MESSAGE = '0xabcd';
function split(signature) {
const raw = web3.utils.hexToBytes(signature);
switch (raw.length) {
case 64:
return [
web3.utils.bytesToHex(raw.slice(0, 32)), // r
web3.utils.bytesToHex(raw.slice(32, 64)), // vs
];
case 65:
return [
raw[64], // v
web3.utils.bytesToHex(raw.slice(0, 32)), // r
web3.utils.bytesToHex(raw.slice(32, 64)), // s
];
default:
expect.fail('Invalid signature length, cannot split');
}
function toSignature(signature) {
return ethers.Signature.from(signature);
}
contract('ECDSA', function (accounts) {
const [other] = accounts;
async function fixture() {
const [signer] = await ethers.getSigners();
const mock = await ethers.deployContract('$ECDSA');
return { signer, mock };
}
describe('ECDSA', function () {
beforeEach(async function () {
this.ecdsa = await ECDSA.new();
Object.assign(this, await loadFixture(fixture));
});
context('recover with invalid signature', function () {
describe('recover with invalid signature', function () {
it('with short signature', async function () {
await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, '0x1234'), 'ECDSAInvalidSignatureLength', [2]);
await expect(this.mock.$recover(TEST_MESSAGE, '0x1234'))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(2);
});
it('with long signature', async function () {
await expectRevertCustomError(
await expect(
// eslint-disable-next-line max-len
this.ecdsa.$recover(
this.mock.$recover(
TEST_MESSAGE,
'0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789',
),
'ECDSAInvalidSignatureLength',
[85],
);
)
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(85);
});
});
context('recover with valid signature', function () {
context('using web3.eth.sign', function () {
describe('recover with valid signature', function () {
describe('using <signer>.sign', function () {
it('returns signer address with correct signature', async function () {
// Create the signature
const signature = await web3.eth.sign(TEST_MESSAGE, other);
const signature = await this.signer.signMessage(TEST_MESSAGE);
// Recover the signer address from the generated message and signature.
expect(await this.ecdsa.$recover(toEthSignedMessageHash(TEST_MESSAGE), signature)).to.equal(other);
expect(await this.mock.$recover(ethers.hashMessage(TEST_MESSAGE), signature)).to.equal(this.signer.address);
});
it('returns signer address with correct signature for arbitrary length message', async function () {
// Create the signature
const signature = await web3.eth.sign(NON_HASH_MESSAGE, other);
const signature = await this.signer.signMessage(NON_HASH_MESSAGE);
// Recover the signer address from the generated message and signature.
expect(await this.ecdsa.$recover(toEthSignedMessageHash(NON_HASH_MESSAGE), signature)).to.equal(other);
expect(await this.mock.$recover(ethers.hashMessage(NON_HASH_MESSAGE), signature)).to.equal(this.signer.address);
});
it('returns a different address', async function () {
const signature = await web3.eth.sign(TEST_MESSAGE, other);
expect(await this.ecdsa.$recover(WRONG_MESSAGE, signature)).to.not.equal(other);
const signature = await this.signer.signMessage(TEST_MESSAGE);
expect(await this.mock.$recover(WRONG_MESSAGE, signature)).to.not.be.equal(this.signer.address);
});
it('reverts with invalid signature', async function () {
// eslint-disable-next-line max-len
const signature =
'0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c';
await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []);
await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError(
this.mock,
'ECDSAInvalidSignature',
);
});
});
context('with v=27 signature', function () {
describe('with v=27 signature', function () {
// Signature generated outside ganache with method web3.eth.sign(signer, message)
const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c';
// eslint-disable-next-line max-len
@ -106,124 +83,112 @@ contract('ECDSA', function (accounts) {
'0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892';
it('works with correct v value', async function () {
const v = '1b'; // 27 = 1b.
const signature = signatureWithoutV + v;
expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer);
const v = '0x1b'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer);
expect(
await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)),
).to.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal(
signer,
);
expect(
await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)'](
TEST_MESSAGE,
...split(to2098Format(signature)),
),
).to.equal(signer);
expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.equal(signer);
});
it('rejects incorrect v value', async function () {
const v = '1c'; // 28 = 1c.
const signature = signatureWithoutV + v;
expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
const v = '0x1c'; // 28 = 1c.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
expect(
await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)),
await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.not.equal(signer);
expect(
await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)'](
TEST_MESSAGE,
...split(to2098Format(signature)),
),
).to.not.equal(signer);
expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.not.equal(
signer,
);
});
it('reverts wrong v values', async function () {
for (const v of ['00', '01']) {
const signature = signatureWithoutV + v;
await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []);
await expectRevertCustomError(
this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)),
for (const v of ['0x00', '0x01']) {
const signature = ethers.concat([signatureWithoutV, v]);
await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError(
this.mock,
'ECDSAInvalidSignature',
[],
);
const { r, s } = toSignature(signature);
await expect(
this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature');
}
});
it('rejects short EIP2098 format', async function () {
const v = '1b'; // 27 = 1b.
const signature = signatureWithoutV + v;
await expectRevertCustomError(
this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)),
'ECDSAInvalidSignatureLength',
[64],
);
const v = '0x1b'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
await expect(this.mock.$recover(TEST_MESSAGE, toSignature(signature).compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
});
});
context('with v=28 signature', function () {
describe('with v=28 signature', function () {
const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E';
// eslint-disable-next-line max-len
const signatureWithoutV =
'0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0';
it('works with correct v value', async function () {
const v = '1c'; // 28 = 1c.
const signature = signatureWithoutV + v;
expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer);
const v = '0x1c'; // 28 = 1c.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.equal(signer);
expect(
await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)),
).to.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
expect(await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s)).to.equal(
signer,
);
expect(
await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)'](
TEST_MESSAGE,
...split(to2098Format(signature)),
),
).to.equal(signer);
expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.equal(signer);
});
it('rejects incorrect v value', async function () {
const v = '1b'; // 27 = 1b.
const signature = signatureWithoutV + v;
expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
const v = '0x1b'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
expect(await this.mock.$recover(TEST_MESSAGE, signature)).to.not.equal(signer);
const { r, s, yParityAndS: vs } = toSignature(signature);
expect(
await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)),
await this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.not.equal(signer);
expect(
await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)'](
TEST_MESSAGE,
...split(to2098Format(signature)),
),
).to.not.equal(signer);
expect(await this.mock.getFunction('$recover(bytes32,bytes32,bytes32)')(TEST_MESSAGE, r, vs)).to.not.equal(
signer,
);
});
it('reverts invalid v values', async function () {
for (const v of ['00', '01']) {
const signature = signatureWithoutV + v;
await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []);
await expectRevertCustomError(
this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)),
for (const v of ['0x00', '0x01']) {
const signature = ethers.concat([signatureWithoutV, v]);
await expect(this.mock.$recover(TEST_MESSAGE, signature)).to.be.revertedWithCustomError(
this.mock,
'ECDSAInvalidSignature',
[],
);
const { r, s } = toSignature(signature);
await expect(
this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s),
).to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignature');
}
});
it('rejects short EIP2098 format', async function () {
const v = '1c'; // 27 = 1b.
const signature = signatureWithoutV + v;
await expectRevertCustomError(
this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)),
'ECDSAInvalidSignatureLength',
[64],
);
const v = '0x1c'; // 27 = 1b.
const signature = ethers.concat([signatureWithoutV, v]);
await expect(this.mock.$recover(TEST_MESSAGE, toSignature(signature).compactSerialized))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureLength')
.withArgs(64);
});
});
@ -232,14 +197,18 @@ contract('ECDSA', function (accounts) {
// eslint-disable-next-line max-len
const highSSignature =
'0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b';
const [r, v, s] = split(highSSignature);
await expectRevertCustomError(this.ecdsa.$recover(message, highSSignature), 'ECDSAInvalidSignatureS', [s]);
await expectRevertCustomError(
this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, r, v, s),
'ECDSAInvalidSignatureS',
[s],
);
expect(() => to2098Format(highSSignature)).to.throw("invalid signature 's' value");
const r = ethers.dataSlice(highSSignature, 0, 32);
const s = ethers.dataSlice(highSSignature, 32, 64);
const v = ethers.dataSlice(highSSignature, 64, 65);
await expect(this.mock.$recover(message, highSSignature))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS')
.withArgs(s);
await expect(this.mock.getFunction('$recover(bytes32,uint8,bytes32,bytes32)')(TEST_MESSAGE, v, r, s))
.to.be.revertedWithCustomError(this.mock, 'ECDSAInvalidSignatureS')
.withArgs(s);
expect(() => toSignature(highSSignature)).to.throw('non-canonical s');
});
});
});

@ -1,4 +1,5 @@
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { getDomain, domainType, domainSeparator, hashTypedData } = require('../../helpers/eip712');
const { getChainId } = require('../../helpers/chainid');
const { mapValues } = require('../../helpers/iterate');

@ -1,55 +1,68 @@
require('@openzeppelin/test-helpers');
const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign');
const { domainSeparator, hashTypedData } = require('../../helpers/eip712');
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const MessageHashUtils = artifacts.require('$MessageHashUtils');
const { domainSeparator, hashTypedData } = require('../../helpers/eip712');
contract('MessageHashUtils', function () {
beforeEach(async function () {
this.messageHashUtils = await MessageHashUtils.new();
async function fixture() {
const mock = await ethers.deployContract('$MessageHashUtils');
return { mock };
}
this.message = '0x' + Buffer.from('abcd').toString('hex');
this.messageHash = web3.utils.sha3(this.message);
this.verifyingAddress = web3.utils.toChecksumAddress(web3.utils.randomHex(20));
describe('MessageHashUtils', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});
context('toEthSignedMessageHash', function () {
describe('toEthSignedMessageHash', function () {
it('prefixes bytes32 data correctly', async function () {
expect(await this.messageHashUtils.methods['$toEthSignedMessageHash(bytes32)'](this.messageHash)).to.equal(
toEthSignedMessageHash(this.messageHash),
);
const message = ethers.randomBytes(32);
const expectedHash = ethers.hashMessage(message);
expect(await this.mock.getFunction('$toEthSignedMessageHash(bytes32)')(message)).to.equal(expectedHash);
});
it('prefixes dynamic length data correctly', async function () {
expect(await this.messageHashUtils.methods['$toEthSignedMessageHash(bytes)'](this.message)).to.equal(
toEthSignedMessageHash(this.message),
);
const message = ethers.randomBytes(128);
const expectedHash = ethers.hashMessage(message);
expect(await this.mock.getFunction('$toEthSignedMessageHash(bytes)')(message)).to.equal(expectedHash);
});
it('version match for bytes32', async function () {
const message = ethers.randomBytes(32);
const fixed = await this.mock.getFunction('$toEthSignedMessageHash(bytes32)')(message);
const dynamic = await this.mock.getFunction('$toEthSignedMessageHash(bytes)')(message);
expect(fixed).to.equal(dynamic);
});
});
context('toDataWithIntendedValidatorHash', function () {
describe('toDataWithIntendedValidatorHash', function () {
it('returns the digest correctly', async function () {
expect(
await this.messageHashUtils.$toDataWithIntendedValidatorHash(this.verifyingAddress, this.message),
).to.equal(toDataWithIntendedValidatorHash(this.verifyingAddress, this.message));
const verifier = ethers.Wallet.createRandom().address;
const message = ethers.randomBytes(128);
const expectedHash = ethers.solidityPackedKeccak256(
['string', 'address', 'bytes'],
['\x19\x00', verifier, message],
);
expect(await this.mock.$toDataWithIntendedValidatorHash(verifier, message)).to.equal(expectedHash);
});
});
context('toTypedDataHash', function () {
describe('toTypedDataHash', function () {
it('returns the digest correctly', async function () {
const domain = {
name: 'Test',
version: 1,
chainId: 1,
verifyingContract: this.verifyingAddress,
version: '1',
chainId: 1n,
verifyingContract: ethers.Wallet.createRandom().address,
};
const structhash = web3.utils.randomHex(32);
const expectedDomainSeparator = await domainSeparator(domain);
expect(await this.messageHashUtils.$toTypedDataHash(expectedDomainSeparator, structhash)).to.equal(
hashTypedData(domain, structhash),
);
const structhash = ethers.randomBytes(32);
const expectedHash = hashTypedData(domain, structhash);
expect(await this.mock.$toTypedDataHash(domainSeparator(domain), structhash)).to.equal(expectedHash);
});
});
});

@ -1,85 +1,59 @@
const { toEthSignedMessageHash } = require('../../helpers/sign');
const { ethers } = require('hardhat');
const { expect } = require('chai');
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
const TEST_MESSAGE = ethers.id('OpenZeppelin');
const TEST_MESSAGE_HASH = ethers.hashMessage(TEST_MESSAGE);
const SignatureChecker = artifacts.require('$SignatureChecker');
const ERC1271WalletMock = artifacts.require('ERC1271WalletMock');
const ERC1271MaliciousMock = artifacts.require('ERC1271MaliciousMock');
const WRONG_MESSAGE = ethers.id('Nope');
const WRONG_MESSAGE_HASH = ethers.hashMessage(WRONG_MESSAGE);
const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin');
const WRONG_MESSAGE = web3.utils.sha3('Nope');
async function fixture() {
const [signer, other] = await ethers.getSigners();
const mock = await ethers.deployContract('$SignatureChecker');
const wallet = await ethers.deployContract('ERC1271WalletMock', [signer]);
const malicious = await ethers.deployContract('ERC1271MaliciousMock');
const signature = await signer.signMessage(TEST_MESSAGE);
contract('SignatureChecker (ERC1271)', function (accounts) {
const [signer, other] = accounts;
return { signer, other, mock, wallet, malicious, signature };
}
describe('SignatureChecker (ERC1271)', function () {
before('deploying', async function () {
this.signaturechecker = await SignatureChecker.new();
this.wallet = await ERC1271WalletMock.new(signer);
this.malicious = await ERC1271MaliciousMock.new();
this.signature = await web3.eth.sign(TEST_MESSAGE, signer);
Object.assign(this, await loadFixture(fixture));
});
context('EOA account', function () {
describe('EOA account', function () {
it('with matching signer and signature', async function () {
expect(
await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(TEST_MESSAGE), this.signature),
).to.equal(true);
expect(await this.mock.$isValidSignatureNow(this.signer, TEST_MESSAGE_HASH, this.signature)).to.be.true;
});
it('with invalid signer', async function () {
expect(
await this.signaturechecker.$isValidSignatureNow(other, toEthSignedMessageHash(TEST_MESSAGE), this.signature),
).to.equal(false);
expect(await this.mock.$isValidSignatureNow(this.other, TEST_MESSAGE_HASH, this.signature)).to.be.false;
});
it('with invalid signature', async function () {
expect(
await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(WRONG_MESSAGE), this.signature),
).to.equal(false);
expect(await this.mock.$isValidSignatureNow(this.signer, WRONG_MESSAGE_HASH, this.signature)).to.be.false;
});
});
context('ERC1271 wallet', function () {
for (const signature of ['isValidERC1271SignatureNow', 'isValidSignatureNow']) {
context(signature, function () {
describe('ERC1271 wallet', function () {
for (const fn of ['isValidERC1271SignatureNow', 'isValidSignatureNow']) {
describe(fn, function () {
it('with matching signer and signature', async function () {
expect(
await this.signaturechecker[`$${signature}`](
this.wallet.address,
toEthSignedMessageHash(TEST_MESSAGE),
this.signature,
),
).to.equal(true);
expect(await this.mock.getFunction(`$${fn}`)(this.wallet, TEST_MESSAGE_HASH, this.signature)).to.be.true;
});
it('with invalid signer', async function () {
expect(
await this.signaturechecker[`$${signature}`](
this.signaturechecker.address,
toEthSignedMessageHash(TEST_MESSAGE),
this.signature,
),
).to.equal(false);
expect(await this.mock.getFunction(`$${fn}`)(this.mock, TEST_MESSAGE_HASH, this.signature)).to.be.false;
});
it('with invalid signature', async function () {
expect(
await this.signaturechecker[`$${signature}`](
this.wallet.address,
toEthSignedMessageHash(WRONG_MESSAGE),
this.signature,
),
).to.equal(false);
expect(await this.mock.getFunction(`$${fn}`)(this.wallet, WRONG_MESSAGE_HASH, this.signature)).to.be.false;
});
it('with malicious wallet', async function () {
expect(
await this.signaturechecker[`$${signature}`](
this.malicious.address,
toEthSignedMessageHash(TEST_MESSAGE),
this.signature,
),
).to.equal(false);
expect(await this.mock.getFunction(`$${fn}`)(this.malicious, TEST_MESSAGE_HASH, this.signature)).to.be.false;
});
});
}

Loading…
Cancel
Save