diff --git a/.changeset/green-feet-begin.md b/.changeset/green-feet-begin.md
new file mode 100644
index 0000000000000000000000000000000000000000..a31841db26a5a66fe77b9bdee2d906bf9fdea857
--- /dev/null
+++ b/.changeset/green-feet-begin.md
@@ -0,0 +1,5 @@
+---
+'@eth-optimism/contracts': patch
+---
+
+Add etherscan verification support
diff --git a/.changeset/nice-waves-jog.md b/.changeset/nice-waves-jog.md
new file mode 100644
index 0000000000000000000000000000000000000000..db9f12b422db4962990277104685675fee45f6c7
--- /dev/null
+++ b/.changeset/nice-waves-jog.md
@@ -0,0 +1,5 @@
+---
+'@eth-optimism/core-utils': patch
+---
+
+increased coverage of core-utils
diff --git a/.changeset/seven-geese-whisper.md b/.changeset/seven-geese-whisper.md
new file mode 100644
index 0000000000000000000000000000000000000000..4e20d824ce1d59a72806108a49fe988f73eb9ef7
--- /dev/null
+++ b/.changeset/seven-geese-whisper.md
@@ -0,0 +1,8 @@
+---
+'@eth-optimism/batch-submitter': patch
+'@eth-optimism/core-utils': patch
+'@eth-optimism/data-transport-layer': patch
+'@eth-optimism/message-relayer': patch
+---
+
+Added coverage for packages
diff --git a/.changeset/sweet-actors-hope.md b/.changeset/sweet-actors-hope.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3bcd1d1d4f4ea58f9662136bab31395d0562af6
--- /dev/null
+++ b/.changeset/sweet-actors-hope.md
@@ -0,0 +1,6 @@
+---
+'@eth-optimism/core-utils': patch
+'@eth-optimism/l2geth': patch
+---
+
+Lower per tx fee overhead to more accurately represent L1 costs
diff --git a/.changeset/yellow-tomatoes-peel.md b/.changeset/yellow-tomatoes-peel.md
new file mode 100644
index 0000000000000000000000000000000000000000..02833e41c3f2ac64fc01e096a8ec550b5be24414
--- /dev/null
+++ b/.changeset/yellow-tomatoes-peel.md
@@ -0,0 +1,5 @@
+---
+'@eth-optimism/batch-submitter': patch
+---
+
+Add loglines for eip1559 related fields before sending a transaction
diff --git a/.github/workflows/ts-packages.yml b/.github/workflows/ts-packages.yml
index 5ab532c383a147409c8983014ccda17590544b03..a3f3b83f4d3bfa194b553c9ea837a3adcf0a5f8d 100644
--- a/.github/workflows/ts-packages.yml
+++ b/.github/workflows/ts-packages.yml
@@ -60,45 +60,8 @@ jobs:
         env:
           CC_SECRET: ${{ secrets.CC_SECRET }}
 
