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 = new Set() private chainMap: Map = 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';