@ -1,38 +1,39 @@
const { ethers } = require ( 'hardhat' ) ;
const { ethers } = require ( 'hardhat' ) ;
const { expect } = require ( 'chai' ) ;
const { expect } = require ( 'chai' ) ;
const { getDomain , domainType , domainSeparator , hashTypedData } = require ( '../../helpers/eip712' ) ;
const { loadFixture } = require ( '@nomicfoundation/hardhat-network-helpers' ) ;
const { getChainId } = require ( '../../helpers/chainid' ) ;
const { mapValues } = require ( '../../helpers/iterate' ) ;
const EIP712Verifier = artifacts . require ( '$EIP712Verifier' ) ;
const Clones = artifacts . require ( '$Clones' ) ;
contract ( 'EIP712' , function ( accounts ) {
const { getDomain , domainSeparator , hashTypedData } = require ( '../../helpers/eip712' ) ;
const [ mailTo ] = accounts ;
const { getChainId } = require ( '../../helpers/chainid' ) ;
const shortName = 'A Name' ;
const shortVersion = '1' ;
const longName = 'A' . repeat ( 40 ) ;
const LENGTHS = {
const longVersion = 'B' . repeat ( 40 ) ;
short : [ 'A Name' , '1' ] ,
long : [ 'A' . repeat ( 40 ) , 'B' . repeat ( 40 ) ] ,
} ;
const fixture = async ( ) => {
const [ from , to ] = await ethers . getSigners ( ) ;
const lengths = { } ;
for ( const [ shortOrLong , [ name , version ] ] of Object . entries ( LENGTHS ) ) {
lengths [ shortOrLong ] = { name , version } ;
lengths [ shortOrLong ] . eip712 = await ethers . deployContract ( '$EIP712Verifier' , [ name , version ] ) ;
lengths [ shortOrLong ] . domain = {
name ,
version ,
chainId : await getChainId ( ) ,
verifyingContract : lengths [ shortOrLong ] . eip712 . target ,
} ;
}
const cases = [
return { from , to , lengths } ;
[ 'short' , shortName , shortVersion ] ,
} ;
[ 'long' , longName , longVersion ] ,
] ;
for ( const [ shortOrLong , name , version ] of cases ) {
describe ( 'EIP712' , function ( ) {
for ( const [ shortOrLong , [ name , version ] ] of Object . entries ( LENGTHS ) ) {
describe ( ` with ${ shortOrLong } name and version ` , function ( ) {
describe ( ` with ${ shortOrLong } name and version ` , function ( ) {
beforeEach ( 'deploying' , async function ( ) {
beforeEach ( 'deploying' , async function ( ) {
this . eip712 = await EIP712Verifier . new ( name , version ) ;
Object . assign ( this , await loadFixture ( fixture ) ) ;
Object . assign ( this , this . lengths [ shortOrLong ] ) ;
this . domain = {
name ,
version ,
chainId : await getChainId ( ) ,
verifyingContract : this . eip712 . address ,
} ;
this . domainType = domainType ( this . domain ) ;
} ) ;
} ) ;
describe ( 'domain separator' , function ( ) {
describe ( 'domain separator' , function ( ) {
@ -44,7 +45,7 @@ contract('EIP712', function (accounts) {
it ( "can be rebuilt using EIP-5267's eip712Domain" , async function ( ) {
it ( "can be rebuilt using EIP-5267's eip712Domain" , async function ( ) {
const rebuildDomain = await getDomain ( this . eip712 ) ;
const rebuildDomain = await getDomain ( this . eip712 ) ;
expect ( mapValues ( rebuildDomain , String ) ) . to . be . deep . equal ( mapValues ( this . domain , String ) ) ;
expect ( rebuildDomain ) . to . be . deep . equal ( this . domain ) ;
} ) ;
} ) ;
if ( shortOrLong === 'short' ) {
if ( shortOrLong === 'short' ) {
@ -52,33 +53,29 @@ contract('EIP712', function (accounts) {
// the upgradeable contract variant is used and the initializer is invoked.
// the upgradeable contract variant is used and the initializer is invoked.
it ( 'adjusts when behind proxy' , async function ( ) {
it ( 'adjusts when behind proxy' , async function ( ) {
const factory = await Clones . new ( ) ;
const factory = await ethers . deployContract ( '$Clones' ) ;
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 clone = await factory
. $clone ( this . eip712 )
. then ( tx => tx . wait ( ) )
. then ( receipt => receipt . logs . find ( ev => ev . fragment . name == 'return$clone' ) . args . instance )
. then ( address => ethers . getContractAt ( '$EIP712Verifier' , address ) ) ;
const reportedDomain = await getDomain ( clone ) ;
const expectedDomain = { ... this . domain , verifyingContract : clone . target } ;
expect ( mapValues ( reportedDomain , String ) ) . to . be . deep . equal ( mapValues ( cloneDomain , String ) ) ;
expect ( await getDomain ( clone ) ) . to . be . deep . equal ( expectedDomain ) ;
const expectedSeparator = await domainSeparator ( clone Domain) ;
const expectedSeparator = await domainSeparator ( expected Domain) ;
expect ( await clone . $ _domainSeparatorV4 ( ) ) . to . equal ( expectedSeparator ) ;
expect ( await clone . $ _domainSeparatorV4 ( ) ) . to . equal ( expectedSeparator ) ;
} ) ;
} ) ;
}
}
} ) ;
} ) ;
it ( 'hash digest' , async function ( ) {
it ( 'hash digest' , async function ( ) {
const structhash = web3 . utils . randomHex ( 32 ) ;
const structhash = ethers . hexlify ( ethers . randomBytes ( 32 ) ) ;
expect ( await this . eip712 . $ _hashTypedDataV4 ( structhash ) ) . to . be . equal ( hashTypedData ( this . domain , structhash ) ) ;
expect ( await this . eip712 . $ _hashTypedDataV4 ( structhash ) ) . to . equal ( hashTypedData ( this . domain , structhash ) ) ;
} ) ;
} ) ;
it ( 'digest' , async function ( ) {
it ( 'digest' , async function ( ) {
const message = {
to : mailTo ,
contents : 'very interesting' ,
} ;
const types = {
const types = {
Mail : [
Mail : [
{ name : 'to' , type : 'address' } ,
{ name : 'to' , type : 'address' } ,
@ -86,19 +83,22 @@ contract('EIP712', function (accounts) {
] ,
] ,
} ;
} ;
const signer = ethers . Wallet . createRandom ( ) ;
const message = {
const address = await signer . getAddress ( ) ;
to : this . to . address ,
const signature = await signer . signTypedData ( this . domain , types , message ) ;
contents : 'very interesting' ,
} ;
const signature = await this . from . signTypedData ( this . domain , types , message ) ;
await this . eip712 . verify ( signature , address , message . to , message . contents ) ;
await expect ( this . eip712 . verify ( signature , this . from . address , message . to , message . contents ) ) . to . not . be . reverted ;
} ) ;
} ) ;
it ( 'name' , async function ( ) {
it ( 'name' , async function ( ) {
expect ( await this . eip712 . $ _EIP712Name ( ) ) . to . be . equal ( name ) ;
expect ( await this . eip712 . $ _EIP712Name ( ) ) . to . equal ( name ) ;
} ) ;
} ) ;
it ( 'version' , async function ( ) {
it ( 'version' , async function ( ) {
expect ( await this . eip712 . $ _EIP712Version ( ) ) . to . be . equal ( version ) ;
expect ( await this . eip712 . $ _EIP712Version ( ) ) . to . equal ( version ) ;
} ) ;
} ) ;
} ) ;
} ) ;
}
}