Viewing File: /home/ubuntu/todaykat-frontend-base/node_modules/eth-json-rpc-middleware/wallet.js

const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware')
const createScaffoldMiddleware = require('json-rpc-engine/src/createScaffoldMiddleware')
const sigUtil = require('eth-sig-util')
const { ethErrors } = require('eth-rpc-errors')

module.exports = function createWalletMiddleware(opts = {}) {
  // parse + validate options
  const getAccounts = opts.getAccounts
  const processTypedMessage = opts.processTypedMessage
  const processTypedMessageV3 = opts.processTypedMessageV3
  const processTypedMessageV4 = opts.processTypedMessageV4
  const processPersonalMessage = opts.processPersonalMessage
  const processEthSignMessage = opts.processEthSignMessage
  const processTransaction = opts.processTransaction
  const processDecryptMessage = opts.processDecryptMessage
  const processEncryptionPublicKey = opts.processEncryptionPublicKey

  if (!getAccounts) {
    throw new Error('opts.getAccounts is required')
  }

  return createScaffoldMiddleware({
    // account lookups
    'eth_accounts': createAsyncMiddleware(lookupAccounts),
    'eth_coinbase': createAsyncMiddleware(lookupDefaultAccount),
    // tx signatures
    'eth_sendTransaction': createAsyncMiddleware(sendTransaction),
    // message signatures
    'eth_sign': createAsyncMiddleware(ethSign),
    'eth_signTypedData': createAsyncMiddleware(signTypedData),
    'eth_signTypedData_v3': createAsyncMiddleware(signTypedDataV3),
    'eth_signTypedData_v4': createAsyncMiddleware(signTypedDataV4),
    'personal_sign': createAsyncMiddleware(personalSign),
    'eth_getEncryptionPublicKey': createAsyncMiddleware(encryptionPublicKey),
    'eth_decrypt': createAsyncMiddleware(decryptMessage),
    'personal_ecRecover': createAsyncMiddleware(personalRecover),
  })

  //
  // account lookups
  //

  async function lookupAccounts(req, res) {
    res.result = await getAccounts(req)
  }

  async function lookupDefaultAccount(req, res) {
    const accounts = await getAccounts(req)
    res.result = accounts[0] || null
  }

  //
  // transaction signatures
  //

  async function sendTransaction(req, res) {

    if (!processTransaction) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const txParams = req.params[0] || {}
    txParams.from = await validateAndNormalizeKeyholder(txParams.from, req)
    res.result = await processTransaction(txParams, req)
  }

  //
  // message signatures
  //

  async function ethSign(req, res) {

    if (!processEthSignMessage) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const address = await validateAndNormalizeKeyholder(req.params[0], req)
    const message = req.params[1]
    const extraParams = req.params[2] || {}
    const msgParams = Object.assign({}, extraParams, {
      from: address,
      data: message,
    })

    res.result = await processEthSignMessage(msgParams, req)
  }

  async function signTypedData (req, res) {

    if (!processTypedMessage) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const message = req.params[0]
    const address = await validateAndNormalizeKeyholder(req.params[1], req)
    const version = 'V1'
    const extraParams = req.params[2] || {}
    const msgParams = Object.assign({}, extraParams, {
      from: address,
      data: message,
    })

    res.result = await processTypedMessage(msgParams, req, version)
  }

  async function signTypedDataV3 (req, res) {

    if (!processTypedMessageV3) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const address = await validateAndNormalizeKeyholder(req.params[0], req)
    const message = req.params[1]
    const version = 'V3'
    const msgParams = {
      data: message,
      from: address,
      version
    }

    res.result = await processTypedMessageV3(msgParams, req, version)
  }

  async function signTypedDataV4 (req, res) {

    if (!processTypedMessageV4) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const address = await validateAndNormalizeKeyholder(req.params[0], req)
    const message = req.params[1]
    const version = 'V4'
    const msgParams = {
      data: message,
      from: address,
      version
    }

    res.result = await processTypedMessageV4(msgParams, req, version)
  }

  async function personalSign (req, res) {

    if (!processPersonalMessage) {
      throw ethErrors.rpc.methodNotSupported()
    }

    // process normally
    const firstParam = req.params[0]
    const secondParam = req.params[1]
    // non-standard "extraParams" to be appended to our "msgParams" obj
    const extraParams = req.params[2] || {}

    // We initially incorrectly ordered these parameters.
    // To gracefully respect users who adopted this API early,
    // we are currently gracefully recovering from the wrong param order
    // when it is clearly identifiable.
    //
    // That means when the first param is definitely an address,
    // and the second param is definitely not, but is hex.
    let address, message
    if (resemblesAddress(firstParam) && !resemblesAddress(secondParam)) {
      let warning = `The eth_personalSign method requires params ordered `
      warning += `[message, address]. This was previously handled incorrectly, `
      warning += `and has been corrected automatically. `
      warning += `Please switch this param order for smooth behavior in the future.`
      res.warning = warning

      address = firstParam
      message = secondParam
    } else {
      message = firstParam
      address = secondParam
    }
    address = await validateAndNormalizeKeyholder(address, req)

    const msgParams = Object.assign({}, extraParams, {
      from: address,
      data: message,
    })
    
    res.result = await processPersonalMessage(msgParams, req)
  }

  async function personalRecover(req, res) {

    const message = req.params[0]
    const signature = req.params[1]
    const extraParams = req.params[2] || {}
    const msgParams = Object.assign({}, extraParams, {
      sig: signature,
      data: message,
    })
    const signerAddress = sigUtil.recoverPersonalSignature(msgParams)

    res.result = signerAddress
  }

  async function encryptionPublicKey (req, res) {

    if (!processEncryptionPublicKey) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const address = await validateAndNormalizeKeyholder(req.params[0], req)

    res.result = await processEncryptionPublicKey(address, req)
  }
	
  async function decryptMessage (req, res) {

    if (!processDecryptMessage) {
      throw ethErrors.rpc.methodNotSupported()
    }

    const ciphertext = req.params[0]
    const address = await validateAndNormalizeKeyholder(req.params[1], req)
    const extraParams = req.params[2] || {}
    const msgParams = Object.assign({}, extraParams, {
      from: address,
      data: ciphertext,
    })

    res.result = await processDecryptMessage(msgParams, req)
  }

  //
  // utility
  //

  /**
   * Validates the keyholder address, and returns a normalized (i.e. lowercase)
   * copy of it.
   * 
   * @param {string} address - The address to validate and normalize.
   * @param {Object} req - The request object.
   * @returns {string} - The normalized address, if valid. Otherwise, throws
   * an error
   */
  async function validateAndNormalizeKeyholder(address, req) {

    if (typeof address === 'string' && address.length > 0) {

      // ensure address is included in provided accounts
      const accounts = await getAccounts(req)
      const normalizedAccounts = accounts.map(_address => _address.toLowerCase())
      const normalizedAddress =  address.toLowerCase()

      if (normalizedAccounts.includes(normalizedAddress)) {
        return normalizedAddress
      }
    }
    throw ethErrors.rpc.invalidParams({
      message: `Invalid parameters: must provide an Ethereum address.`
    })
  }
}

function resemblesAddress (string) {
  // hex prefix 2 + 20 bytes
  return string.length === (2 + (20 * 2))
}
Back to Directory File Manager