-  # A hack that allows running a job only if a specific directory changed.
-  # Ref: https://github.community/t/run-job-only-if-folder-changed/118292
-  is-contracts-package:
-    name: Check files for changes to the contracts package
-    # This job will break on a push event, so we just skip it,
-    # which in turn skips the test-coverage job.
-    if: ${{ github.event_name != 'push' }}
-    outputs:
-      run_coverage: ${{ steps.check_files.outputs.run_coverage }}
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-      - run: git fetch origin $GITHUB_BASE_REF
-
-      - name: check modified files
-        id: check_files
-        run: |
-          echo "=============== list modified files ==============="
-          git diff --name-only origin/$GITHUB_BASE_REF HEAD -- .
-
-          echo "========== check paths of modified files =========="
-          git diff --name-only origin/$GITHUB_BASE_REF HEAD -- . > files.txt
-          while IFS= read -r file
-          do
-            echo $file
-            if [[ $file != packages/contracts/* ]]; then
-              echo "This modified files are not in the contracts package."
-              echo "::set-output name=run_coverage::false"
-              break
-            else
-              echo "::set-output name=run_coverage::true"
-            fi
-          done < files.txt
-
   test-coverage:
     name: Generate test coverage
-    needs: is-contracts-package
-    if: needs.is-contracts-package.outputs.run_coverage == 'true'
     runs-on: ubuntu-latest
 
     steps:
@@ -142,6 +105,31 @@ jobs:
           files: ./packages/contracts/coverage.json
           fail_ci_if_error: false
           verbose: true
+          flags: contracts
+      - uses: codecov/codecov-action@v1
+        with:
+          files: ./packages/core-utils/coverage.json
+          fail_ci_if_error: false
+          verbose: true
+          flags: core-utils
+      - uses: codecov/codecov-action@v1
+        with:
+          files: ./packages/batch-submitter/coverage.json
+          fail_ci_if_error: false
+          verbose: true
+          flags: batch-submitter
+      - uses: codecov/codecov-action@v1
+        with:
+          files: ./packages/data-transport-layer/coverage.json
+          fail_ci_if_error: false
+          verbose: true
+          flags: data-transport-layer
+      - uses: codecov/codecov-action@v1
+        with:
+          files: ./packages/message-relayer/coverage.json
+          fail_ci_if_error: false
+          verbose: true
+          flags: message-relayer
   lint:
     name: Linting
     runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index e031e635cb48d8d9dec3a50b868d690dd4151cee..6954e8ca4dbe3631ce4538a39f8145525943c30b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ node_modules
 results
 temp
 .nyc_output
+coverage.json
 *.tsbuildinfo
 
 dist
diff --git a/go/utils/fees/rollup_fee.go b/go/utils/fees/rollup_fee.go
index 13feafbbdef7373b9e8b5fe5424e328fe1b71463..874a9b4761475a3498787a7724ee2b7dd5cebc7f 100644
--- a/go/utils/fees/rollup_fee.go
+++ b/go/utils/fees/rollup_fee.go
@@ -9,7 +9,7 @@ import (
 
 // overhead represents the fixed cost of batch submission of a single
 // transaction in gas.
-const overhead uint64 = 4200 + 200*params.TxDataNonZeroGasEIP2028
+const overhead uint64 = 2750
 
 // feeScalar is used to scale the calculations in EncodeL2GasLimit
 // to prevent them from being too large
diff --git a/integration-tests/test/rpc.spec.ts b/integration-tests/test/rpc.spec.ts
index bdd209d5753c1c05c9f2f35b3e6014d4e82ef416..b3022b8b441a0adcc0c67681a0f9d24c64b3fd7f 100644
--- a/integration-tests/test/rpc.spec.ts
+++ b/integration-tests/test/rpc.spec.ts
@@ -420,9 +420,7 @@ describe('Basic RPC tests', () => {
         expect(decoded).to.deep.eq(BigNumber.from(l2Gaslimit))
         expect(estimate.toString().endsWith(l2Gaslimit.toString()))
 
-        const l2GasPrice = BigNumber.from(0)
-        // The L2GasPrice should be fetched from the L2GasPrice oracle contract,
-        // but it does not yet exist. Use the default value for now
+        const l2GasPrice = await env.gasPriceOracle.gasPrice()
         const expected = TxGasLimit.encode({
           data: tx.data,
           l1GasPrice,
diff --git a/l2geth/rollup/fees/rollup_fee.go b/l2geth/rollup/fees/rollup_fee.go
index d248c03ec36e15feee0a8240a17e0b130ac832f6..f6870aebb746c85ae4712f3862be9bd4e9242c19 100644
--- a/l2geth/rollup/fees/rollup_fee.go
+++ b/l2geth/rollup/fees/rollup_fee.go
@@ -25,7 +25,7 @@ var (
 
 // overhead represents the fixed cost of batch submission of a single
 // transaction in gas.
-const overhead uint64 = 4200 + 200*params.TxDataNonZeroGasEIP2028
+const overhead uint64 = 2750
 
 // feeScalar is used to scale the calculations in EncodeL2GasLimit
 // to prevent them from being too large
diff --git a/packages/batch-submitter/README.md b/packages/batch-submitter/README.md
index 0868486a64aee825178c4b1522a34d2fb59c2509..1a8f5ad3e241bd1ee2c10888d39092dedca86169 100644
--- a/packages/batch-submitter/README.md
+++ b/packages/batch-submitter/README.md
@@ -1,3 +1,4 @@
+[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=batch-submitter)](https://codecov.io/gh/ethereum-optimism/optimism)
 # Batch Submitter
 
 Contains an executable batch submitter service which watches L1 and a local L2 node and submits batches to the
@@ -31,9 +32,9 @@ Examples:
 
 ### Submission
 
-You may test a submission locally against a local Hardhat fork. 
+You may test a submission locally against a local Hardhat fork.
 
-1. Follow the instructions [here](https://github.com/ethereum-optimism/hardhat) to run a Hardhat node. 
+1. Follow the instructions [here](https://github.com/ethereum-optimism/hardhat) to run a Hardhat node.
 2. Change the Batch Submitter `.env` field `L1_NODE_WEB3_URL` to the local Hardhat url. Depending on which network you are using, update `ADDRESS_MANAGER_ADDRESS` according to the [Regenesis repo](https://github.com/ethereum-optimism/regenesis).
 3. Also check `L2_NODE_WEB3_URL` is correctly set and has transactions to submit.
 3. Run `yarn build` to build your changes.
diff --git a/packages/batch-submitter/package.json b/packages/batch-submitter/package.json
index a6d115a0c07eed00d4f146d6bd09d819c3224a63..5b126a8bd67007bc5e682fbeae343dccf30d6b6f 100644
--- a/packages/batch-submitter/package.json
+++ b/packages/batch-submitter/package.json
@@ -16,7 +16,8 @@
     "pre-commit": "lint-staged",
     "lint:fix": "yarn lint:check --fix",
     "lint:check": "eslint .",
-    "test": "hardhat test --show-stack-traces"
+    "test": "hardhat test --show-stack-traces",
+    "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
   },
   "keywords": [
     "optimism",
diff --git a/packages/batch-submitter/src/batch-submitter/batch-submitter.ts b/packages/batch-submitter/src/batch-submitter/batch-submitter.ts
index ea84a95a330c5f9e9d220be692972d8f512ffa95..60daedf7b1ec4d8bdccd44b2ec17f96cf7eba765 100644
--- a/packages/batch-submitter/src/batch-submitter/batch-submitter.ts
+++ b/packages/batch-submitter/src/batch-submitter/batch-submitter.ts
@@ -195,6 +195,9 @@ export abstract class BatchSubmitter {
       beforeSendTransaction: (tx: PopulatedTransaction) => {
         this.logger.info(`Submitting ${txName} transaction`, {
           gasPrice: tx.gasPrice,
+          maxFeePerGas: tx.maxFeePerGas,
+          maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
+          gasLimit: tx.gasLimit,
           nonce: tx.nonce,
           contractAddr: this.chainContract.address,
         })
diff --git a/packages/contracts/README.md b/packages/contracts/README.md
index 40cadb3447108c7f003a49c2c28f96f4c359ceb3..322b0fc9daf1500ea39f271b2bf393b2c973f63e 100644
--- a/packages/contracts/README.md
+++ b/packages/contracts/README.md
@@ -1,4 +1,4 @@
-[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR)](https://codecov.io/gh/ethereum-optimism/optimism)
+[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=contracts)](https://codecov.io/gh/ethereum-optimism/optimism)
 
 # Optimistic Ethereum Smart Contracts
 
diff --git a/packages/contracts/hardhat.config.ts b/packages/contracts/hardhat.config.ts
index 6fc2e3201e9c213bd85773215f743d6749c6f73d..31ad325fb2768ba08054fd028e427ec7bb17d845 100644
--- a/packages/contracts/hardhat.config.ts
+++ b/packages/contracts/hardhat.config.ts
@@ -10,6 +10,7 @@ import {
 // Hardhat plugins
 import '@nomiclabs/hardhat-ethers'
 import '@nomiclabs/hardhat-waffle'
+import '@nomiclabs/hardhat-etherscan'
 import 'hardhat-deploy'
 import '@typechain/hardhat'
 import '@eth-optimism/hardhat-ovm'
@@ -24,6 +25,8 @@ import 'hardhat-gas-reporter'
 dotenv.config()
 
 const enableGasReport = !!process.env.ENABLE_GAS_REPORT
+const privateKey = process.env.PRIVATE_KEY ||
+  "0x0000000000000000000000000000000000000000000000000000000000000000"; // this is to avoid hardhat error
 
 const config: HardhatUserConfig = {
   networks: {
@@ -41,6 +44,20 @@ const config: HardhatUserConfig = {
       ovm: true,
       saveDeployments: false,
     },
+    'optimism-kovan': {
+      chainId: 69,
+      url: 'https://kovan.optimism.io',
+      accounts: [privateKey],
+      gasPrice: 15000000,
+      ovm: true,
+    },
+    'optimism-mainnet': {
+      chainId: 10,
+      url: 'https://mainnet.optimism.io',
+      accounts: [privateKey],
+      gasPrice: 15000000,
+      ovm: true,
+    },
   },
   mocha: {
     timeout: 50000,
@@ -81,6 +98,9 @@ const config: HardhatUserConfig = {
     gasPrice: 100,
     outputFile: process.env.CI ? 'gas-report.txt' : undefined,
   },
+  etherscan: {
+    apiKey: process.env.ETHERSCAN_API_KEY,
+  },
 }
 
 if (
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index 1371cae06274e3942c04c09c1748a4dba84af8b6..54095d9f6a9a7392f9bb902341dac33deaab8ec1 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -55,6 +55,7 @@
     "@ethersproject/abstract-signer": "^5.4.1",
     "@ethersproject/contracts": "^5.4.1",
     "@ethersproject/hardware-wallets": "^5.4.0",
+    "@nomiclabs/hardhat-etherscan": "^2.1.5",
     "glob": "^7.1.6"
   },
   "devDependencies": {
diff --git a/packages/core-utils/.gitignore b/packages/core-utils/.gitignore
index b51ea715cf58b2239ffd0fee051ffd1de033bdfa..b38db2f296ff3664e67b1a2f1869321e5e7af6a0 100644
--- a/packages/core-utils/.gitignore
+++ b/packages/core-utils/.gitignore
@@ -1,2 +1,2 @@
 node_modules/
-build/
\ No newline at end of file
+build/
diff --git a/packages/core-utils/README.md b/packages/core-utils/README.md
index fc01bdfdfe785aa665f9c18e8845d58f1931ef39..30d9b240fc03c838c435d4d298259c8dddcd05f4 100644
--- a/packages/core-utils/README.md
+++ b/packages/core-utils/README.md
@@ -1,3 +1,5 @@
+[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=core-utils)](https://codecov.io/gh/ethereum-optimism/optimism)
+
 # @eth-optimism/core-utils
 
 ## What is this?
diff --git a/packages/core-utils/package.json b/packages/core-utils/package.json
index f8d27c97eb737febc023a59b5bcbc807edbf2421..c25ce0da7f329370053f4506bdbd72a07b637828 100644
--- a/packages/core-utils/package.json
+++ b/packages/core-utils/package.json
@@ -17,7 +17,8 @@
     "lint:check": "eslint .",
     "lint:fix": "yarn lint:check --fix",
     "pre-commit": "lint-staged",
-    "test": "ts-mocha test/**/*.spec.ts"
+    "test": "ts-mocha test/**/*.spec.ts",
+    "test:coverage": "nyc ts-mocha test/**/*.spec.ts && nyc merge .nyc_output coverage.json"
   },
   "devDependencies": {
     "@types/chai": "^4.2.17",
@@ -26,20 +27,21 @@
     "@types/prettier": "^2.2.3",
     "@typescript-eslint/eslint-plugin": "^4.26.0",
     "@typescript-eslint/parser": "^4.26.0",
-    "chai": "^4.3.0",
     "babel-eslint": "^10.1.0",
+    "chai": "^4.3.0",
     "eslint": "^7.27.0",
-    "eslint-plugin-prettier": "^3.4.0",
     "eslint-config-prettier": "^8.3.0",
     "eslint-plugin-ban": "^1.5.2",
     "eslint-plugin-import": "^2.23.4",
     "eslint-plugin-jsdoc": "^35.1.2",
     "eslint-plugin-prefer-arrow": "^1.2.3",
+    "eslint-plugin-prettier": "^3.4.0",
     "eslint-plugin-react": "^7.24.0",
     "eslint-plugin-unicorn": "^32.0.1",
+    "lint-staged": "11.0.0",
     "mocha": "^8.3.0",
+    "nyc": "^15.1.0",
     "prettier": "^2.2.1",
-    "lint-staged": "11.0.0",
     "ts-mocha": "^8.0.0",
     "typescript": "^4.2.3"
   },
diff --git a/packages/core-utils/src/fees.ts b/packages/core-utils/src/fees.ts
index 5c9013a7edfb2f18f7d54de10f5d4328260f6db6..dd1a37b77a53093ca07bdc510f5ac56b00a5d383 100644
--- a/packages/core-utils/src/fees.ts
+++ b/packages/core-utils/src/fees.ts
@@ -8,7 +8,7 @@ import { remove0x } from './common'
 const feeScalar = 10_000_000
 const txDataZeroGas = 4
 const txDataNonZeroGasEIP2028 = 16
-const overhead = 4200 + 200 * txDataNonZeroGasEIP2028
+const overhead = 2750
 const tenThousand = BigNumber.from(10_000)
 export const TxGasPrice = BigNumber.from(feeScalar + feeScalar / 2)
 export interface EncodableL2GasLimit {
diff --git a/packages/core-utils/test/coders/batch-encoder.spec.ts b/packages/core-utils/test/coders/batch-encoder.spec.ts
index 473443e2a97c5130e62ad799d3db4ba280a1228c..ab647dc61de81fa54537879cf5c7c8c9fdea64d8 100644
--- a/packages/core-utils/test/coders/batch-encoder.spec.ts
+++ b/packages/core-utils/test/coders/batch-encoder.spec.ts
@@ -50,5 +50,28 @@ describe('BatchEncoder', () => {
         expect(encoded).to.equal(calldata)
       }
     })
+
+    it('should throw an error', () => {
+      const batch = {
+        shouldStartAtElement: 10,
+        totalElementsToAppend: 1,
+        contexts: [
+          {
+            numSequencedTransactions: 2,
+            numSubsequentQueueTransactions: 1,
+            timestamp: 100,
+            blockNumber: 200,
+          },
+        ],
+        transactions: ['0x454234000000112', '0x45423400000012'],
+      }
+      expect(() => encodeAppendSequencerBatch(batch)).to.throw(
+        'Unexpected uneven hex string value!'
+      )
+
+      expect(() => sequencerBatch.decode('0x')).to.throw(
+        'Incorrect function signature'
+      )
+    })
   })
 })
