import { Blockchain } from '@/chain/blockchain' import { getNonce } from '@/api/User' import { useAppStore } from '@/store/app' import { useUserStore } from '@/store/user' import { message } from 'ant-design-vue' import { Chain } from '@/chain/Chain' import { AVAILABLE_CHAINS } from '@/configs/configchain' import { AllChains } from '@/configs/allchain' import { ACTIVATE_PROXY_ABI, MYSTERY_BOX_ABI, MYSTERY_PROXY_ABI } from '@/configs/contracts' const AppModule = useAppStore(); const UserModule = useUserStore(); export default class ChainManager { bc: Blockchain instanceMap: Map public chainMap: Map = new Map() private _availableChains: Map = new Map() constructor() { this.bc = new Blockchain() this.instanceMap = new Map() for (const data of AllChains) { this.chainMap.set(data.id, data) } } get availableChains() { if (this._availableChains.size === 0) { for (const id of AVAILABLE_CHAINS) { const d = this.chainMap.get(id) if (d) { this._availableChains.set(id, d) } } } return this._availableChains } public async init() { if (this.bc.isWalletConnect) { try { await this.bc.connect() await this.getNance() } catch (err) { console.log('connect chain error: ', err) } } } get isLogined() { return !!UserModule.token && !!AppModule.step } public async logout() { await this.bc.disconnect() } public get currentChain() { return this.bc.currentChain } public async login() { if (!AppModule.step) { try { await this.bc.connect(true) await this.checkNance() } catch (err) { message.error(err.message, 5) await Promise.reject(err) } } } public async checkNance() { try { let nonce = AppModule.nonce if (!nonce) { const preRequest: any = await getNonce({ account: AppModule.accountId, net_id: AppModule.chainId }) nonce = preRequest.nonce + '' AppModule.updateNonce(nonce) } await UserModule.Login({ bcInstance: this.bc, account: AppModule.accountId, chainId: AppModule.chainId, nonce }) AppModule.updateStep(1) } catch (err) { console.log(err) await Promise.reject(err) } } public async getNance() { console.log('need get nance') try { const preRequest: any = await getNonce({ account: AppModule.accountId, net_id: AppModule.chainId }) console.log('success get nonce: ', preRequest) // if need check sign and has nonce val, store it if (preRequest.state) { AppModule.updateStep(1) } else if (!preRequest.state && preRequest.nonce) { if (UserModule.token) { await UserModule.Logout() } AppModule.updateStep(0) } if (preRequest.nonce) { AppModule.updateNonce(preRequest.nonce + '') } } catch (err) { message.error('Error get login nonce', 5); } } public async getInstance(address: string, chainId: number, abi?: any) { const key = `${chainId}_${address}` if (!this.instanceMap.has(key)) { const chain = new Chain(this.chainMap.get(chainId)!.rpc) const coinInstance = await chain.initContractInstance(address, abi) this.instanceMap.set(key, coinInstance) } return this.instanceMap.get(key) } public async getBalance(address: string, chainId: number) { const coinInstance = await this.getInstance(address, chainId) const balance = await coinInstance.methods.balanceOf(AppModule.accountId).call() console.log('balance: ', balance) return balance } /** * get amount of mystery boxes * this method can get amount of general erc721 also * @param {string} address * @param {number} chainId * @return {Promise} */ public async getNftBalance(address: string, chainId: number) { const coinInstance = await this.getInstance(address, chainId, MYSTERY_BOX_ABI) const balance = await coinInstance.methods.balanceOf(AppModule.accountId).call() console.log('nft balance: ', balance) return balance } /** * Get NFT list of current user * @param {string} address NFT address * @param {number} chainId chain id * @param {number} start * @param {number} page */ public async getNftList(address: string, chainId: number, start = 0, page = 8) { const nftInstance = await this.getInstance(address, chainId, MYSTERY_BOX_ABI) return nftInstance.methods.userTokens(AppModule.accountId, start, page).call() } /** * Get NFT of current user with index * @param {string} address * @param {number} chainId * @param {number} index * @return {Promise} */ public async getNftIdOfIndex(address: string, chainId: number, index: number) { const nftInstance = await this.getInstance(address, chainId, MYSTERY_BOX_ABI) const nftId = await nftInstance.methods.tokenOfOwnerByIndex(AppModule.accountId, index).call() console.log(`address: ${address}, chainId: ${chainId}, index: ${index}, token: ${nftId}`) return nftId } /** * Open one mystery box * @param {string} address address of mystery box contract on current chain * @param {string} boxId nftid of mystery box * @param {number[]} tokenIds * @param {string} nonce * @param {string} signature * @return {Promise} */ public async openMysteryBox( address: string, boxId: string, tokenIds: number[], nonce: string, signature: string ) { const proxyInstance = await this.bc.getContractInstance(address, MYSTERY_PROXY_ABI) // get transactionHash and upload to server for verify return proxyInstance.methods.openBox(boxId, tokenIds, nonce, signature).send({ gas: 1000000 }) } /** * activate one nft with 18 digital id * @param {string} address * @param {string} nftOld * @param {string} nftNew * @param {number} nftType * @param {string} nonce * @param {string} signature * @return {Promise} */ public async activateOneNft( address: string, nftOld: string, nftNew: string, nftType: number, nonce: string, signature: string ) { const nftProxyInstance = await this.bc.getContractInstance(address, ACTIVATE_PROXY_ABI) const gas = await nftProxyInstance.methods .activateOne(nftOld, nftNew, nftType, nonce, signature) .estimateGas({ gas: 1000000 }) console.log('nftProxyInstance activateOne need gas: ', gas) return nftProxyInstance.methods.activateOne(nftOld, nftNew, nftType, nonce, signature).send({ gas: (gas * 1.1) | 0 }) } public async transferToAccount({ to, amount, chainId, address } : { to: string amount: number chainId: number address: string}) { const self = this if (chainId !== this.bc.currentChain) { return new Promise((resolve, reject) => { this.bc.switchEthereumChain(chainId, function() { self.bc.transferToAccount(to, amount, address) .then(res => { resolve && resolve(res) }) .catch(err => { reject && reject(err) }) }) }) } else { return this.bc.transferToAccount(to, amount, address) } } }