diff --git a/src/constants.ts b/src/constants.ts index b2236a1..1c4cef0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,7 +1,7 @@ +import type { InjectedExtension } from "@polkadot/extension-inject/types"; + export const VARAN_WALLET_LS_KEY = 'VARAN_WALLET'; - - -window.addEventListener('storage', (ev) => { - if (ev.storageArea !== localStorage || ev.key !== VARAN_WALLET_LS_KEY) return; - -}) \ No newline at end of file +export const mockAccountsSubscribe: InjectedExtension['accounts']['subscribe'] = () => { + console.warn('Accounts subscribe does not currently support in Varan Wallet'); + return () => {}; +}; \ No newline at end of file diff --git a/src/helpers.ts b/src/helpers.ts index 18ac724..bf2b708 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -6,7 +6,6 @@ export const parseWalletsFromStartParam = (webApp: WebApp): ConnectResult['walle if (!startParam) return null; const result = decodeResult(startParam); - console.log('parseWalletsFromStartParam', result); return 'wallets' in result ? result.wallets : null; }; diff --git a/src/store.ts b/src/store.ts index 4d20717..8a5d9ff 100644 --- a/src/store.ts +++ b/src/store.ts @@ -20,9 +20,14 @@ const defaultStore: WalletStoreType = { } export class WalletStore { - constructor( - private readonly store: WalletStorage, - ) { + private readonly store: WalletStorage; + private readonly storeSubscribe: (cb: (ev: StorageEvent) => void) => void; + + constructor() { + this.store = window.localStorage as WalletStorage; + this.storeSubscribe = (cb): void => { + window.addEventListener('storage', cb); + }; this._setupListeners(); } @@ -38,12 +43,12 @@ export class WalletStore { }; private get _store(): WalletStoreType { - return JSON.parse(this.store.getItem(VARAN_WALLET_LS_KEY) || '{}') as WalletStoreType; + return Object.assign(defaultStore, JSON.parse(this.store.getItem(VARAN_WALLET_LS_KEY) || '{}')) as WalletStoreType; } private _setupListeners(): void { let currentState = this._store; - this.store.subscribe(ev => { + this.storeSubscribe(ev => { ev.stopImmediatePropagation(); if (ev.key !== VARAN_WALLET_LS_KEY) return; @@ -103,7 +108,7 @@ export class WalletStore { } get(key: Key): WalletStoreType[Key] { - return this._store[key]; + return this._store[key] || defaultStore[key]; } set(key: Key, value: WalletStoreType[Key]): void { diff --git a/src/types.ts b/src/types.ts index 9a52b90..cfff711 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,15 +5,12 @@ declare global { interface Window extends InjectedWindow {} } -export type WalletStorage = Storage & { - subscribe: (cb: (ev: StorageEvent) => void) => void; -} +export type WalletStorage = Storage; export type InjectionConfig = { callbackUrl: string; isDev?: boolean; connectTimeout?: number; - storage?: WalletStorage; } export type WebApp = typeof WebAppConst; diff --git a/src/varan-wallet.ts b/src/varan-wallet.ts index 0ced4ce..9c5eab1 100644 --- a/src/varan-wallet.ts +++ b/src/varan-wallet.ts @@ -5,12 +5,6 @@ const defaultInjectionConfig: Required = { callbackUrl: '', isDev: false, connectTimeout: 30_000, - storage: { - ...localStorage, - subscribe: (cb) => { - window.addEventListener('storage', cb); - }, - } , } const injectVaranWallet = (webApp: WebApp, config: InjectionConfig = defaultInjectionConfig): void => { diff --git a/src/wallet.ts b/src/wallet.ts index c78d500..bb20a8e 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -1,10 +1,11 @@ import type { ConnectRequest, SignTransactionRequest, WebApp } from "./types"; import type { InjectionConfig } from "./types"; import { WalletStore } from "./store"; -import type { InjectedAccount, InjectedExtension, InjectedWindowProvider } from "@polkadot/extension-inject/types"; +import type { Injected, InjectedAccount, InjectedExtension, InjectedMetadataKnown, InjectedWindowProvider } from "@polkadot/extension-inject/types"; import { encodeRequest } from "./encryption"; import { SignerPayloadRaw, SignerResult } from "@polkadot/types/types"; import { generateRequestId, parseSignedTxFromStartParam, parseWalletsFromStartParam } from "./helpers"; +import { mockAccountsSubscribe } from "./constants"; export class Wallet implements InjectedWindowProvider { private readonly varanWalletUrl!: string; @@ -15,10 +16,10 @@ export class Wallet implements InjectedWindowProvider { constructor( private readonly webApp: WebApp, - { callbackUrl, isDev, connectTimeout, storage }: Required, + { callbackUrl, isDev, connectTimeout }: Required, ) { this.varanWalletUrl = isDev ? 'https://t.me/devReptileBot?startapp=' : 'https://t.me/varanwalletbot?startapp='; - this.store = new WalletStore(storage); + this.store = new WalletStore(); this.callbackUrl = callbackUrl; this.connectTimeout = connectTimeout; void this._startParamsCheck(); @@ -28,6 +29,12 @@ export class Wallet implements InjectedWindowProvider { return '1.0.0'; } + private get signer(): InjectedExtension['signer'] { + return { + signRaw: (raw) => this.signRawTransaction(raw), + }; + } + private async _startParamsCheck(): Promise { let actions = 0; const newWalletAddresses = parseWalletsFromStartParam(this.webApp); @@ -66,7 +73,7 @@ export class Wallet implements InjectedWindowProvider { if (actions) { - this.webApp.close(); + // this.webApp.close(); } } @@ -82,6 +89,29 @@ export class Wallet implements InjectedWindowProvider { return Promise.resolve(accounts.map(this.formatAccount)); } + private get extensionAccounts(): InjectedExtension['accounts'] { + return { + get: () => this.accounts, + subscribe: mockAccountsSubscribe + }; + } + + private get extensionMetadata(): InjectedExtension['metadata'] { + const metadata = this.store.get('injectedMetadataKnown'); + const setMetadata = async (metadata: InjectedMetadataKnown) => { + await this.store.set('injectedMetadataKnown', metadata); + return true; + }; + if (!metadata) return { + get: () => Promise.resolve([]), + provide: setMetadata, + }; + return { + get: () => Promise.resolve([metadata]), + provide: setMetadata, + }; + } + private async signRawTransaction(raw: SignerPayloadRaw): Promise { const accounts = await this.accounts; if (!accounts.length) throw new Error('No accounts found'); @@ -143,27 +173,36 @@ export class Wallet implements InjectedWindowProvider { } async connect(): Promise { - await Promise.race([ - this._connect(), - new Promise((_, reject) => { - setTimeout(() => { - reject(new Error('Connect timeout')); - }, this.connectTimeout); - }) - ]); + const accounts = await this.accounts; + if (!accounts.length) { + await Promise.race([ + this._connect(), + new Promise((_, reject) => { + setTimeout(() => { + reject(new Error('Connect timeout')); + }, this.connectTimeout); + }) + ]); + } return Promise.resolve({ name: this.name, version: this.version, - accounts: { - get: () => this.accounts, - subscribe: () => { - return () => {}; - }, - }, - signer: { - signRaw: (raw) => this.signRawTransaction(raw), - }, + accounts: this.extensionAccounts, + signer: this.signer, + metadata: this.extensionMetadata, }); } + + async enable(): Promise { + const accounts = await this.accounts; + if (!accounts.length) { + throw new Error('Please connect first'); + } + return { + accounts: this.extensionAccounts, + signer: this.signer, + metadata: this.extensionMetadata, + }; + } } \ No newline at end of file