diff --git a/packages/core-utils/test/common/hex-utils.spec.ts b/packages/core-utils/test/common/hex-utils.spec.ts
index 1b7260e2cec48f770bafb93a19377ee179306bc9..3e0cc3c3bbc0e1d8d3abbd8a2af7f6fcebaee65e 100644
--- a/packages/core-utils/test/common/hex-utils.spec.ts
+++ b/packages/core-utils/test/common/hex-utils.spec.ts
@@ -2,7 +2,105 @@ import { expect } from '../setup'
 import { BigNumber } from 'ethers'
 
 /* Imports: Internal */
-import { toRpcHexString } from '../../src'
+import {
+  toRpcHexString,
+  remove0x,
+  add0x,
+  fromHexString,
+  toHexString,
+  padHexString,
+} from '../../src'
+
+describe('remove0x', () => {
+  it('should return undefined', () => {
+    expect(remove0x(undefined)).to.deep.equal(undefined)
+  })
+
+  it('should return without a 0x', () => {
+    const cases = [
+      { input: '0x', output: '' },
+      {
+        input: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+        output: '1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+      },
+      { input: 'a', output: 'a' },
+    ]
+    for (const test of cases) {
+      expect(remove0x(test.input)).to.deep.equal(test.output)
+    }
+  })
+})
+
+describe('add0x', () => {
+  it('should return undefined', () => {
+    expect(add0x(undefined)).to.deep.equal(undefined)
+  })
+
+  it('should return with a 0x', () => {
+    const cases = [
+      { input: '0x', output: '0x' },
+      {
+        input: '1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+        output: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+      },
+      { input: '', output: '0x' },
+    ]
+    for (const test of cases) {
+      expect(add0x(test.input)).to.deep.equal(test.output)
+    }
+  })
+})
+
+describe('toHexString', () => {
+  it('should return undefined', () => {
+    expect(add0x(undefined)).to.deep.equal(undefined)
+  })
+
+  it('should return with a hex string', () => {
+    const cases = [
+      { input: 0, output: '0x00' },
+      {
+        input: '0',
+        output: '0x30',
+      },
+      { input: '', output: '0x' },
+    ]
+    for (const test of cases) {
+      expect(toHexString(test.input)).to.deep.equal(test.output)
+    }
+  })
+})
+
+describe('fromHexString', () => {
+  it('should return a buffer from a hex string', () => {
+    const cases = [
+      { input: '0x', output: Buffer.from('', 'hex') },
+      {
+        input: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
+        output: Buffer.from('1f9840a85d5af5bf1d1762f925bdaddc4201f984', 'hex'),
+      },
+      { input: '', output: Buffer.from('', 'hex') },
+      {
+        input: Buffer.from('1f9840a85d5af5bf1d1762f925bdaddc4201f984'),
+        output: Buffer.from('1f9840a85d5af5bf1d1762f925bdaddc4201f984'),
+      },
+    ]
+
+    for (const test of cases) {
+      expect(fromHexString(test.input)).to.deep.equal(test.output)
+    }
+  })
+})
+
+describe('padHexString', () => {
+  it('should return return input string if length is 2 + length * 2', () => {
+    expect(padHexString('abcd', 1)).to.deep.equal('abcd')
+    expect(padHexString('abcdefgh', 3).length).to.deep.equal(8)
+  })
+  it('should return a string padded with 0x and zeros', () => {
+    expect(padHexString('0xabcd', 3)).to.deep.equal('0x00abcd')
+  })
+})
 
 describe('toRpcHexString', () => {
   it('should parse 0', () => {
diff --git a/packages/core-utils/test/common/misc.spec.ts b/packages/core-utils/test/common/misc.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a8d0859e1a5d6fa3549617822f3229ec3aa79162
--- /dev/null
+++ b/packages/core-utils/test/common/misc.spec.ts
@@ -0,0 +1,13 @@
+import { expect } from '../setup'
+
+/* Imports: Internal */
+import { sleep } from '../../src'
+
+describe('sleep', async () => {
+  it('should return wait input amount of ms', async () => {
+    const startTime = Date.now()
+    await sleep(1000)
+    const endTime = Date.now()
+    expect(startTime + 1000 <= endTime).to.deep.equal(true)
+  })
+})
diff --git a/packages/core-utils/test/fees/fees.spec.ts b/packages/core-utils/test/fees/fees.spec.ts
index d5c1debf1052cb4b30029471ac65aa9cc3c525a2..e3272b256d1d38dea593b9318389a615c0598fa2 100644
--- a/packages/core-utils/test/fees/fees.spec.ts
+++ b/packages/core-utils/test/fees/fees.spec.ts
@@ -1,8 +1,9 @@
 import { expect } from '../setup'
 import * as fees from '../../src/fees'
-import { utils } from 'ethers'
+import { BigNumber, utils } from 'ethers'
 
 const hundredBillion = 10 ** 11
+const tenThousand = 10 ** 4
 
 describe('Fees', () => {
   it('should count zeros and ones', () => {
@@ -116,5 +117,12 @@ describe('Fees', () => {
         expect(decoded).to.deep.eq(roundedL2GasLimit)
       })
     }
+
+    it('should decode numbers', () => {
+      const x = 1
+      expect(fees.TxGasLimit.decode(x)).to.deep.equal(
+        BigNumber.from(x * tenThousand)
+      )
+    })
   })
 })
diff --git a/packages/data-transport-layer/README.md b/packages/data-transport-layer/README.md
index f6293199293e62f3b5aa21c565ef4cce273b9ac3..4bcb0703779af1d4bfcef11f73b219d5805f9435 100644
--- a/packages/data-transport-layer/README.md
+++ b/packages/data-transport-layer/README.md
@@ -1,3 +1,4 @@
+[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=data-transport-layer)](https://codecov.io/gh/ethereum-optimism/optimism)
 # @eth-optimism/data-transport-layer
 
 ## What is this?
diff --git a/packages/data-transport-layer/package.json b/packages/data-transport-layer/package.json
index c7b19af8cc35062bdf25e68ef13a3fcbd9a88915..957066289a11e0741dc3ba90d480493f351c7e83 100644
--- a/packages/data-transport-layer/package.json
+++ b/packages/data-transport-layer/package.json
@@ -18,6 +18,7 @@
     "start": "ts-node ./src/services/run.ts",
     "start:local": "ts-node ./src/services/run.ts | pino-pretty",
     "test": "hardhat --config test/config/hardhat.config.ts test",
+    "test:coverage": "nyc hardhat --config test/config/hardhat.config.ts test && nyc merge .nyc_output coverage.json",
     "build": "tsc -p tsconfig.build.json",
     "pre-commit": "lint-staged"
   },
diff --git a/packages/message-relayer/README.md b/packages/message-relayer/README.md
index 964f1a67e5e9dc09b37584d7f5818e8d8ffc0d0b..5d591c9fe85d1f9546ab369baeff65235d02e7e5 100644
--- a/packages/message-relayer/README.md
+++ b/packages/message-relayer/README.md
@@ -1,3 +1,4 @@
+[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=message-relayer)](https://codecov.io/gh/ethereum-optimism/optimism)
 # @eth-optimism/message-relayer
 
 This package contains:
@@ -63,7 +64,7 @@ const main = async () => {
   //     proof
   //   )
   // }
-} 
+}
 
 main()
 ```
diff --git a/packages/message-relayer/package.json b/packages/message-relayer/package.json
index 6e81ca263e7917f4f55ecd394c387b0d5097cde0..254b10f31fbce6a141dcfc8580528dcaeb1919fa 100644
--- a/packages/message-relayer/package.json
+++ b/packages/message-relayer/package.json
@@ -18,7 +18,8 @@
     "pre-commit": "lint-staged",
     "lint:fix": "yarn lint:check --fix",
     "lint:check": "eslint .",
-    "test": "hardhat test --show-stack-traces"
+    "test": "hardhat test --show-stack-traces",
+    "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
   },
   "keywords": [
     "optimism",
diff --git a/yarn.lock b/yarn.lock
index 28147d7a60a4f56c19ddbb4c014a4da861ed209c..37303fd9ab9c868cfd2fdc84ce71269057cb226e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -21,7 +21,7 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176"
   integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==
 
-"@babel/core@^7.12.16":
+"@babel/core@^7.12.16", "@babel/core@^7.7.5":
   version "7.15.0"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8"
   integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==
@@ -734,7 +734,7 @@
     "@ethersproject/logger" "^5.4.0"
     "@ethersproject/properties" "^5.4.0"
 
-"@ethersproject/address@5.4.0", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.0", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.4.0":
+"@ethersproject/address@5.4.0", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.4.0":
   version "5.4.0"
   resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.4.0.tgz#ba2d00a0f8c4c0854933b963b9a3a9f6eb4a37a3"
   integrity sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q==
@@ -1070,6 +1070,22 @@
   resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
   integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==
 
+"@istanbuljs/load-nyc-config@^1.0.0":
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
+  integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
+  dependencies:
+    camelcase "^5.3.1"
+    find-up "^4.1.0"
+    get-package-type "^0.1.0"
+    js-yaml "^3.13.1"
+    resolve-from "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
+  integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
+
 "@ledgerhq/cryptoassets@^5.27.2":
   version "5.53.0"
   resolved "https://registry.yarnpkg.com/@ledgerhq/cryptoassets/-/cryptoassets-5.53.0.tgz#11dcc93211960c6fd6620392e4dd91896aaabe58"
@@ -1900,6 +1916,19 @@
   resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.2.tgz#c472abcba0c5185aaa4ad4070146e95213c68511"
   integrity sha512-6quxWe8wwS4X5v3Au8q1jOvXYEPkS1Fh+cME5u6AwNdnI4uERvPlVjlgRWzpnb+Rrt1l/cEqiNRH9GlsBMSDQg==
 
+"@nomiclabs/hardhat-etherscan@^2.1.5":
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-2.1.5.tgz#bfd09784dbd0982dbab27f28ca4fb4671b1cd5f6"
+  integrity sha512-Vxm1hcVrpgNg1yf/oBjkMuOpjz88cq9UiFUHdmnLNDgXfGNb+J/BtuZSCiVnRaS81OeEeXfjrTA5B31UiscaLA==
+  dependencies:
+    "@ethersproject/abi" "^5.1.2"
+    "@ethersproject/address" "^5.0.2"
+    cbor "^5.0.2"
+    debug "^4.1.1"
+    fs-extra "^7.0.1"
+    node-fetch "^2.6.0"
+    semver "^6.3.0"
+
 "@nomiclabs/hardhat-waffle@^2.0.1":
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz#5d43654fba780720c5033dea240fe14f70ef4bd2"
@@ -2072,14 +2101,14 @@
     "@octokit/openapi-types" "^9.5.0"
 
 "@openzeppelin/contracts-upgradeable@^3.3.0":
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-3.4.1.tgz#38dfdfa86fda0a088c6fcdebe6870cfaf897b471"
-  integrity sha512-wBGlUzEkOxcj/ghtcF2yKc8ZYh+PTUtm1mK38zoENulJ6aplij7eH8quo3lMugfzPJy+V6V5qI8QhdQmCn7hkQ==
+  version "3.4.2"
+  resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-3.4.2.tgz#2c2a1b0fa748235a1f495b6489349776365c51b3"
+  integrity sha512-mDlBS17ymb2wpaLcrqRYdnBAmP1EwqhOXMvqWk2c5Q1N1pm5TkiCtXM9Xzznh4bYsQBq0aIWEkFFE2+iLSN1Tw==
 
 "@openzeppelin/contracts@^3.3.0":
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1.tgz#03c891fec7f93be0ae44ed74e57a122a38732ce7"
-  integrity sha512-cUriqMauq1ylzP2TxePNdPqkwI7Le3Annh4K9rrpvKfSBB/bdW+Iu1ihBaTIABTAAJ85LmKL5SSPPL9ry8d1gQ==
+  version "3.4.2"
+  resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527"
+  integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA==
 
 "@resolver-engine/core@^0.3.3":
   version "0.3.3"
@@ -3212,6 +3241,13 @@ anymatch@~3.1.1, anymatch@~3.1.2:
     normalize-path "^3.0.0"
     picomatch "^2.0.4"
 
+append-transform@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12"
+  integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==
+  dependencies:
+    default-require-extensions "^3.0.0"
+
 aproba@^1.0.3:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -3222,6 +3258,11 @@ aproba@^2.0.0:
   resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
   integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
 
+archy@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
+  integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
+
 are-we-there-yet@~1.1.2:
   version "1.1.5"
   resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
@@ -4476,6 +4517,16 @@ cachedown@1.0.0:
     abstract-leveldown "^2.4.1"
     lru-cache "^3.2.0"
 
+caching-transform@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f"
+  integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==
+  dependencies:
+    hasha "^5.0.0"
+    make-dir "^3.0.0"
+    package-hash "^4.0.0"
+    write-file-atomic "^3.0.0"
+
 call-bind@^1.0.0, call-bind@^1.0.2, call-bind@~1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@@ -4560,6 +4611,14 @@ caseless@^0.12.0, caseless@~0.12.0:
   resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
   integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
 
+cbor@^5.0.2:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c"
+  integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==
+  dependencies:
+    bignumber.js "^9.0.1"
+    nofilter "^1.0.4"
+
 chai-as-promised@^7.1.1:
   version "7.1.1"
   resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0"
@@ -4982,6 +5041,11 @@ comment-parser@1.1.6-beta.0:
   resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.1.6-beta.0.tgz#57e503b18d0a5bd008632dcc54b1f95c2fffe8f6"
   integrity sha512-q3cA8TSMyqW7wcPSYWzbO/rMahnXgzs4SLG/UIWXdEsnXTFPZkEkWAdNgPiHig2OzxgpPLOh4WwsmClDxndwHw==
 
+commondir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+  integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
+
 compare-func@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3"
@@ -5298,7 +5362,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
     shebang-command "^1.2.0"
     which "^1.2.9"
 
-cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
   version "7.0.3"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
   integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@@ -5505,6 +5569,13 @@ deep-is@^0.1.3, deep-is@~0.1.3:
   resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
   integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
 
+default-require-extensions@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96"
+  integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==
+  dependencies:
+    strip-bom "^4.0.0"
+
 defaults@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
@@ -5937,6 +6008,11 @@ es5-ext@^0.10.35, es5-ext@^0.10.50:
     es6-symbol "~3.1.3"
     next-tick "~1.0.0"
 
+es6-error@^4.0.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
+  integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
+
 es6-iterator@~2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
@@ -7186,6 +7262,15 @@ finalhandler@~1.1.2:
     statuses "~1.5.0"
     unpipe "~1.0.0"
 
+find-cache-dir@^3.2.0:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b"
+  integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==
+  dependencies:
+    commondir "^1.0.1"
+    make-dir "^3.0.2"
+    pkg-dir "^4.1.0"
+
 find-replace@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0"
@@ -7333,6 +7418,14 @@ foreach@^2.0.5:
   resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
   integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
 
+foreground-child@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53"
+  integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==
+  dependencies:
+    cross-spawn "^7.0.0"
+    signal-exit "^3.0.2"
+
 forever-agent@~0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@@ -7397,6 +7490,11 @@ fresh@0.5.2:
   resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
   integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
 
+fromentries@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a"
+  integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==
+
 fs-constants@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
@@ -7588,6 +7686,11 @@ get-own-enumerable-property-symbols@^3.0.0:
   resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
   integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
 
+get-package-type@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+  integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
 get-pkg-repo@^4.0.0:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.1.2.tgz#c4ffd60015cf091be666a0212753fc158f01a4c0"
@@ -8120,6 +8223,14 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7:
     inherits "^2.0.3"
     minimalistic-assert "^1.0.1"
 
+hasha@^5.0.0:
+  version "5.2.2"
+  resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1"
+  integrity sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==
+  dependencies:
+    is-stream "^2.0.0"
+    type-fest "^0.8.0"
+
 he@1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -8164,6 +8275,11 @@ hosted-git-info@^4.0.0, hosted-git-info@^4.0.1:
   dependencies:
     lru-cache "^6.0.0"
 
+html-escaper@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+  integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
 http-basic@^8.1.1:
   version "8.1.3"
   resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-8.1.3.tgz#a7cabee7526869b9b710136970805b1004261bbf"
@@ -8897,6 +9013,67 @@ isstream@~0.1.2:
   resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
   integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
 
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
+  integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
+
+istanbul-lib-hook@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6"
+  integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==
+  dependencies:
+    append-transform "^2.0.0"
+
+istanbul-lib-instrument@^4.0.0:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d"
+  integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==
+  dependencies:
+    "@babel/core" "^7.7.5"
+    "@istanbuljs/schema" "^0.1.2"
+    istanbul-lib-coverage "^3.0.0"
+    semver "^6.3.0"
+
+istanbul-lib-processinfo@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c"
+  integrity sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==
+  dependencies:
+    archy "^1.0.0"
+    cross-spawn "^7.0.0"
+    istanbul-lib-coverage "^3.0.0-alpha.1"
+    make-dir "^3.0.0"
+    p-map "^3.0.0"
+    rimraf "^3.0.0"
+    uuid "^3.3.3"
+
+istanbul-lib-report@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6"
+  integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==
+  dependencies:
+    istanbul-lib-coverage "^3.0.0"
+    make-dir "^3.0.0"
+    supports-color "^7.1.0"
+
+istanbul-lib-source-maps@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9"
+  integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==
+  dependencies:
+    debug "^4.1.1"
+    istanbul-lib-coverage "^3.0.0"
+    source-map "^0.6.1"
+
+istanbul-reports@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b"
+  integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==
+  dependencies:
+    html-escaper "^2.0.0"
+    istanbul-lib-report "^3.0.0"
+
 isurl@^1.0.0-alpha5:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
@@ -9634,6 +9811,11 @@ lodash.clonedeep@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
   integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
 
+lodash.flattendeep@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
+  integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
+
 lodash.get@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
@@ -9802,7 +9984,7 @@ make-dir@^2.1.0:
     pify "^4.0.1"
     semver "^5.6.0"
 
-make-dir@^3.0.0:
+make-dir@^3.0.0, make-dir@^3.0.2:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
   integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
@@ -10780,11 +10962,23 @@ node-hid@2.1.1:
     node-addon-api "^3.0.2"
     prebuild-install "^6.0.0"
 
+node-preload@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301"
+  integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==
+  dependencies:
+    process-on-spawn "^1.0.0"
+
 node-releases@^1.1.75:
   version "1.1.75"
   resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe"
   integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==
 
+nofilter@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e"
+  integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==
+
 noms@0.0.0:
   version "0.0.0"
   resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
@@ -10980,6 +11174,39 @@ number-to-bn@1.7.0:
     bn.js "4.11.6"
     strip-hex-prefix "1.0.0"
 
+nyc@^15.1.0:
+  version "15.1.0"
+  resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02"
+  integrity sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==
+  dependencies:
+    "@istanbuljs/load-nyc-config" "^1.0.0"
+    "@istanbuljs/schema" "^0.1.2"
+    caching-transform "^4.0.0"
+    convert-source-map "^1.7.0"
+    decamelize "^1.2.0"
+    find-cache-dir "^3.2.0"
+    find-up "^4.1.0"
+    foreground-child "^2.0.0"
+    get-package-type "^0.1.0"
+    glob "^7.1.6"
+    istanbul-lib-coverage "^3.0.0"
+    istanbul-lib-hook "^3.0.0"
+    istanbul-lib-instrument "^4.0.0"
+    istanbul-lib-processinfo "^2.0.2"
+    istanbul-lib-report "^3.0.0"
+    istanbul-lib-source-maps "^4.0.0"
+    istanbul-reports "^3.0.2"
+    make-dir "^3.0.0"
+    node-preload "^0.2.1"
+    p-map "^3.0.0"
+    process-on-spawn "^1.0.0"
+    resolve-from "^5.0.0"
+    rimraf "^3.0.0"
+    signal-exit "^3.0.2"
+    spawn-wrap "^2.0.0"
+    test-exclude "^6.0.0"
+    yargs "^15.0.2"
+
 oauth-sign@~0.9.0:
   version "0.9.0"
   resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
@@ -11314,6 +11541,13 @@ p-map@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
   integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
 
+p-map@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d"
+  integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==
+  dependencies:
+    aggregate-error "^3.0.0"
+
 p-map@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
@@ -11370,6 +11604,16 @@ p-waterfall@^2.1.1:
   dependencies:
     p-reduce "^2.0.0"
 
+package-hash@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506"
+  integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==
+  dependencies:
+    graceful-fs "^4.1.15"
+    hasha "^5.0.0"
+    lodash.flattendeep "^4.4.0"
+    release-zalgo "^1.0.0"
+
 pacote@^11.2.6:
   version "11.3.5"
   resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2"
@@ -11714,7 +11958,7 @@ pkg-dir@^2.0.0:
   dependencies:
     find-up "^2.1.0"
 
-pkg-dir@^4.2.0:
+pkg-dir@^4.1.0, pkg-dir@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
   integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
@@ -11857,6 +12101,13 @@ process-nextick-args@~2.0.0:
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
   integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
 
+process-on-spawn@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93"
+  integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==
+  dependencies:
+    fromentries "^1.2.0"
+
 process@^0.11.10:
   version "0.11.10"
   resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -12469,6 +12720,13 @@ regjsparser@^0.1.4:
   dependencies:
     jsesc "~0.5.0"
 
+release-zalgo@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730"
+  integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=
+  dependencies:
+    es6-error "^4.0.1"
+
 repeat-element@^1.1.2:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
@@ -12706,7 +12964,7 @@ rimraf@^2.2.8, rimraf@^2.6.3:
   dependencies:
     glob "^7.1.3"
 
-rimraf@^3.0.2:
+rimraf@^3.0.0, rimraf@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
   integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -13373,6 +13631,18 @@ source-map@~0.2.0:
   dependencies:
     amdefine ">=0.0.4"
 
+spawn-wrap@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e"
+  integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==
+  dependencies:
+    foreground-child "^2.0.0"
+    is-windows "^1.0.2"
+    make-dir "^3.0.0"
+    rimraf "^3.0.0"
+    signal-exit "^3.0.2"
+    which "^2.0.1"
+
 spawndamnit@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/spawndamnit/-/spawndamnit-2.0.0.tgz#9f762ac5c3476abb994b42ad592b5ad22bb4b0ad"
@@ -13940,6 +14210,15 @@ term-size@^2.1.0:
   resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
   integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
 
+test-exclude@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+  integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
+  dependencies:
+    "@istanbuljs/schema" "^0.1.2"
+    glob "^7.1.4"
+    minimatch "^3.0.4"
+
 test-value@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291"
@@ -14352,7 +14631,7 @@ type-fest@^0.7.1:
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
   integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
 
-type-fest@^0.8.1:
+type-fest@^0.8.0, type-fest@^0.8.1:
   version "0.8.1"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
   integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
@@ -14680,7 +14959,7 @@ uuid@3.3.2:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
   integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
 
-uuid@^3.3.2:
+uuid@^3.3.2, uuid@^3.3.3:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
   integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
@@ -15680,7 +15959,7 @@ yargs@16.2.0, yargs@^16.1.0, yargs@^16.2.0:
     y18n "^5.0.5"
     yargs-parser "^20.2.2"
 
-yargs@^15.1.0:
+yargs@^15.0.2, yargs@^15.1.0:
   version "15.4.1"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
   integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==