jcwallet/src/index.ts

296 lines
8.0 KiB
TypeScript

import { singleton } from "./decorator/singleton.decorator";
import Web3 from 'web3';
import { recoverTypedSignature, signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util';
import 'whatwg-fetch'
import { AllChains } from "./data/allchain";
import { createWalletEvents, WALLET_ACCOUNT_CHANGE, WALLET_CHAIN_CHANGE, WALLET_TOKEN_TYPE_CHANGE } from "./common/WalletEvent";
import { ERC20Standard } from "./standards/ERC20Standard";
import { ERC721Standard } from "./standards/ERC721Standard";
import { IAccount, initAccount } from "./data/DataModel";
import { loadData, saveData } from "./manage/DataManage";
import { WALLET_STORAGE_KEY_NAME } from "./config/constants";
import { DEFALUT_TOKENS } from "./config/chain_config";
import { newAccount, newMnemonic, restoreWalletByMnemonic } from "./manage/WalletManage";
var global =
(typeof globalThis !== 'undefined' && globalThis) ||
(typeof self !== 'undefined' && self) ||
(typeof global !== 'undefined' && global) ||
{}
declare global {
interface Window {
jc: {
wallet: JCWallet;
},
ethSigUtil: any,
cc: any
Stream: any
}
}
// window.Buffer = require('buffer').Buffer;
// window.process = require('process');
// window.Stream = require('stream-browserify');
export interface IChainData {
name: string,
type: string,
rpc: string,
id: number,
symbol: string,
explorerurl: string
}
@singleton
export default class JCWallet {
web3: Web3 = null
private wallet: any = null
private password: string = '111111'
private chainSet: Set<number> = new Set()
private chainMap: Map<number, IChainData> = new Map()
private _currentChain: IChainData
public erc20Standard: ERC20Standard
public erc721Standard: ERC721Standard
public mainHandlers = createWalletEvents()
public data: IAccount[] = []
public iconType = 'jazz'
private accountIndex = 0
constructor() {
// this.web3 = new Web3('https://rpc-mainnet.kcc.network')
this.web3 = new Web3('https://rpc-testnet.kcc.network')
this.erc20Standard = new ERC20Standard(this.web3);
this.erc721Standard = new ERC721Standard(this.web3);
this.wallet = this.web3.eth.accounts.wallet.load(this.password, WALLET_STORAGE_KEY_NAME)
this.data = loadData()
window.jc = { wallet: this };
window.cc = window.cc || {};
window.cc.walletCallback = (dataStr: string) => {
console.log('[Native CB]::' + dataStr)
}
this.init({chains: [322, 97]})
}
public init({chains}: {chains: number[]}) {
for (let chain of chains) {
this.chainSet.add(chain)
if (!this.chainMap.has(chain)) {
let data = AllChains.find(o => o.id === chain)
if (data) {
this.chainMap.set(chain, data);
if (!this._currentChain) {
this._currentChain = data
}
}
}
}
if (!this.wallet || this.wallet.length === 0) {
// this.createAccount();
this.newWallet('111111');
}
}
public newWallet(password: string) {
this.password = password
newMnemonic(this.password)
this.createAccount()
}
public restoreFromMnemonic(mnemonic: string, password: string) {
this.password = password
this.wallet.clear()
restoreWalletByMnemonic(mnemonic, this.password);
this.createAccount()
}
get currentChain() {
return this._currentChain
}
updateCurrentChain(chainId: number) {
const chainData = this.chainMap.get(chainId)
this._currentChain = chainData
this.web3.eth.setProvider(chainData.rpc)
this.mainHandlers.emit(WALLET_CHAIN_CHANGE, chainData)
this.updateListType('tokens')
}
updateListType(type: string) {
this.mainHandlers.emit(WALLET_TOKEN_TYPE_CHANGE, type)
}
get chainList() {
return [...this.chainMap.values()]
}
public saveLocal() {
}
public loadLocal() {
}
public saveRemove() {
}
public loadRemote() {
}
public currentAccount() {
return this.wallet[this.accountIndex];
}
get currentAccountData() {
let address = this.currentAccount().address;
const chain = this.currentChain.id
let data = this.data.find(o => o.address === address)
if (!data) {
throw new Error('account data not found');
}
if (!data.tokenData[chain]) {
let tokens = DEFALUT_TOKENS[chain]
data.tokenData[chain] = {
tokens,
heros: [],
weapons: [],
chips: []
}
}
saveData(this.data)
return data
}
get accounts() {
return this.data
}
public createAccount() {
// let account = this.web3.eth.accounts.create()
const index = this.getMaxIdexOfType(0);
const accountNew = newAccount(this.password, index)
const account = this.wallet.add(accountNew)
this.wallet.save(this.password, WALLET_STORAGE_KEY_NAME)
const chain = this.currentChain.id
let data = this.data.find(o => o.address === account.address)
if (!data) {
const nickname = `Account ${ index + 1 }`
data = initAccount({
address: account.address,
chain,
nickname,
type: 0,
index
})
this.data.push(data);
saveData(this.data)
}
this.accountIndex = this.wallet.length - 1
this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, account.address)
}
public importAccount(privateKey: string) {
const account = this.wallet.add(privateKey);
const chain = this.currentChain.id
let data = this.data.find(o => o.address === account.address)
if (!data) {
const index = this.getMaxIdexOfType(1);
const nickname = `Imported ${ index + 1 }`
data = initAccount({
address: account.address,
chain,
nickname,
type: 1,
index
})
this.data.push(data);
saveData(this.data)
}
this.web3.eth.accounts.wallet.save(this.password, WALLET_STORAGE_KEY_NAME);
this.accountIndex = this.wallet.length - 1
this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, account.address)
return true
}
private getMaxIdexOfType(type: number) {
let maxIdx = -1;
for (let i = 0, l = this.data.length; i < l; i++) {
if (this.data[i].type !== type) {
continue;
}
maxIdx = Math.max(this.data[i].index, maxIdx);
}
return maxIdx + 1
}
public selectAccount(address: string) {
let index = 0
for (let i = 0, l = this.wallet.length; i < l ; i ++) {
if (this.wallet[i].address === address) {
index = i
break
}
}
if (index !== this.accountIndex && index < this.wallet.length) {
this.accountIndex = index
this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, this.wallet[index].address)
}
}
public async sendEth(to: string, amount: number | string) {
let from = this.currentAccount().address;
const amountToSend = this.web3.utils.toWei(amount+'', "ether");
let gas = await this.web3.eth.estimateGas({ from, to, value: amountToSend })
this.web3.eth.sendTransaction({ from, to, gas, value: amountToSend });
}
public async getBalance(address?: string) {
console.log('get balance with address: ', address);
if (!address) {
let accountData = this.wallet[this.accountIndex]
if (!accountData) {
throw new Error('no account found')
}
address = accountData.address
}
let balance = await this.web3.eth.getBalance(address);
return balance
}
public signTypedDataV4(signObj: any) {
const account = this.currentAccount()
return signTypedData({
data: signObj,
privateKey: Buffer.from(account.privateKey.replace('0x', ''), 'hex'),
version: SignTypedDataVersion.V4
})
}
public recoverTypedSignatureV4(signObj: any, signature: string) {
return recoverTypedSignature({
data: signObj,
signature,
version: SignTypedDataVersion.V4
})
}
}
// window.jc = window.jc || {wallet: new JCWallet()};
export * from './common/WalletEvent'
export * from './common/ZError'
export * from './config/chain_config'
export * from './util/number.util'
export * from './util/wallet.util'
export * from "./data/DataModel";
export * from './config/chain_config';