diff --git a/src/index.ts b/src/index.ts index b5e7bae..6fdce8b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,34 +1,51 @@ - import { singleton } from "./decorator/singleton.decorator"; -import Web3 from 'web3'; -import { recoverTypedSignature, signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util'; -import 'whatwg-fetch' +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 { + 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 { + checkPassword, + loadData, + saveData, + savePassword, +} 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"; +import { + newAccount, + newMnemonic, + restoreWalletByMnemonic, +} from "./manage/WalletManage"; import { signLogin } from "./util/sign.util"; - var global = - (typeof globalThis !== 'undefined' && globalThis) || - (typeof self !== 'undefined' && self) || - (typeof global !== 'undefined' && 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 - } + interface Window { + jc: { + wallet: JCWallet; + }; + jcwallet: JCWallet; + ethSigUtil: any; + cc: any; + Stream: any; + } } // window.Buffer = require('buffer').Buffer; @@ -36,118 +53,119 @@ declare global { // window.Stream = require('stream-browserify'); export interface IChainData { - name: string, - type: string, - rpc: string, - id: number, - symbol: string, - explorerurl: string + 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 + 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() { + constructor(password: string) { // this.web3 = new Web3('https://rpc-mainnet.kcc.network') + if (!password) { + throw new Error("need password"); + } + if (!checkPassword(password)) { + throw new Error("password error"); + } + this.password = password; + savePassword(password); var start = Date.now(); - this.web3 = new Web3('https://rpc-testnet.kcc.network') - console.log(`init web3 cost: ${(Date.now() - start)/ 1000}`) + this.web3 = new Web3("https://rpc-testnet.kcc.network"); + console.log(`init web3 cost: ${(Date.now() - start) / 1000}`); this.erc20Standard = new ERC20Standard(this.web3); this.erc721Standard = new ERC721Standard(this.web3); start = Date.now(); - this.wallet = this.web3.eth.accounts.wallet.load(this.password, WALLET_STORAGE_KEY_NAME) - console.log(`load wallet cost: ${(Date.now() - start)/ 1000}`) - start = Date.now() - this.data = loadData() - console.log(`init wallet ext data cost: ${(Date.now() - start)/ 1000}`) - + this.wallet = this.web3.eth.accounts.wallet.load( + this.password, + WALLET_STORAGE_KEY_NAME + ); + console.log(`load wallet cost: ${(Date.now() - start) / 1000}`); + start = Date.now(); + this.data = loadData(); + console.log(`init wallet ext data cost: ${(Date.now() - start) / 1000}`); window.jc = { wallet: this }; - window.cc = window.cc || {}; - window.cc.walletCallback = (dataStr: string) => { - console.log('[Native CB]::' + dataStr) - } - this.init({chains: [322, 97]}) + // window.cc = window.cc || {}; + // window.cc.walletCallback = (dataStr: string) => { + // console.log('[Native CB]::' + dataStr) + // } + this.init({ chains: [322, 97], password }); } - - - public init({chains}: {chains: number[]}) { + + public init({ chains, password }: { chains: number[]; password: string }) { for (let chain of chains) { - this.chainSet.add(chain) + this.chainSet.add(chain); if (!this.chainMap.has(chain)) { - let data = AllChains.find(o => o.id === chain) + let data = AllChains.find((o) => o.id === chain); if (data) { this.chainMap.set(chain, data); if (!this._currentChain) { - this._currentChain = data + this._currentChain = data; } } } } if (!this.wallet || this.wallet.length === 0) { // this.createAccount(); - this.newWallet('111111'); + this.newWallet(password); } } public newWallet(password: string) { - this.password = password - newMnemonic(this.password) - this.createAccount() + this.password = password; + newMnemonic(this.password); + this.createAccount(); } public restoreFromMnemonic(mnemonic: string, password: string) { - this.password = password - this.wallet.clear() + this.password = password; + this.wallet.clear(); restoreWalletByMnemonic(mnemonic, this.password); - this.createAccount() + this.createAccount(); } get currentChain() { - return this._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') + 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) + this.mainHandlers.emit(WALLET_TOKEN_TYPE_CHANGE, type); } get chainList() { - return [...this.chainMap.values()] + return [...this.chainMap.values()]; } - public saveLocal() { - - } + public saveLocal() {} - public loadLocal() { + public loadLocal() {} - } - - public saveRemove() { + public saveRemote() {} - } - - public loadRemote() { - - } + public loadRemote() {} public currentAccount() { return this.wallet[this.accountIndex]; @@ -155,77 +173,77 @@ export default class JCWallet { get currentAccountData() { let address = this.currentAccount().address; - const chain = this.currentChain.id - let data = this.data.find(o => o.address === address) + const chain = this.currentChain.id; + let data = this.data.find((o) => o.address === address); if (!data) { - throw new Error('account data not found'); - } + throw new Error("account data not found"); + } if (!data.tokenData[chain]) { - let tokens = DEFALUT_TOKENS[chain] + let tokens = DEFALUT_TOKENS[chain]; data.tokenData[chain] = { tokens, heros: [], weapons: [], - chips: [] - } + chips: [], + }; } - saveData(this.data) - return data + saveData(this.data); + return data; } get accounts() { - return this.data + 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) + 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 }` + const nickname = `Account ${index + 1}`; data = initAccount({ - address: account.address, - chain, - nickname, - type: 0, - index - }) + address: account.address, + chain, + nickname, + type: 0, + index, + }); this.data.push(data); - saveData(this.data) + saveData(this.data); } - - this.accountIndex = this.wallet.length - 1 - this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, account.address) - return account.address + + this.accountIndex = this.wallet.length - 1; + this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, account.address); + return 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) + 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 }` + const nickname = `Imported ${index + 1}`; data = initAccount({ - address: account.address, - chain, - nickname, - type: 1, - index - }) + address: account.address, + chain, + nickname, + type: 1, + index, + }); this.data.push(data); - saveData(this.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 account.address + this.accountIndex = this.wallet.length - 1; + this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, account.address); + return account.address; } private getMaxIdexOfType(type: number) { @@ -236,74 +254,77 @@ export default class JCWallet { } maxIdx = Math.max(this.data[i].index, maxIdx); } - return maxIdx + 1 + return maxIdx + 1; } public selectAccount(address: string) { - let index = 0 - for (let i = 0, l = this.wallet.length; i < l ; i ++) { + let index = 0; + for (let i = 0, l = this.wallet.length; i < l; i++) { if (this.wallet[i].address === address) { - index = i - break + index = i; + break; } } if (index !== this.accountIndex && index < this.wallet.length) { - this.accountIndex = index - this.mainHandlers.emit(WALLET_ACCOUNT_CHANGE, this.wallet[index].address) + 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 }) + 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); + console.log("get balance with address: ", address); if (!address) { - let accountData = this.wallet[this.accountIndex] + let accountData = this.wallet[this.accountIndex]; if (!accountData) { - throw new Error('no account found') + throw new Error("no account found"); } - address = accountData.address + address = accountData.address; } - + let balance = await this.web3.eth.getBalance(address); - return balance + return balance; } public signTypedDataV4(signObj: any) { - const account = this.currentAccount() + const account = this.currentAccount(); return signTypedData({ data: signObj, - privateKey: Buffer.from(account.privateKey.replace('0x', ''), 'hex'), - version: SignTypedDataVersion.V4 - }) + privateKey: Buffer.from(account.privateKey.replace("0x", ""), "hex"), + version: SignTypedDataVersion.V4, + }); } public loginSign(nonce: string, tips: string) { const account = this.currentAccount(); - return signLogin(nonce, tips, account.privateKey) + return signLogin(nonce, tips, account.privateKey); } - public recoverTypedSignatureV4(signObj: any, signature: string) { return recoverTypedSignature({ data: signObj, signature, - version: SignTypedDataVersion.V4 - }) + 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 "./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'; +export * from "./config/chain_config"; diff --git a/src/manage/DataManage.ts b/src/manage/DataManage.ts index a330dc7..6e82f39 100644 --- a/src/manage/DataManage.ts +++ b/src/manage/DataManage.ts @@ -1,8 +1,11 @@ import { IAccount } from "../data/DataModel"; import { aesDecrypt, aesEncrypt } from "../util/crypto.util"; +import sha256 from 'crypto-js/sha256' const LOCAL_ACCOUNT_DATAS = 'local_account_datas' const LOCAL_WALLET_MNEMONIC = 'local_wallet_mnemonic' +const LOCAL_WALLET_PASSWORD = 'local_wallet_password'; +const LOCAL_PASSWORD_SALT = '_jcwallet'; export function loadData(){ @@ -31,9 +34,18 @@ export function loadMnemonic(password: string) { return dataStr } - - export function saveMnemonic(mnemonic: string, password: string) { const dataStr = aesEncrypt(mnemonic, password); localStorage.setItem(LOCAL_WALLET_MNEMONIC, dataStr); +} + +export function checkPassword(password: string) { + const localStr: string = localStorage.getItem(LOCAL_WALLET_PASSWORD); + const dataStr = sha256(password + LOCAL_PASSWORD_SALT).toString(); + return !localStr || localStr === dataStr; +} + +export function savePassword(password: string) { + const dataStr = sha256(password + LOCAL_PASSWORD_SALT).toString(); + localStorage.setItem(LOCAL_WALLET_PASSWORD, dataStr); } \ No newline at end of file