UNPKG

@depay/web3-wallets

Version:

One-Stop-Shop JavaScript library to integrate various web3 crypto wallets and multiple blockchains at once with a single interface.

750 lines (667 loc) 360 kB
import { getProvider, request, estimate, rpcRequest } from '@depay/web3-client'; import Blockchains from '@depay/web3-blockchains'; import { PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, transact } from '@depay/solana-web3.js'; import { ethers } from 'ethers'; import { SignClient } from '@depay/walletconnect-v2'; import { CoinbaseWalletSDK } from '@depay/coinbase-wallet-sdk'; function _optionalChain$C(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } class Transaction { constructor({ blockchain, from, to, value, api, method, params, instructions, signers, alts, sent, succeeded, failed, accepted, }) { // required this.blockchain = blockchain; this.from = (from && from.match('0x')) ? ethers.utils.getAddress(from) : from; this.to = (to && to.match('0x')) ? ethers.utils.getAddress(to) : to; // optional this.value = _optionalChain$C([Transaction, 'access', _ => _.bigNumberify, 'call', _2 => _2(value, blockchain), 'optionalAccess', _3 => _3.toString, 'call', _4 => _4()]); this.api = api; this.method = method; this.params = params; this.accepted = accepted; this.sent = sent; this.succeeded = succeeded; this.failed = failed; this.instructions = instructions; this.signers = signers; this.alts = alts; // internal this._succeeded = false; this._failed = false; } async prepare({ wallet }) { this.from = await wallet.account(this.blockchain); } static bigNumberify(value, blockchain) { if (typeof value === 'number') { return ethers.utils.parseUnits(value.toString(), Blockchains[blockchain].currency.decimals) } else if (value && value.toString) { return ethers.BigNumber.from(value.toString()) } else { return value } } findFragment() { return this.getContract().interface.fragments.find((fragment) => { return( fragment.name == this.method && (fragment.inputs && this.params && typeof(this.params) === 'object' ? fragment.inputs.length == Object.keys(this.params).length : true) ) }) } getParamType(param) { if(_optionalChain$C([param, 'optionalAccess', _5 => _5.components, 'optionalAccess', _6 => _6.length])) { return `(${param.components.map((param)=>this.getParamType(param)).join(',')})` } else { return param.type } } getMethodNameWithSignature() { let fragment = this.findFragment(); if(fragment.inputs) { return `${this.method}(${fragment.inputs.map((param)=>this.getParamType(param)).join(',')})` } else { return this.method } } getContractArguments() { if(this.params instanceof Array) { return this.params } else if (this.params instanceof Object) { let fragment = this.findFragment(); return fragment.inputs.map((input) => { return this.params[input.name] }) } } getContract() { return new ethers.Contract(this.to, this.api) } async getData() { let contractArguments = this.getContractArguments(); let populatedTransaction; if(contractArguments) { populatedTransaction = await this.getContract().populateTransaction[this.getMethodNameWithSignature()].apply( null, contractArguments ); } else { populatedTransaction = await this.getContract().populateTransaction[this.getMethodNameWithSignature()].apply(null); } return populatedTransaction.data } success() { if (this._succeeded) { return Promise.resolve(this) } return new Promise((resolve, reject) => { let originalSucceeded = this.succeeded; this.succeeded = (transaction) => { if (originalSucceeded) originalSucceeded(transaction); resolve(transaction); }; }) } failure() { if (this._failed) { return Promise.resolve(this) } return new Promise((resolve, reject) => { let originalFailed = this.failed; this.failed = (transaction, reason) => { if (originalFailed) originalFailed(transaction, reason); resolve(transaction, reason); }; }) } } function _optionalChain$B(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } const POLL_SPEED = 500; // 0.5 seconds const MAX_POLLS = 240; // 120 seconds const sendTransaction$3 = async ({ transaction, wallet })=> { transaction = new Transaction(transaction); await transaction.prepare({ wallet }); await submit$3({ transaction, wallet }).then((signature)=>{ if(signature) { transaction.id = signature; transaction.url = Blockchains.findByName(transaction.blockchain).explorerUrlFor({ transaction }); if (transaction.sent) transaction.sent(transaction); let count = 0; const interval = setInterval(async ()=> { count++; if(count >= MAX_POLLS) { return clearInterval(interval) } const provider = await getProvider(transaction.blockchain); const { value } = await provider.getSignatureStatus(signature); const confirmationStatus = _optionalChain$B([value, 'optionalAccess', _ => _.confirmationStatus]); if(confirmationStatus) { const hasReachedSufficientCommitment = confirmationStatus === 'confirmed' || confirmationStatus === 'finalized'; if (hasReachedSufficientCommitment) { if(value.err) { transaction._failed = true; const confirmedTransaction = await provider.getConfirmedTransaction(signature); const failedReason = _optionalChain$B([confirmedTransaction, 'optionalAccess', _2 => _2.meta, 'optionalAccess', _3 => _3.logMessages]) ? confirmedTransaction.meta.logMessages[confirmedTransaction.meta.logMessages.length - 1] : null; if(transaction.failed) transaction.failed(transaction, failedReason); } else { transaction._succeeded = true; if (transaction.succeeded) transaction.succeeded(transaction); } return clearInterval(interval) } } }, POLL_SPEED); } else { throw('Submitting transaction failed!') } }); return transaction }; const submit$3 = async({ transaction, wallet })=> { let result = await submitThroughWallet({ transaction, wallet }); let signature; if(typeof result === 'object' && result.signatures && result.message) { signature = await submitDirectly(result, await wallet.account()); } else if (typeof result === 'object' && result.signature && result.signature.length) { signature = result.signature; } else if (typeof result === 'string' && result.length) { signature = result; } return signature }; const submitDirectly = async(tx, from) =>{ let provider = await getProvider('solana'); return await provider.sendRawTransaction(tx.serialize()) }; const submitThroughWallet = async({ transaction, wallet })=> { if(transaction.instructions) { return submitInstructions({ transaction, wallet }) } else { return submitSimpleTransfer$3({ transaction, wallet }) } }; const submitSimpleTransfer$3 = async ({ transaction, wallet })=> { let fromPubkey = new PublicKey(await wallet.account()); let toPubkey = new PublicKey(transaction.to); const provider = await getProvider(transaction.blockchain); let { blockhash, lastValidBlockHeight } = await provider.getLatestBlockhash(); const instructions = [ SystemProgram.transfer({ fromPubkey, toPubkey, lamports: parseInt(Transaction.bigNumberify(transaction.value, transaction.blockchain), 10) }) ]; const messageV0 = new TransactionMessage({ payerKey: fromPubkey, recentBlockhash: blockhash, instructions, }).compileToV0Message(); const transactionV0 = new VersionedTransaction(messageV0); transaction._lastValidBlockHeight = lastValidBlockHeight; return wallet._sendTransaction(transactionV0) }; const submitInstructions = async ({ transaction, wallet })=> { let fromPubkey = new PublicKey(await wallet.account()); const provider = await getProvider(transaction.blockchain); let { blockhash, lastValidBlockHeight } = await provider.getLatestBlockhash(); const messageV0 = new TransactionMessage({ payerKey: fromPubkey, recentBlockhash: blockhash, instructions: transaction.instructions, }).compileToV0Message( transaction.alts ? await Promise.all(transaction.alts.map(async(alt)=>{ return (await getProvider('solana')).getAddressLookupTable(new PublicKey(alt)).then((res) => res.value) })) : undefined); const transactionV0 = new VersionedTransaction(messageV0); if(transaction.signers && transaction.signers.length) { transactionV0.sign(Array.from(new Set(transaction.signers))); } transaction._lastValidBlockHeight = lastValidBlockHeight; return wallet._sendTransaction(transactionV0) }; let supported$1 = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism', 'base', 'worldchain']; supported$1.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism', 'base', 'worldchain']; supported$1.svm = ['solana']; function _optionalChain$A(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } class WindowSolana { static __initStatic() {this.info = { name: 'Solana Wallet', logo: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI2LjAuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA0NDYuNCAzNzYuOCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDQ2LjQgMzc2Ljg7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojODI4NDg3O30KCS5zdDF7ZmlsbDp1cmwoI1NWR0lEXzFfKTt9Cgkuc3Qye2ZpbGw6dXJsKCNTVkdJRF8wMDAwMDE2NTIzNDE5NTQ5NTc2MDU4MDgwMDAwMDAwNjMwMzAwNDA2OTM1MjExODk1MV8pO30KCS5zdDN7ZmlsbDp1cmwoI1NWR0lEXzAwMDAwMDkyNDIyMzgxNjc5OTg1OTI5MTcwMDAwMDA2ODU0NzIyMTYxOTE4MTIzNjUzXyk7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMzgxLjcsMTEwLjJoNjQuN1Y0Ni41YzAtMjUuNy0yMC44LTQ2LjUtNDYuNS00Ni41SDQ2LjVDMjAuOCwwLDAsMjAuOCwwLDQ2LjV2NjUuMWgzNS43bDI2LjktMjYuOQoJYzEuNS0xLjUsMy42LTIuNSw1LjctMi43bDAsMGgwLjRoNzguNmM1LjMtMjUuNSwzMC4yLTQyLDU1LjctMzYuN2MyNS41LDUuMyw0MiwzMC4yLDM2LjcsNTUuN2MtMS42LDcuNS00LjksMTQuNi05LjgsMjAuNQoJYy0wLjksMS4xLTEuOSwyLjItMywzLjNjLTEuMSwxLjEtMi4yLDIuMS0zLjMsM2MtMjAuMSwxNi42LTQ5LjksMTMuOC02Ni41LTYuM2MtNC45LTUuOS04LjMtMTMtOS44LTIwLjZINzMuMmwtMjYuOSwyNi44CgljLTEuNSwxLjUtMy42LDIuNS01LjcsMi43bDAsMGgtMC40aC0wLjFoLTAuNUgwdjc0aDI4LjhsMTguMi0xOC4yYzEuNS0xLjYsMy42LTIuNSw1LjctMi43bDAsMGgwLjRoMjkuOQoJYzUuMi0yNS41LDMwLjItNDEuOSw1NS43LTM2LjdzNDEuOSwzMC4yLDM2LjcsNTUuN3MtMzAuMiw0MS45LTU1LjcsMzYuN2MtMTguNS0zLjgtMzIuOS0xOC4yLTM2LjctMzYuN0g1Ny43bC0xOC4yLDE4LjMKCWMtMS41LDEuNS0zLjYsMi41LTUuNywyLjdsMCwwaC0wLjRIMHYzNC4yaDU2LjNjMC4yLDAsMC4zLDAsMC41LDBoMC4xaDAuNGwwLDBjMi4yLDAuMiw0LjIsMS4yLDUuOCwyLjhsMjgsMjhoNTcuNwoJYzUuMy0yNS41LDMwLjItNDIsNTUuNy0zNi43czQyLDMwLjIsMzYuNyw1NS43Yy0xLjcsOC4xLTUuNSwxNS43LTExLDIxLjljLTAuNiwwLjctMS4yLDEuMy0xLjksMnMtMS4zLDEuMy0yLDEuOQoJYy0xOS41LDE3LjMtNDkuMywxNS42LTY2LjctMy45Yy01LjUtNi4yLTkuMy0xMy43LTExLTIxLjlIODcuMWMtMS4xLDAtMi4xLTAuMi0zLjEtMC41aC0wLjFsLTAuMy0wLjFsLTAuMi0wLjFsLTAuMi0wLjFsLTAuMy0wLjEKCWgtMC4xYy0wLjktMC41LTEuOC0xLjEtMi42LTEuOGwtMjgtMjhIMHY1My41YzAuMSwyNS43LDIwLjksNDYuNCw0Ni41LDQ2LjRoMzUzLjNjMjUuNywwLDQ2LjUtMjAuOCw0Ni41LTQ2LjV2LTYzLjZoLTY0LjcKCWMtNDMuMiwwLTc4LjItMzUtNzguMi03OC4ybDAsMEMzMDMuNSwxNDUuMiwzMzguNSwxMTAuMiwzODEuNywxMTAuMnoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTIyMC45LDI5OC4xYzAtMTQuNC0xMS42LTI2LTI2LTI2cy0yNiwxMS42LTI2LDI2czExLjYsMjYsMjYsMjZTMjIwLjksMzEyLjQsMjIwLjksMjk4LjFMMjIwLjksMjk4LjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMTkuNiw5MS41YzAtMTQuNC0xMS42LTI2LTI2LTI2cy0yNiwxMS42LTI2LDI2czExLjYsMjYsMjYsMjZTMjE5LjYsMTA1LjgsMjE5LjYsOTEuNXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTM4Mi4yLDEyOC44aC0wLjVjLTMyLjksMC01OS42LDI2LjctNTkuNiw1OS42bDAsMGwwLDBjMCwzMi45LDI2LjcsNTkuNiw1OS42LDU5LjZsMCwwaDAuNQoJYzMyLjksMCw1OS42LTI2LjcsNTkuNi01OS42bDAsMEM0NDEuOCwxNTUuNCw0MTUuMSwxMjguOCwzODIuMiwxMjguOHogTTM5Ni42LDIxOS40aC0zMWw4LjktMzIuNWMtNy43LTMuNy0xMS0xMi45LTcuNC0yMC42CgljMy43LTcuNywxMi45LTExLDIwLjYtNy40YzcuNywzLjcsMTEsMTIuOSw3LjQsMjAuNmMtMS41LDMuMi00LjEsNS44LTcuNCw3LjRMMzk2LjYsMjE5LjR6Ii8+CjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMV8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMTQ5LjAwNzciIHkxPSIxMzkuMzA5MyIgeDI9IjEyMi4xMjMxIiB5Mj0iMTkwLjgwNDIiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSAwIDAgMSAwIDMwLjUzNTQpIj4KCTxzdG9wICBvZmZzZXQ9IjAiIHN0eWxlPSJzdG9wLWNvbG9yOiMwMEZGQTMiLz4KCTxzdG9wICBvZmZzZXQ9IjEiIHN0eWxlPSJzdG9wLWNvbG9yOiNEQzFGRkYiLz4KPC9saW5lYXJHcmFkaWVudD4KPHBhdGggY2xhc3M9InN0MSIgZD0iTTExMi43LDIwMy41YzAuMy0wLjMsMC43LTAuNSwxLjEtMC41aDM4LjhjMC43LDAsMS4xLDAuOSwwLjYsMS40bC03LjcsNy43Yy0wLjMsMC4zLTAuNywwLjUtMS4xLDAuNWgtMzguOAoJYy0wLjcsMC0xLjEtMC45LTAuNi0xLjRMMTEyLjcsMjAzLjV6Ii8+CjxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMDAwMDAxNzUzMTAwMjIwMDgyNTMzODQyNTAwMDAwMTEwOTY3OTQyODQ4NDUzNDEzNTVfIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjEzNy4yNTMzIiB5MT0iMTMzLjE3MjUiIHgyPSIxMTAuMzY4NyIgeTI9IjE4NC42Njc0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIDEgMCAzMC41MzU0KSI+Cgk8c3RvcCAgb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojMDBGRkEzIi8+Cgk8c3RvcCAgb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojREMxRkZGIi8+CjwvbGluZWFyR3JhZGllbnQ+CjxwYXRoIHN0eWxlPSJmaWxsOnVybCgjU1ZHSURfMDAwMDAxNzUzMTAwMjIwMDgyNTMzODQyNTAwMDAwMTEwOTY3OTQyODQ4NDUzNDEzNTVfKTsiIGQ9Ik0xMTIuNywxNzQuOWMwLjMtMC4zLDAuNy0wLjUsMS4xLTAuNWgzOC44CgljMC43LDAsMS4xLDAuOSwwLjYsMS40bC03LjcsNy43Yy0wLjMsMC4zLTAuNywwLjUtMS4xLDAuNWgtMzguOGMtMC43LDAtMS4xLTAuOS0wLjYtMS40TDExMi43LDE3NC45eiIvPgo8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzAwMDAwMDIyNTU3MTYwNTg5MTY1MTU3NTIwMDAwMDE1NDYyNjI0Mjk4Nzk4NTYzMjYxXyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIxNDMuMDkyOSIgeTE9IjEzNi4yMjEyIiB4Mj0iMTE2LjIwODIiIHkyPSIxODcuNzE2MiIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAxIDAgMzAuNTM1NCkiPgoJPHN0b3AgIG9mZnNldD0iMCIgc3R5bGU9InN0b3AtY29sb3I6IzAwRkZBMyIvPgoJPHN0b3AgIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6I0RDMUZGRiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8cGF0aCBzdHlsZT0iZmlsbDp1cmwoI1NWR0lEXzAwMDAwMDIyNTU3MTYwNTg5MTY1MTU3NTIwMDAwMDE1NDYyNjI0Mjk4Nzk4NTYzMjYxXyk7IiBkPSJNMTQ1LjYsMTg5LjFjLTAuMy0wLjMtMC43LTAuNS0xLjEtMC41CgloLTM4LjhjLTAuNywwLTEuMSwwLjktMC42LDEuNGw3LjcsNy43YzAuMywwLjMsMC43LDAuNSwxLjEsMC41aDM4LjhjMC43LDAsMS4xLTAuOSwwLjYtMS40TDE0NS42LDE4OS4xeiIvPgo8L3N2Zz4K', blockchains: supported$1.svm };} static __initStatic2() {this.isAvailable = async()=>{ return ( _optionalChain$A([window, 'optionalAccess', _6 => _6.solana]) && // not Phantom !(window.phantom && !window.glow && !window.solana.isGlow && !['isBitKeep'].some((identifier)=>window.solana && window.solana[identifier])) && // not Coin98 !window.coin98 && // not BitKeep !(_optionalChain$A([window, 'optionalAccess', _7 => _7.solana]) && _optionalChain$A([window, 'optionalAccess', _8 => _8.solana, 'access', _9 => _9.isBitKeep])) && // not Glow !window.solana.isGlow && // not trust !window.trustwallet && // Brave Wallet !window.solana.isBraveWallet && // OKX Wallet !_optionalChain$A([window, 'optionalAccess', _10 => _10.okxwallet]) ) };} constructor () { this.name = this.constructor.info.name; this.logo = this.constructor.info.logo; this.blockchains = this.constructor.info.blockchains; this.sendTransaction = (transaction)=>{ return sendTransaction$3({ wallet: this, transaction }) }; } getProvider() { return window.solana } async account() { const provider = this.getProvider(); if(provider == undefined){ return } if(provider.publicKey) { return provider.publicKey.toString() } if(provider.isBraveWallet != true) { let publicKey; try { ({ publicKey } = await window.solana.connect({ onlyIfTrusted: true })); } catch (e) {} if(publicKey){ return publicKey.toString() } } } async connect() { const provider = this.getProvider(); if(!provider) { return undefined } let result; try { result = await provider.connect(); } catch (e2) {} if(result && result.publicKey) { return result.publicKey.toString() } else { return provider.publicKey.toString() } } on(event, callback) { let internalCallback; switch (event) { case 'account': internalCallback = (publicKey) => callback(_optionalChain$A([publicKey, 'optionalAccess', _11 => _11.toString, 'call', _12 => _12()])); this.getProvider().on('accountChanged', internalCallback); break } return internalCallback } off(event, internalCallback) { switch (event) { case 'account': this.getProvider().removeListener('accountChanged', internalCallback); break } return internalCallback } async connectedTo(input) { if(input) { return input == 'solana' } else { return 'solana' } } switchTo(blockchainName) { return new Promise((resolve, reject)=>{ reject({ code: 'NOT_SUPPORTED' }); }) } addNetwork(blockchainName) { return new Promise((resolve, reject)=>{ reject({ code: 'NOT_SUPPORTED' }); }) } async sign(message) { const encodedMessage = new TextEncoder().encode(message); const signedMessage = await this.getProvider().signMessage(encodedMessage); if(signedMessage && signedMessage.signature) { return Array.from(signedMessage.signature) } } _sendTransaction(transaction) { return this.getProvider() .signAndSendTransaction( transaction, { skipPreflight: false } // requires default options to not raise error on phantom in app mobile (https://discord.com/channels/958228318132514876/974393659380334618/1089298098905423924) ) } } WindowSolana.__initStatic(); WindowSolana.__initStatic2(); function _optionalChain$z(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } class Backpack extends WindowSolana { static __initStatic() {this.info = { name: 'Backpack', logo: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI3LjIuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMDAgMTAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2NsaXAtcGF0aDp1cmwoI1NWR0lEXzAwMDAwMTA2ODQwODY0OTg0NTM1NTU0MzQwMDAwMDAwNDc2MjMzMDgyNzcwODcyOTcxXyk7fQoJLnN0MXtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiNFMzNFM0Y7fQo8L3N0eWxlPgo8Zz4KCTxkZWZzPgoJCTxyZWN0IGlkPSJTVkdJRF8xXyIgeD0iMjMuOCIgeT0iMTAuNCIgd2lkdGg9IjUyLjQiIGhlaWdodD0iNzYuMiIvPgoJPC9kZWZzPgoJPGNsaXBQYXRoIGlkPSJTVkdJRF8wMDAwMDE3ODE5NTUzMTM2ODQxNzQ3MDkwMDAwMDAxNDk2Njk4MDAxOTUxNjc4MTk3MF8iPgoJCTx1c2UgeGxpbms6aHJlZj0iI1NWR0lEXzFfIiAgc3R5bGU9Im92ZXJmbG93OnZpc2libGU7Ii8+Cgk8L2NsaXBQYXRoPgoJPGcgc3R5bGU9ImNsaXAtcGF0aDp1cmwoI1NWR0lEXzAwMDAwMTc4MTk1NTMxMzY4NDE3NDcwOTAwMDAwMDE0OTY2OTgwMDE5NTE2NzgxOTcwXyk7Ij4KCQk8cGF0aCBjbGFzcz0ic3QxIiBkPSJNNTUsMTYuNGMyLjgsMCw1LjQsMC40LDcuOCwxLjFjLTIuNC01LjUtNy4yLTcuMS0xMi43LTcuMWMtNS41LDAtMTAuNCwxLjYtMTIuNyw3LjFjMi40LTAuNyw1LTEuMSw3LjctMS4xCgkJCUg1NXogTTQ0LjQsMjEuOWMtMTMuMiwwLTIwLjcsMTAuNC0yMC43LDIzLjF2MTMuMWMwLDEuMywxLjEsMi4zLDIuNCwyLjNoNDcuNmMxLjMsMCwyLjQtMSwyLjQtMi4zVjQ1YzAtMTIuOC04LjctMjMuMS0yMS45LTIzLjEKCQkJSDQ0LjR6IE01MCw0NS4xYzQuNiwwLDguMy0zLjcsOC4zLTguM3MtMy43LTguMy04LjMtOC4zcy04LjMsMy43LTguMyw4LjNTNDUuNCw0NS4xLDUwLDQ1LjF6IE0yMy44LDY4LjFjMC0xLjMsMS4xLTIuMywyLjQtMi4zCgkJCWg0Ny42YzEuMywwLDIuNCwxLDIuNCwyLjNWODJjMCwyLjYtMi4xLDQuNi00LjgsNC42SDI4LjZjLTIuNiwwLTQuOC0yLjEtNC44LTQuNlY2OC4xeiIvPgoJPC9nPgo8L2c+Cjwvc3ZnPgo=', blockchains: ['solana'] };} static __initStatic2() {this.isAvailable = async()=>{ return ( _optionalChain$z([window, 'optionalAccess', _2 => _2.backpack]) && window.backpack.isBackpack ) };} getProvider() { return window.backpack } async sign(message) { const encodedMessage = new TextEncoder().encode(message); const signature = await this.getProvider().signMessage(encodedMessage); return Object.values(signature) } _sendTransaction(transaction) { return this.getProvider().sendAndConfirm(transaction) } } Backpack.__initStatic(); Backpack.__initStatic2(); function _optionalChain$y(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } const sendTransaction$2 = async ({ transaction, wallet })=> { transaction = new Transaction(transaction); if((await wallet.connectedTo(transaction.blockchain)) == false) { await wallet.switchTo(transaction.blockchain); } if((await wallet.connectedTo(transaction.blockchain)) == false) { throw({ code: 'WRONG_NETWORK' }) } await transaction.prepare({ wallet }); let transactionCount = await request({ blockchain: transaction.blockchain, method: 'transactionCount', address: transaction.from }); transaction.nonce = transactionCount; let provider = new ethers.providers.Web3Provider(wallet.getProvider(), 'any'); let signer = provider.getSigner(0); await submit$2({ transaction, provider, signer }).then((sentTransaction)=>{ if (sentTransaction) { transaction.id = sentTransaction.hash; transaction.nonce = sentTransaction.nonce || transactionCount; transaction.url = Blockchains.findByName(transaction.blockchain).explorerUrlFor({ transaction }); if (transaction.sent) transaction.sent(transaction); retrieveConfirmedTransaction$2(sentTransaction).then(() => { transaction._succeeded = true; if (transaction.succeeded) transaction.succeeded(transaction); }).catch((error)=>{ if(error && error.code && error.code == 'TRANSACTION_REPLACED') { if(error.replacement && error.replacement.hash) { transaction.id = error.replacement.hash; transaction.url = Blockchains.findByName(transaction.blockchain).explorerUrlFor({ transaction }); } if(error.replacement && error.replacement.hash && error.receipt && error.receipt.status == 1) { transaction._succeeded = true; if (transaction.succeeded) transaction.succeeded(transaction); } else if(error.replacement && error.replacement.hash && error.receipt && error.receipt.status == 0) { transaction._failed = true; if(transaction.failed) transaction.failed(transaction, error); } } else { transaction._failed = true; if(transaction.failed) transaction.failed(transaction, error); } }); } else { throw('Submitting transaction failed!') } }); return transaction }; const retrieveConfirmedTransaction$2 = (sentTransaction)=>{ return new Promise((resolve, reject)=>{ try { sentTransaction.wait(1).then(resolve).catch((error)=>{ if( (error && _optionalChain$y([error, 'optionalAccess', _ => _.stack, 'optionalAccess', _2 => _2.match, 'call', _3 => _3('JSON-RPC error')])) || (error && error.toString().match('undefined')) ) { setTimeout(()=>{ retrieveConfirmedTransaction$2(sentTransaction) .then(resolve) .catch(reject); }, 500); } else { reject(error); } }); } catch(error) { if( (error && _optionalChain$y([error, 'optionalAccess', _4 => _4.stack, 'optionalAccess', _5 => _5.match, 'call', _6 => _6('JSON-RPC error')])) || (error && error.toString().match('undefined')) ) { setTimeout(()=>{ retrieveConfirmedTransaction$2(sentTransaction) .then(resolve) .catch(reject); }, 500); } else { reject(error); } } }) }; const submit$2 = ({ transaction, provider, signer }) => { if(transaction.method) { return submitContractInteraction$2({ transaction, signer, provider }) } else { return submitSimpleTransfer$2({ transaction, signer }) } }; const submitContractInteraction$2 = async ({ transaction, signer, provider })=>{ let contract = new ethers.Contract(transaction.to, transaction.api, provider); let contractArguments = transaction.getContractArguments({ contract }); let method = contract.connect(signer)[transaction.getMethodNameWithSignature()]; let gas; try { gas = await estimate(transaction); gas = gas.add(gas.div(10)); } catch (e) {} if(contractArguments) { return await method(...contractArguments, { value: Transaction.bigNumberify(transaction.value, transaction.blockchain), gasLimit: _optionalChain$y([gas, 'optionalAccess', _7 => _7.toHexString, 'call', _8 => _8()]) }) } else { return await method({ value: Transaction.bigNumberify(transaction.value, transaction.blockchain), gasLimit: _optionalChain$y([gas, 'optionalAccess', _9 => _9.toHexString, 'call', _10 => _10()]) }) } }; const submitSimpleTransfer$2 = ({ transaction, signer })=>{ return signer.sendTransaction({ to: transaction.to, value: Transaction.bigNumberify(transaction.value, transaction.blockchain) }) }; function _optionalChain$x(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } class WindowEthereum { static __initStatic() {this.info = { name: 'Ethereum Wallet', logo: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI2LjAuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA0NDYuNCAzNzYuOCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDQ2LjQgMzc2Ljg7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojODI4NDg3O30KCS5zdDF7ZmlsbDojMzQzNDM0O30KCS5zdDJ7ZmlsbDojOEM4QzhDO30KCS5zdDN7ZmlsbDojM0MzQzNCO30KCS5zdDR7ZmlsbDojMTQxNDE0O30KCS5zdDV7ZmlsbDojMzkzOTM5O30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTM4MS43LDExMC4yaDY0LjdWNDYuNWMwLTI1LjctMjAuOC00Ni41LTQ2LjUtNDYuNUg0Ni41QzIwLjgsMCwwLDIwLjgsMCw0Ni41djY1LjFoMzUuN2wyNi45LTI2LjkKCWMxLjUtMS41LDMuNi0yLjUsNS43LTIuN2wwLDBoMC40aDc4LjZjNS4zLTI1LjUsMzAuMi00Miw1NS43LTM2LjdjMjUuNSw1LjMsNDIsMzAuMiwzNi43LDU1LjdjLTEuNiw3LjUtNC45LDE0LjYtOS44LDIwLjUKCWMtMC45LDEuMS0xLjksMi4yLTMsMy4zYy0xLjEsMS4xLTIuMiwyLjEtMy4zLDNjLTIwLjEsMTYuNi00OS45LDEzLjgtNjYuNS02LjNjLTQuOS01LjktOC4zLTEzLTkuOC0yMC42SDczLjJsLTI2LjksMjYuOAoJYy0xLjUsMS41LTMuNiwyLjUtNS43LDIuN2wwLDBoLTAuNGgtMC4xaC0wLjVIMHY3NGgyOC44bDE4LjItMTguMmMxLjUtMS42LDMuNi0yLjUsNS43LTIuN2wwLDBoMC40aDI5LjkKCWM1LjItMjUuNSwzMC4yLTQxLjksNTUuNy0zNi43czQxLjksMzAuMiwzNi43LDU1LjdzLTMwLjIsNDEuOS01NS43LDM2LjdjLTE4LjUtMy44LTMyLjktMTguMi0zNi43LTM2LjdINTcuN2wtMTguMiwxOC4zCgljLTEuNSwxLjUtMy42LDIuNS01LjcsMi43bDAsMGgtMC40SDB2MzQuMmg1Ni4zYzAuMiwwLDAuMywwLDAuNSwwaDAuMWgwLjRsMCwwYzIuMiwwLjIsNC4yLDEuMiw1LjgsMi44bDI4LDI4aDU3LjcKCWM1LjMtMjUuNSwzMC4yLTQyLDU1LjctMzYuN3M0MiwzMC4yLDM2LjcsNTUuN2MtMS43LDguMS01LjUsMTUuNy0xMSwyMS45Yy0wLjYsMC43LTEuMiwxLjMtMS45LDJzLTEuMywxLjMtMiwxLjkKCWMtMTkuNSwxNy4zLTQ5LjMsMTUuNi02Ni43LTMuOWMtNS41LTYuMi05LjMtMTMuNy0xMS0yMS45SDg3LjFjLTEuMSwwLTIuMS0wLjItMy4xLTAuNWgtMC4xbC0wLjMtMC4xbC0wLjItMC4xbC0wLjItMC4xbC0wLjMtMC4xCgloLTAuMWMtMC45LTAuNS0xLjgtMS4xLTIuNi0xLjhsLTI4LTI4SDB2NTMuNWMwLjEsMjUuNywyMC45LDQ2LjQsNDYuNSw0Ni40aDM1My4zYzI1LjcsMCw0Ni41LTIwLjgsNDYuNS00Ni41di02My42aC02NC43CgljLTQzLjIsMC03OC4yLTM1LTc4LjItNzguMmwwLDBDMzAzLjUsMTQ1LjIsMzM4LjUsMTEwLjIsMzgxLjcsMTEwLjJ6Ii8+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMjAuOSwyOTguMWMwLTE0LjQtMTEuNi0yNi0yNi0yNnMtMjYsMTEuNi0yNiwyNnMxMS42LDI2LDI2LDI2UzIyMC45LDMxMi40LDIyMC45LDI5OC4xTDIyMC45LDI5OC4xeiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjE5LjYsOTEuNWMwLTE0LjQtMTEuNi0yNi0yNi0yNnMtMjYsMTEuNi0yNiwyNnMxMS42LDI2LDI2LDI2UzIxOS42LDEwNS44LDIxOS42LDkxLjV6Ii8+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0zODIuMiwxMjguOGgtMC41Yy0zMi45LDAtNTkuNiwyNi43LTU5LjYsNTkuNmwwLDBsMCwwYzAsMzIuOSwyNi43LDU5LjYsNTkuNiw1OS42bDAsMGgwLjUKCWMzMi45LDAsNTkuNi0yNi43LDU5LjYtNTkuNmwwLDBDNDQxLjgsMTU1LjQsNDE1LjEsMTI4LjgsMzgyLjIsMTI4Ljh6IE0zOTYuNiwyMTkuNGgtMzFsOC45LTMyLjVjLTcuNy0zLjctMTEtMTIuOS03LjQtMjAuNgoJYzMuNy03LjcsMTIuOS0xMSwyMC42LTcuNGM3LjcsMy43LDExLDEyLjksNy40LDIwLjZjLTEuNSwzLjItNC4xLDUuOC03LjQsNy40TDM5Ni42LDIxOS40eiIvPgo8ZyBpZD0iTGF5ZXJfeDAwMjBfMSI+Cgk8ZyBpZD0iXzE0MjEzOTQzNDI0MDAiPgoJCTxnPgoJCQk8cG9seWdvbiBjbGFzcz0ic3QxIiBwb2ludHM9IjEyOSwxNjYuMiAxMjguNywxNjcuMyAxMjguNywyMDEuNCAxMjksMjAxLjcgMTQ0LjgsMTkyLjQgCQkJIi8+CgkJCTxwb2x5Z29uIGNsYXNzPSJzdDIiIHBvaW50cz0iMTI5LDE2Ni4yIDExMy4yLDE5Mi40IDEyOSwyMDEuNyAxMjksMTg1LjIgCQkJIi8+CgkJCTxwb2x5Z29uIGNsYXNzPSJzdDMiIHBvaW50cz0iMTI5LDIwNC43IDEyOC44LDIwNC45IDEyOC44LDIxNyAxMjksMjE3LjYgMTQ0LjgsMTk1LjQgCQkJIi8+CgkJCTxwb2x5Z29uIGNsYXNzPSJzdDIiIHBvaW50cz0iMTI5LDIxNy42IDEyOSwyMDQuNyAxMTMuMiwxOTUuNCAJCQkiLz4KCQkJPHBvbHlnb24gY2xhc3M9InN0NCIgcG9pbnRzPSIxMjksMjAxLjcgMTQ0LjgsMTkyLjQgMTI5LDE4NS4yIAkJCSIvPgoJCQk8cG9seWdvbiBjbGFzcz0ic3Q1IiBwb2ludHM9IjExMy4yLDE5Mi40IDEyOSwyMDEuNyAxMjksMTg1LjIgCQkJIi8+CgkJPC9nPgoJPC9nPgo8L2c+Cjwvc3ZnPgo=", blockchains: supported$1.evm };} static __initStatic2() {this.isAvailable = async()=>{ return ( _optionalChain$x([window, 'optionalAccess', _38 => _38.ethereum]) && // not MetaMask !(_optionalChain$x([window, 'optionalAccess', _39 => _39.ethereum, 'optionalAccess', _40 => _40.isMetaMask]) && Object.keys(window.ethereum).filter((key)=>key.match(/^is(?!Connected)(?!PocketUniverse)(?!RevokeCash)/)).length == 1) && // not Coin98 !_optionalChain$x([window, 'optionalAccess', _41 => _41.coin98]) && // not Trust Wallet !(_optionalChain$x([window, 'optionalAccess', _42 => _42.ethereum, 'optionalAccess', _43 => _43.isTrust]) || _optionalChain$x([window, 'optionalAccess', _44 => _44.ethereum, 'optionalAccess', _45 => _45.isTrustWallet])) && // not crypto.com !_optionalChain$x([window, 'optionalAccess', _46 => _46.ethereum, 'optionalAccess', _47 => _47.isDeficonnectProvider]) && // not HyperPay !_optionalChain$x([window, 'optionalAccess', _48 => _48.ethereum, 'optionalAccess', _49 => _49.isHyperPay]) && // not Phantom !(window.phantom && !window.glow && !_optionalChain$x([window, 'optionalAccess', _50 => _50.solana, 'optionalAccess', _51 => _51.isGlow]) && !['isBitKeep'].some((identifier)=>window.solana && window.solana[identifier])) && // not Rabby !_optionalChain$x([window, 'optionalAccess', _52 => _52.ethereum, 'optionalAccess', _53 => _53.isRabby]) && // not Backpack !_optionalChain$x([window, 'optionalAccess', _54 => _54.backpack, 'optionalAccess', _55 => _55.isBackpack]) && // not TokenPocket !_optionalChain$x([window, 'optionalAccess', _56 => _56.ethereum, 'optionalAccess', _57 => _57.isTokenPocket]) && // not BitKeep !_optionalChain$x([window, 'optionalAccess', _58 => _58.ethereum, 'optionalAccess', _59 => _59.isBitKeep]) && // not Coinbase !(_optionalChain$x([window, 'optionalAccess', _60 => _60.ethereum, 'optionalAccess', _61 => _61.isCoinbaseWallet]) || _optionalChain$x([window, 'optionalAccess', _62 => _62.ethereum, 'optionalAccess', _63 => _63.isWalletLink])) && // MetaMask through ProviderMap !_optionalChain$x([window, 'optionalAccess', _64 => _64.ethereum, 'optionalAccess', _65 => _65.providerMap, 'optionalAccess', _66 => _66.has, 'call', _67 => _67('MetaMask')]) && // Brave Wallet !_optionalChain$x([window, 'optionalAccess', _68 => _68.ethereum, 'optionalAccess', _69 => _69.isBraveWallet]) && // Uniswap Wallet !_optionalChain$x([window, 'optionalAccess', _70 => _70.ethereum, 'optionalAccess', _71 => _71.isUniswapWallet]) && // Rainbow !_optionalChain$x([window, 'optionalAccess', _72 => _72.ethereum, 'optionalAccess', _73 => _73.isRainbow]) && // OKX Wallet !_optionalChain$x([window, 'optionalAccess', _74 => _74.okxwallet]) ) };} constructor () { this.name = this.constructor.info.name; this.logo = this.constructor.info.logo; this.blockchains = this.constructor.info.blockchains; this.sendTransaction = (transaction)=>{ return sendTransaction$2({ wallet: this, transaction }) }; } getProvider() { return window.ethereum } async account() { if(!this.getProvider()) { return undefined } const accounts = (await this.getProvider().request({ method: 'eth_accounts' })).map((address)=>ethers.utils.getAddress(address)); return accounts[0] } async connect() { if(!this.getProvider()) { return undefined } const accounts = (await this.getProvider().request({ method: 'eth_requestAccounts' })).map((address)=>ethers.utils.getAddress(address)); return accounts[0] } on(event, callback) { let internalCallback; switch (event) { case 'account': internalCallback = (accounts) => { if(accounts && accounts.length) { callback(ethers.utils.getAddress(accounts[0])); } else { callback(); } }; this.getProvider().on('accountsChanged', internalCallback); break } return internalCallback } off(event, internalCallback) { switch (event) { case 'account': this.getProvider().removeListener('accountsChanged', internalCallback); break } return internalCallback } async connectedTo(input) { const blockchain = Blockchains.findById(await this.getProvider().request({ method: 'eth_chainId' })); if(!blockchain) { return false } if(input) { return input === blockchain.name } else { return blockchain.name } } addNetwork(blockchainName) { return new Promise((resolve, reject)=>{ const blockchain = Blockchains.findByName(blockchainName); this.getProvider().request({ method: 'wallet_addEthereumChain', params: [{ chainId: blockchain.id, chainName: blockchain.fullName, nativeCurrency: { name: blockchain.currency.name, symbol: blockchain.currency.symbol, decimals: blockchain.currency.decimals }, rpcUrls: [blockchain.rpc], blockExplorerUrls: [blockchain.explorer], iconUrls: [blockchain.logo] }], }).then(resolve).catch(reject); }) } switchTo(blockchainName) { return new Promise((resolve, reject)=>{ const blockchain = Blockchains.findByName(blockchainName); this.getProvider().request({ method: 'wallet_switchEthereumChain', params: [{ chainId: blockchain.id }], }).then(resolve).catch((error)=> { if(error.code === 4902){ // chain not yet added this.addNetwork(blockchainName) .then(()=>this.switchTo(blockchainName).then(resolve)) .catch(reject); } else { reject(error); } }); }) } transactionCount({ blockchain, address }) { return request({ blockchain, method: 'transactionCount', address }) } async sign(message) { if(typeof message === 'object') { let provider = this.getProvider(); let account = await this.account(); let blockchain = Blockchains.findByNetworkId(message.domain.chainId); if((await this.connectedTo(blockchain.name)) == false) { await this.switchTo(blockchain.name); } if((await this.connectedTo(blockchain.name)) == false) { throw({ code: 'WRONG_NETWORK' }) } let signature = await provider.request({ method: 'eth_signTypedData_v4', params: [account, message], from: account, }); return signature } else if (typeof message === 'string') { await this.account(); let provider = new ethers.providers.Web3Provider(this.getProvider(), 'any'); let signer = provider.getSigner(0); let signature = await signer.signMessage(message); return signature } } } WindowEthereum.__initStatic(); WindowEthereum.__initStatic2(); function _optionalChain$w(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } class Binance extends WindowEthereum { static __initStatic() {this.info = { name: 'Binance', logo: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAxOTIgMTkzLjciPgogIDwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyOS40LjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiAyLjEuMCBCdWlsZCAxNTIpICAtLT4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLnN0MCB7CiAgICAgICAgZmlsbDogIzFlMjAyNDsKICAgICAgfQoKICAgICAgLnN0MSB7CiAgICAgICAgZmlsbDogI2YzYmEyZjsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPHJlY3QgY2xhc3M9InN0MCIgeT0iMCIgd2lkdGg9IjE5MiIgaGVpZ2h0PSIxOTMuNyIvPgogIDxnPgogICAgPHBhdGggY2xhc3M9InN0MSIgZD0iTTY1LjcsODQuNGwzMC4zLTMwLjMsMzAuMywzMC4zLDE3LjYtMTcuNi00Ny45LTQ3LjktNDcuOSw0Ny45LDE3LjYsMTcuNloiLz4KICAgIDxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xOCw5Ni44bDE3LjYtMTcuNiwxNy42LDE3LjYtMTcuNiwxNy42LTE3LjYtMTcuNloiLz4KICAgIDxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik02NS43LDEwOS4zbDMwLjMsMzAuMywzMC4zLTMwLjMsMTcuNiwxNy42aDBzLTQ3LjksNDcuOS00Ny45LDQ3LjlsLTQ3LjktNDcuOWgwczE3LjctMTcuNiwxNy43LTE3LjZaIi8+CiAgICA8cGF0aCBjbGFzcz0ic3QxIiBkPSJNMTM4LjgsOTYuOGwxNy42LTE3LjYsMTcuNiwxNy42LTE3LjYsMTcuNi0xNy42LTE3LjZaIi8+CiAgICA8cGF0aCBjbGFzcz0ic3QxIiBkPSJNMTEzLjksOTYuOGwtMTcuOS0xNy45LTEzLjIsMTMuMi0xLjUsMS41LTMuMSwzLjFoMHMwLDAsMCwwbDE3LjksMTcuOSwxNy45LTE3LjloMHMwLDAsMCwwWiIvPgogIDwvZz4KPC9zdmc+", blockchains: supported$1.evm };} static __initStatic2() {this.isAvailable = async()=>{ return _optionalChain$w([window, 'optionalAccess', _2 => _2.BinanceChain]) && !window.coin98 && !window.trustwallet };} getProvider() { return window.BinanceChain } } Binance.__initStatic(); Binance.__initStatic2(); var logos = { exodus: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDMwMCAzMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0yOTguMjAzIDgzLjc2NDVMMTcwLjQ0OSAwVjQ2LjgzMzJMMjUyLjQwNSAxMDAuMDg5TDI0Mi43NjMgMTMwLjU5OEgxNzAuNDQ5VjE2OS40MDJIMjQyLjc2M0wyNTIuNDA1IDE5OS45MTFMMTcwLjQ0OSAyNTMuMTY3VjMwMEwyOTguMjAzIDIxNi41MDNMMjc3LjMxMyAxNTAuMTM0TDI5OC4yMDMgODMuNzY0NVoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8xNjYxXzI5NSkiLz4KPHBhdGggZD0iTTU5LjMwMDcgMTY5LjQwMkgxMzEuMzQ2VjEzMC41OThINTkuMDMyOUw0OS42NTg5IDEwMC4wODlMMTMxLjM0NiA0Ni44MzMyVjBMMy41OTI1MyA4My43NjQ1TDI0LjQ4MzEgMTUwLjEzNEwzLjU5MjUzIDIxNi41MDNMMTMxLjYxNCAzMDBWMjUzLjE2N0w0OS42NTg5IDE5OS45MTFMNTkuMzAwNyAxNjkuNDAyWiIgZmlsbD0idXJsKCNwYWludDFfbGluZWFyXzE2NjFfMjk1KSIvPgo8bWFzayBpZD0ibWFzazBfMTY2MV8yOTUiIHN0eWxlPSJtYXNrLXR5cGU6YWxwaGEiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiIHg9IjMiIHk9IjAiIHdpZHRoPSIyOTYiIGhlaWdodD0iMzAwIj4KPHBhdGggZD0iTTI5OC4yMDQgODMuNzY0NUwxNzAuNDUgMFY0Ni44MzMyTDI1Mi40MDUgMTAwLjA4OUwyNDIuNzYzIDEzMC41OThIMTcwLjQ1VjE2OS40MDJIMjQyLjc2M0wyNTIuNDA1IDE5OS45MTFMMTcwLjQ1IDI1My4xNjdWMzAwTDI5OC4yMDQgMjE2LjUwM0wyNzcuMzEzIDE1MC4xMzRMMjk4LjIwNCA4My43NjQ1WiIgZmlsbD0idXJsKCNwYWludDJfbGluZWFyXzE2NjFfMjk1KSIvPgo8cGF0aCBkPSJNNTkuMzAxIDE2OS40MDJIMTMxLjM0N1YxMzAuNTk4SDU5LjAzMzJMNDkuNjU5MiAxMDAuMDg5TDEzMS4zNDcgNDYuODMzMlYwTDMuNTkyNzcgODMuNzY0NUwyNC40ODM0IDE1MC4xMzRMMy41OTI3NyAyMTYuNTAzTDEzMS42MTUgMzAwVjI1My4xNjdMNDkuNjU5MiAxOTkuOTExTDU5LjMwMSAxNjkuNDAyWiIgZmlsbD0idXJsKCNwYWludDNfbGluZWFyXzE2NjFfMjk1KSIvPgo8L21hc2s+CjxnIG1hc2s9InVybCgjbWFzazBfMTY2MV8yOTUpIj4KPHJlY3QgeD0iMy43NTAyNCIgd2lkdGg9IjI5Mi41IiBoZWlnaHQ9IjMwMCIgZmlsbD0idXJsKCNwYWludDRfbGluZWFyXzE2NjFfMjk1KSIvPgo8L2c+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMTY2MV8yOTUiIHgxPSIyNTYuODc1IiB5MT0iMzIwLjYyNSIgeDI9IjE3MS4zIiB5Mj0iLTMyLjk0NTkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzBCNDZGOSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNCQkZCRTAiLz4KPC9saW5lYXJHcmFkaWVudD4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDFfbGluZWFyXzE2NjFfMjk1IiB4MT0iMjU2Ljg3NSIgeTE9IjMyMC42MjUiIHgyPSIxNzEuMyIgeTI9Ii0zMi45NDU5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMwQjQ2RjkiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjQkJGQkUwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQyX2xpbmVhcl8xNjYxXzI5NSIgeDE9IjI1Ni44NzUiIHkxPSIzMjAuNjI1IiB4Mj0iMTcxLjMiIHkyPSItMzIuOTQ1OSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMEI0NkY5Ii8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0JCRkJFMCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50M19saW5lYXJfMTY2MV8yOTUiIHgxPSIyNTYuODc1IiB5MT0iMzIwLjYyNSIgeDI9IjE3MS4zIiB5Mj0iLTMyLjk0NTkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzBCNDZGOSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNCQkZCRTAiLz4KPC9saW5lYXJHcmFkaWVudD4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDRfbGluZWFyXzE2NjFfMjk1IiB4MT0iMjIuNTAwMiIgeTE9IjY3LjUiIHgyPSIxNzAuNjI1IiB5Mj0iMTc4LjEyNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBvZmZzZXQ9IjAuMTE5NzkyIiBzdG9wLWNvbG9yPSIjODk1MkZGIiBzdG9wLW9wYWNpdHk9IjAuODciLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjREFCREZGIiBzdG9wLW9wYWNpdHk9IjAiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K", phantom: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI3LjIuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAxMjggMTI4IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAxMjggMTI4OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0FCOUZGMjt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMy43LDEwOWMxMy42LDAsMjMuOS0xMS45LDMwLTIxLjJjLTAuNywyLjEtMS4yLDQuMS0xLjIsNi4xYzAsNS41LDMuMSw5LjQsOS4zLDkuNGM4LjUsMCwxNy42LTcuNSwyMi4zLTE1LjUKCWMtMC4zLDEuMi0wLjUsMi4yLTAuNSwzLjJjMCwzLjgsMi4xLDYuMiw2LjUsNi4yYzEzLjgsMCwyNy43LTI0LjUsMjcuNy00NS45YzAtMTYuNy04LjQtMzEuNC0yOS42LTMxLjQKCWMtMzcuMiwwLTc3LjMsNDUuNS03Ny4zLDc0LjhDMTEuMSwxMDYuMywxNy4zLDEwOSwyMy43LDEwOXogTTc1LjUsNDkuNWMwLTQuMSwyLjMtNy4xLDUuNy03LjFjMy4zLDAsNS42LDIuOSw1LjYsNy4xCgljMCw0LjEtMi4zLDcuMS01LjYsNy4xQzc3LjgsNTYuNyw3NS41LDUzLjcsNzUuNSw0OS41eiBNOTMuMiw0OS41YzAtNC4xLDIuMy03LjEsNS43LTcuMWMzLjMsMCw1LjYsMi45LDUuNiw3LjEKCWMwLDQuMS0yLjMsNy4xLTUuNiw3LjFDOTUuNSw1Ni43LDkzLjIsNTMuNyw5My4yLDQ5LjV6Ii8+Cjwvc3ZnPgo=", coin98: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA0MC43IDQwIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA0MC43IDQwIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBmaWxsPSIjRDlCNDMyIiBkPSJtMzMuMyAwaC0yNS45Yy00LjEgMC03LjQgMy4zLTcuNCA3LjN2MjUuNGMwIDQgMy4zIDcuMyA3LjQgNy4zaDI1LjljNC4xIDAgNy40LTMuMyA3LjQtNy4zdi0yNS40YzAtNC0zLjMtNy4zLTcuNC03LjN6Ii8+CjxwYXRoIGZpbGw9IiMyNTI1MjUiIGQ9Im0zMy4zIDBoLTI1LjljLTQuMSAwLTcuNCAzLjMtNy40IDcuM3YyNS40YzAgNCAzLjMgNy4zIDcuNCA3LjNoMjUuOWM0LjEgMCA3LjQtMy4zIDcuNC03LjN2LTI1LjRjMC00LTMuMy03LjMtNy40LTcuM3ptLTYuMyAxMGMzIDAgNS41IDIuNCA1LjUgNS40IDAgMC45LTAuMiAxLjgtMC42IDIuNi0wLjctMC41LTEuNS0xLTIuMy0xLjMgMC4yLTAuNCAwLjMtMC45IDAuMy0xLjMgMC0xLjUtMS4zLTIuOC0yLjgtMi44LTEuNiAwLTIuOCAxLjMtMi44IDIuOCAwIDAuNSAwLjEgMC45IDAuMyAxLjMtMC44IDAuMy0xLjYgMC43LTIuMyAxLjMtMC41LTAuOC0wLjYtMS43LTAuNi0yLjYtMC4xLTMgMi4zLTUuNCA1LjMtNS40em0tMTMuMyAyMGMtMyAwLTUuNS0yLjQtNS41LTUuNGgyLjZjMCAxLjUgMS4zIDIuOCAyLjggMi44czIuOC0xLjMgMi44LTIuOGgyLjZjMC4yIDMtMi4zIDUuNC01LjMgNS40em0wLTcuNWMtMy41IDAtNi4zLTIuOC02LjMtNi4yczIuOC02LjMgNi4zLTYuMyA2LjQgMi44IDYuNCA2LjNjMCAzLjQtMi45IDYuMi02LjQgNi4yem0xMy4zIDcuNWMtMy41IDAtNi40LTIuOC02LjQtNi4yIDAtMy41IDIuOC02LjMgNi40LTYuMyAzLjUgMCA2LjMgMi44IDYuMyA2LjMgMC4xIDMuNC0yLjggNi4yLTYuMyA2LjJ6bTMuOC02LjNjMCAyLjEtMS43IDMuNy0zLjggMy43cy0zLjgtMS43LTMuOC0zLjdjMC0yLjEgMS43LTMuNyAzLjgtMy43IDIuMSAwLjEgMy44IDEuNyAzLjggMy43em0tMTMuNC03LjRjMCAyLjEtMS43IDMuNy0zLjggMy43cy0zLjgtMS43LTMuOC0zLjdjMC0yLjEgMS43LTMuNyAzLjgtMy43IDIuMiAwIDMuOCAxLjYgMy44IDMuN3oiLz4KPC9zdmc+Cg==", coinbase: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cmVjdCB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiBmaWxsPSIjMDA1MkZGIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTUyIDUxMkMxNTIgNzEwLjgyMyAzMTMuMTc3IDg3MiA1MTIgODcyQzcxMC44MjMgODcyIDg3MiA3MTAuODIzIDg3MiA1MTJDODcyIDMxMy4xNzcgNzEwLjgyMyAxNTIgNTEyIDE1MkMzMTMuMTc3IDE1MiAxNTIgMzEzLjE3NyAxNTIgNTEyWk00MjAgMzk2QzQwNi43NDUgMzk2IDM5NiA0MDYuNzQ1IDM5NiA0MjBWNjA0QzM5NiA2MTcuMjU1IDQwNi43NDUgNjI4IDQyMCA2MjhINjA0QzYxNy4yNTUgNjI4IDYyOCA2MTcuMjU1IDYyOCA2MDRWNDIwQzYyOCA0MDYuNzQ1IDYxNy4yNTUgMzk2IDYwNCAzOTZINDIwWiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==", trust: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI4LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzOTkuOCA0MTUuMSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzk5LjggNDE1LjE7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojMDUwMEZGO30KCS5zdDF7ZmlsbDp1cmwoI1NWR0lEXzFfKTt9Cjwvc3R5bGU+CjxnPgoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTU1LjUsOTJsMTQ0LjQtNDd2MzI1Qzk2LjcsMzI2LjcsNTUuNSwyNDMuNiw1NS41LDE5Ni43TDU1LjUsOTJMNTUuNSw5MnoiLz4KCQoJCTxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMV8iIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMzA1Ljk5NTMiIHkxPSIxODQ2LjAwMDIiIHgyPSIxOTYuODc1MiIgeTI9IjIxODkuMzQwMyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAxIDAgLTE4MjMuNzM5NykiPgoJCTxzdG9wICBvZmZzZXQ9IjIuMDAwMDAwZS0wMiIgc3R5bGU9InN0b3AtY29sb3I6IzAwMDBGRiIvPgoJCTxzdG9wICBvZmZzZXQ9IjguMDAwMDAwZS0wMiIgc3R5bGU9InN0b3AtY29sb3I6IzAwOTRGRiIvPgoJCTxzdG9wICBvZmZzZXQ9IjAuMTYiIHN0eWxlPSJzdG9wLWNvbG9yOiM0OEZGOTEiLz4KCQk8c3RvcCAgb2Zmc2V0PSIwLjQyIiBzdHlsZT0ic3RvcC1jb2xvcjojMDA5NEZGIi8+CgkJPHN0b3AgIG9mZnNldD0iMC42OCIgc3R5bGU9InN0b3AtY29sb3I6IzAwMzhGRiIvPgoJCTxzdG9wICBvZmZzZXQ9IjAuOSIgc3R5bGU9InN0b3AtY29sb3I6IzA1MDBGRiIvPgoJPC9saW5lYXJHcmFkaWVudD4KCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0zNDQuNCw5MkwxOTkuOSw0NXYzMjVjMTAzLjItNDMuMywxNDQuNS0xMjYuNCwxNDQuNS0xNzMuM1Y5MkwzNDQuNCw5MnoiLz4KPC9nPgo8L3N2Zz4K", brave: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNTYgMzAxIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyNTYgMzAxIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgoKCTxwYXRoIGZpbGw9IiNGMTVBMjIiIGQ9Im0yMzYgM