philips-software/cogito

View on GitHub
workspaces/cogito-web3-provider/source/transaction-nonces.js

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import { JsonRpcClient } from './json-rpc-client'

// Calculates transaction nonces. The main problem that this code attempts to
// solve is that the ethereum node does not take pending transactions into
// account when returning the transaction count, leading to duplicated
// transaction nonces when sending a new transaction while another is pending
// (see https://github.com/ethereum/go-ethereum/issues/2880).
// Our solution is to keep a local transaction count, and synchronize that with
// the node transaction count when appropriate
// (loosely based on https://github.com/livepeer/go-livepeer/pull/252).

class TransactionNonces {
  constructor ({ provider }) {
    this.client = new JsonRpcClient({ provider })
    this.nonces = {}
  }

  async getNonce (transaction) {
    const localNonce = this.getLocalNonce(transaction)
    const remoteNonce = await this.getRemoteNonce(transaction)
    const nonce = Math.max(remoteNonce, localNonce)
    return `0x${nonce.toString(16)}`
  }

  commitNonce (transaction) {
    const nonce = parseInt(transaction.nonce.substr(2), 16)
    this.nonces[transaction.from] = nonce + 1
  }

  getLocalNonce (transaction) {
    const nonce = this.nonces[transaction.from] || 0
    return nonce
  }

  async getRemoteNonce (transaction) {
    const request = {
      method: 'eth_getTransactionCount',
      params: [ transaction.from, 'pending' ]
    }
    const nonceHex = (await this.client.send(request)).result
    return parseInt(nonceHex.substr(2), 16)
  }
}

export { TransactionNonces }