dotbit-sdk-allin
Version:
A complete .bit SDK and utilities in TypeScript
102 lines (86 loc) • 3.63 kB
text/typescript
import { MessageTypes, SignTypedDataVersion, TypedDataUtils, TypedMessage } from '@metamask/eth-sig-util'
import { JsonRpcSigner } from '@ethersproject/providers'
import { Wallet } from 'ethers'
import { AlgorithmId, CoinType, EvmChainId2CoinType } from '../const'
import { TxsSignedOrUnSigned } from '../fetchers/SubAccountAPI'
import { TxsWithMMJsonSignedOrUnSigned } from '../fetchers/RegisterAPI.type'
import { BitErrorCode, DotbitError } from '../errors/DotbitError'
import { remove0x } from '../tools/common'
function isMMJson (txs: TxsSignedOrUnSigned | TxsWithMMJsonSignedOrUnSigned): txs is TxsWithMMJsonSignedOrUnSigned {
return 'mm_json' in txs
}
/**
* get mmJson hash and chainId hex
* @param typedData
* @param chainId
*/
export function mmJsonHashAndChainIdHex (typedData: TypedMessage<any>, chainId: number): string {
const mmHash = TypedDataUtils.eip712Hash(typedData, SignTypedDataVersion.V4).toString('hex')
const chainIdHex = chainId.toString(16).padStart(16, '0')
return mmHash + chainIdHex
}
export interface SendTransactionParam {
to: string,
value: string,
data: string,
}
export abstract class BitSigner {
signer: JsonRpcSigner| Wallet
abstract signTypedData (data: TypedMessage<MessageTypes>): Promise<string>
abstract sendTransaction (sendTransactionParam: SendTransactionParam): Promise<string>
signPersonal (data: string| Buffer): Promise<string> {
return this.signer.signMessage(data)
}
getAddress () {
return this.signer.getAddress()
}
getChainId () {
return this.signer.getChainId()
}
async getCoinType (): Promise<CoinType> {
const chainId = await this.getChainId()
const coinType = EvmChainId2CoinType[chainId]
if (!coinType) {
throw new DotbitError(`Unsupported EVM chainId: ${chainId}`, BitErrorCode.UnsupportedEVMChainId)
}
return coinType
}
async signData (data: string | Buffer | object, isEIP712?: boolean): Promise<string> {
if (isEIP712) {
return await this.signTypedData(data as TypedMessage<MessageTypes>)
}
else {
return await this.signPersonal(data as string | Buffer)
}
}
// todo-open: TxsSignedOrUnSigned and TxsWithMMJsonSignedOrUnSigned is pretty much the same, while they are from different api. We need to unify them in backend.
async signTxList (txs: TxsSignedOrUnSigned): Promise<TxsSignedOrUnSigned>
async signTxList (txs: TxsWithMMJsonSignedOrUnSigned): Promise<TxsWithMMJsonSignedOrUnSigned>
async signTxList (txs: TxsSignedOrUnSigned | TxsWithMMJsonSignedOrUnSigned): Promise<TxsSignedOrUnSigned | TxsWithMMJsonSignedOrUnSigned> {
if (isMMJson(txs)) {
for (const signItem of txs.sign_list) {
if (signItem.sign_msg) {
if (signItem.sign_type === AlgorithmId.eip712) {
const mmJson = JSON.parse(JSON.stringify(txs.mm_json))
mmJson.message.digest = signItem.sign_msg
const signDataRes = await this.signTypedData(mmJson)
signItem.sign_msg = signDataRes + mmJsonHashAndChainIdHex(mmJson, mmJson.domain.chainId)
}
else {
signItem.sign_msg = await this.signData(Buffer.from(remove0x(signItem.sign_msg), 'hex'))
}
}
}
}
else {
for (const list of txs.list) {
for (const signItem of list.sign_list) {
if (signItem.sign_msg) {
signItem.sign_msg = await this.signData(Buffer.from(remove0x(signItem.sign_msg), 'hex'))
}
}
}
}
return txs
}
}