import { exec } from 'child_process' ; import { promises , existsSync , truncateSync } from 'fs' ; import { ContractFactory , Contract } from '@ethersproject/contracts' ; import { providers } from 'ethers' ; import waitOn from 'wait-on' ; import kill from 'tree-kill' ; import { BigNumber } from '@ethersproject/bignumber' ; import nitroAdjudicatorArtifact from '../artifacts/contracts/NitroAdjudicator.sol/NitroAdjudicator.json' ; import tokenArtifact from '../artifacts/contracts/Token.sol/Token.json' ; import { NitroAdjudicator } from '../typechain/NitroAdjudicator' ; import { Token } from '../typechain/Token' ; declare global { namespace jest { interface Matchers < R > { toConsumeGas ( benchmark ) : R ; } } } export let nitroAdjudicator ; export let token ; const logFile = './hardhat-network-output.log' ; const hardHatNetworkEndpoint = 'http://localhost:9546' ; jest . setTimeout ( 15000 ) ; if ( existsSync ( logFile ) ) truncateSync ( logFile ) ; const hardhatProcess = exec ( 'npx hardhat node --no-deploy --port 9546' , ( error , stdout ) => { promises . appendFile ( logFile , stdout ) ; } ) ; const hardhatProcessExited = new Promise ( resolve => hardhatProcess . on ( 'exit' , resolve ) ) ; const hardhatProcessClosed = new Promise ( resolve => hardhatProcess . on ( 'close' , resolve ) ) ; export const provider = new providers . JsonRpcProvider ( hardHatNetworkEndpoint ) ; let snapshotId = 0 ; const tokenFactory = new ContractFactory ( tokenArtifact . abi , tokenArtifact . bytecode ) . connect ( provider . getSigner ( 0 ) ) ; const nitroAdjudicatorFactory = new ContractFactory ( nitroAdjudicatorArtifact . abi , nitroAdjudicatorArtifact . bytecode ) . connect ( provider . getSigner ( 0 ) ) ; beforeAll ( async ( ) => { await waitOn ( { resources : [ hardHatNetworkEndpoint ] } ) ; nitroAdjudicator = ( await nitroAdjudicatorFactory . deploy ( ) ) as NitroAdjudicator & Contract ; token = ( await tokenFactory . deploy ( provider . getSigner ( 0 ) . getAddress ( ) ) ) as Token & Contract ; snapshotId = await provider . send ( 'evm_snapshot' , [ ] ) ; } ) ; beforeEach ( async ( ) => { await provider . send ( 'evm_revert' , [ snapshotId ] ) ; snapshotId = await provider . send ( 'evm_snapshot' , [ ] ) ; } ) ; afterAll ( async ( ) => { await kill ( hardhatProcess . pid ) ; await hardhatProcessExited ; await hardhatProcessClosed ; } ) ; expect . extend ( { async toConsumeGas ( received , benchmark ) { const { gasUsed : gasUsedBN } = await received . wait ( ) ; const gasUsed = ( gasUsedBN as BigNumber ) . toNumber ( ) ; const pass = gasUsed === benchmark ; if ( pass ) { return { message : ( ) => `expected to NOT consume ${ benchmark } gas, but did` , pass : true , } ; } else { const format = ( x ) => { return x . toLocaleString ( ) . replace ( /,/g , '_' ) ; } ; const green = ( x ) => `\x1b[32m${ x }\x1b[0m` ; const red = ( x ) => `\x1b[31m${ x }\x1b[0m` ; const diff = gasUsed - benchmark ; const diffStr = diff > 0 ? red ( '+' + format ( diff ) ) : green ( format ( diff ) ) ; const diffPercent = `${ Math . round ( ( Math . abs ( diff ) / benchmark ) * 100 ) }%` ; return { message : ( ) => `expected to consume ${ format ( benchmark ) } gas, but actually consumed ${ format ( gasUsed ) } gas (${ diffStr }, ${ diffPercent }). Consider updating the appropriate number in gas.ts!` , pass : false , } ; } } , } ) ;