Browse Source

Add more test cases for EIP712 (#4212)

Francisco 2 years ago
parent
commit
9e8b74a0e2
2 changed files with 86 additions and 51 deletions
  1. 2 0
      contracts/utils/cryptography/EIP712.sol
  2. 84 51
      test/utils/cryptography/EIP712.test.js

+ 2 - 0
contracts/utils/cryptography/EIP712.sol

@@ -111,6 +111,8 @@ abstract contract EIP712 is IERC5267 {
 
     /**
      * @dev See {EIP-5267}.
+     *
+     * _Available since v4.9._
      */
     function eip712Domain()
         public

+ 84 - 51
test/utils/cryptography/EIP712.test.js

@@ -6,65 +6,98 @@ const { getChainId } = require('../../helpers/chainid');
 const { mapValues } = require('../../helpers/map-values');
 
 const EIP712Verifier = artifacts.require('$EIP712Verifier');
+const Clones = artifacts.require('$Clones');
 
 contract('EIP712', function (accounts) {
   const [mailTo] = accounts;
 
-  const name = 'A Name';
-  const version = '1';
+  const shortName = 'A Name';
+  const shortVersion = '1';
 
-  beforeEach('deploying', async function () {
-    this.eip712 = await EIP712Verifier.new(name, version);
+  const longName = 'A'.repeat(40);
+  const longVersion = 'B'.repeat(40);
 
-    this.domain = {
-      name,
-      version,
-      chainId: await getChainId(),
-      verifyingContract: this.eip712.address,
-    };
-    this.domainType = domainType(this.domain);
-  });
+  const cases = [
+    ['short', shortName, shortVersion],
+    ['long', longName, longVersion],
+  ];
 
-  describe('domain separator', function () {
-    it('is internally available', async function () {
-      const expected = await domainSeparator(this.domain);
+  for (const [shortOrLong, name, version] of cases) {
+    describe(`with ${shortOrLong} name and version`, function () {
+      beforeEach('deploying', async function () {
+        this.eip712 = await EIP712Verifier.new(name, version);
 
-      expect(await this.eip712.$_domainSeparatorV4()).to.equal(expected);
-    });
+        this.domain = {
+          name,
+          version,
+          chainId: await getChainId(),
+          verifyingContract: this.eip712.address,
+        };
+        this.domainType = domainType(this.domain);
+      });
+
+      describe('domain separator', function () {
+        it('is internally available', async function () {
+          const expected = await domainSeparator(this.domain);
+
+          expect(await this.eip712.$_domainSeparatorV4()).to.equal(expected);
+        });
+
+        it("can be rebuilt using EIP-5267's eip712Domain", async function () {
+          const rebuildDomain = await getDomain(this.eip712);
+          expect(mapValues(rebuildDomain, String)).to.be.deep.equal(mapValues(this.domain, String));
+        });
+
+        if (shortOrLong === 'short') {
+          // Long strings are in storage, and the proxy will not be properly initialized unless
+          // the upgradeable contract variant is used and the initializer is invoked.
+
+          it('adjusts when behind proxy', async function () {
+            const factory = await Clones.new();
+            const cloneReceipt = await factory.$clone(this.eip712.address);
+            const cloneAddress = cloneReceipt.logs.find(({ event }) => event === 'return$clone').args.instance;
+            const clone = new EIP712Verifier(cloneAddress);
+
+            const cloneDomain = { ...this.domain, verifyingContract: clone.address };
+
+            const expectedSeparator = await domainSeparator(cloneDomain);
+            expect(await clone.$_domainSeparatorV4()).to.equal(expectedSeparator);
+
+            const reportedDomain = await getDomain(clone);
+            expect(mapValues(reportedDomain, String)).to.be.deep.equal(mapValues(cloneDomain, String));
+          });
+        }
+      });
+
+      it('hash digest', async function () {
+        const structhash = web3.utils.randomHex(32);
+        expect(await this.eip712.$_hashTypedDataV4(structhash)).to.be.equal(hashTypedData(this.domain, structhash));
+      });
+
+      it('digest', async function () {
+        const message = {
+          to: mailTo,
+          contents: 'very interesting',
+        };
+
+        const data = {
+          types: {
+            EIP712Domain: this.domainType,
+            Mail: [
+              { name: 'to', type: 'address' },
+              { name: 'contents', type: 'string' },
+            ],
+          },
+          domain: this.domain,
+          primaryType: 'Mail',
+          message,
+        };
+
+        const wallet = Wallet.generate();
+        const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data });
 
-    it("can be rebuilt using EIP-5267's eip712Domain", async function () {
-      const rebuildDomain = await getDomain(this.eip712);
-      expect(mapValues(rebuildDomain, String)).to.be.deep.equal(mapValues(this.domain, String));
+        await this.eip712.verify(signature, wallet.getAddressString(), message.to, message.contents);
+      });
     });
-  });
-
-  it('hash digest', async function () {
-    const structhash = web3.utils.randomHex(32);
-    expect(await this.eip712.$_hashTypedDataV4(structhash)).to.be.equal(hashTypedData(this.domain, structhash));
-  });
-
-  it('digest', async function () {
-    const message = {
-      to: mailTo,
-      contents: 'very interesting',
-    };
-
-    const data = {
-      types: {
-        EIP712Domain: this.domainType,
-        Mail: [
-          { name: 'to', type: 'address' },
-          { name: 'contents', type: 'string' },
-        ],
-      },
-      domain: this.domain,
-      primaryType: 'Mail',
-      message,
-    };
-
-    const wallet = Wallet.generate();
-    const signature = ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data });
-
-    await this.eip712.verify(signature, wallet.getAddressString(), message.to, message.contents);
-  });
+  }
 });