nova-ui/services/wallet/index.ts

179 lines
4.9 KiB
TypeScript
Raw Normal View History

2022-12-04 09:02:30 +03:00
import { Wallet, ethers } from 'ethers'
import { stripHexPrefix } from 'ethereumjs-util'
import { getEncryptionPublicKey, decrypt } from 'eth-sig-util'
import { privateStorage } from '@/services'
import { SendRequestParams, Params } from '@/services/provider/@types'
import { RPC_LIST } from '@/constants'
import { Options } from './@types'
export const signerMethods = [
'net_version',
'eth_chainId',
'eth_decrypt',
'eth_accounts',
'eth_signTypedData',
'eth_requestAccounts',
'eth_getTransactionByHash',
'eth_getBalance',
'eth_getTransactionReceipt',
'eth_sendTransaction',
'eth_getEncryptionPublicKey',
]
export const localConnector = () => {
const wallet = privateStorage.get('local_provider')
if (!wallet) {
throw new Error('Key is not enough')
}
// TODO add validation
const { key, chainId } = wallet.data
return new LocalProvider({ key, chainId })
}
export class LocalProvider {
private readonly wallet: Wallet
private readonly provider: ethers.providers.JsonRpcProvider
public constructor({ key, chainId }: Options) {
this.wallet = new Wallet(key)
this.provider = new ethers.providers.JsonRpcProvider(RPC_LIST[chainId])
this.wallet = this.wallet.connect(this.provider)
}
public async request({ method, params }: SendRequestParams) {
switch (method) {
case 'eth_requestAccounts':
return await this.requestAccounts()
case 'eth_accounts':
return await this.accounts()
case 'eth_chainId':
return await this.chainId()
case 'eth_decrypt':
return this.decrypt(params as string[])
case 'eth_getEncryptionPublicKey':
return this.getEncryptionPublicKey()
case 'eth_getTransactionByHash':
return await this.getTransactionByHash(params as string[])
case 'eth_getBalance':
return await this.getBalance(params as string[])
case 'eth_getTransactionReceipt':
return await this.getTransactionReceipt(params as string[])
case 'net_version':
return await this.chainId()
case 'eth_sendTransaction':
return await this.sendTransaction(params as Params[])
default:
throw new Error('unsupported method')
}
}
private decrypt([data]: string[]) {
try {
const stripped = stripHexPrefix(data)
const buff = Buffer.from(stripped, 'hex')
const msgData = JSON.parse(buff.toString('utf8'))
const privKey = stripHexPrefix(this.wallet.privateKey)
return decrypt(msgData, privKey)
} catch (err) {
throw new Error(`Provider method decrypt has error: ${err.message}`)
}
}
private getEncryptionPublicKey() {
try {
return getEncryptionPublicKey(this.wallet.privateKey)
} catch (err) {
throw new Error(`Provider method getEncryptionPublicKey has error: ${err.message}`)
}
}
private async requestAccounts() {
try {
const address = await this.wallet.getAddress()
return [address]
} catch (err) {
throw new Error(`Provider method requestAccounts has error: ${err.message}`)
}
}
private async accounts() {
try {
const address = await this.wallet.getAddress()
return [address]
} catch (err) {
throw new Error(`Provider method accounts has error: ${err.message}`)
}
}
private async chainId() {
try {
const network = await this.provider.getNetwork()
return network.chainId
} catch (err) {
throw new Error(`Provider method chainId has error: ${err.message}`)
}
}
private async getTransactionByHash([txHash]: string[]) {
try {
return await this.provider.getTransaction(txHash)
} catch (err) {
throw new Error(`Provider method getTransactionByHash has error: ${err.message}`)
}
}
private async getBalance([address]: string[]) {
try {
return await this.provider.getBalance(address)
} catch (err) {
throw new Error(`Provider method getBalance has error: ${err.message}`)
}
}
private async getTransactionReceipt([txHash]: string[]) {
try {
return await this.provider.getTransactionReceipt(txHash)
} catch (err) {
throw new Error(`Provider method getTransactionReceipt has error: ${err.message}`)
}
}
private async sendTransaction(params: Params[]) {
try {
const nonce = await this.wallet.getTransactionCount()
const [txParams] = params
// TODO validate
const newParams = {
nonce,
to: txParams.to,
from: txParams.from,
data: txParams.data,
value: txParams.value,
gasLimit: txParams.gas,
// ToDo EIP1559
gasPrice: txParams.gasPrice,
}
const signTx = await this.wallet.signTransaction(newParams)
const receipt = await this.provider.sendTransaction(signTx)
const { transactionHash } = await receipt.wait()
return transactionHash
} catch (err) {
throw new Error(`Provider method sendTransaction has error: ${err.message}`)
}
}
}