Refactor wallet storage and subscription handling
- Updated WalletStore to manage localStorage and handle storage events more effectively. - Introduced mockAccountsSubscribe in constants for better account subscription handling. - Removed unnecessary storage subscription from InjectionConfig. - Enhanced Wallet class to utilize new account and metadata management methods.
This commit is contained in:
1 parent
1966988769
commit
38574daace
6 files changed
+70
-36
No files matched your search
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
|
import type { InjectedExtension } from "@polkadot/extension-inject/types";
|
||||||
|
|
||||||
export const VARAN_WALLET_LS_KEY = 'VARAN_WALLET';
|
export const VARAN_WALLET_LS_KEY = 'VARAN_WALLET';
|
||||||
|
export const mockAccountsSubscribe: InjectedExtension['accounts']['subscribe'] = () => {
|
||||||
|
console.warn('Accounts subscribe does not currently support in Varan Wallet');
|
||||||
window.addEventListener('storage', (ev) => {
|
return () => {};
|
||||||
if (ev.storageArea !== localStorage || ev.key !== VARAN_WALLET_LS_KEY) return;
|
};
|
||||||
|
|
||||||
})
|
|
||||||
@@ -6,7 +6,6 @@ export const parseWalletsFromStartParam = (webApp: WebApp): ConnectResult['walle
|
|||||||
if (!startParam) return null;
|
if (!startParam) return null;
|
||||||
|
|
||||||
const result = decodeResult(startParam);
|
const result = decodeResult(startParam);
|
||||||
console.log('parseWalletsFromStartParam', result);
|
|
||||||
return 'wallets' in result ? result.wallets : null;
|
return 'wallets' in result ? result.wallets : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -20,9 +20,14 @@ const defaultStore: WalletStoreType = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class WalletStore {
|
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();
|
this._setupListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,12 +43,12 @@ export class WalletStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private get _store(): WalletStoreType {
|
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 {
|
private _setupListeners(): void {
|
||||||
let currentState = this._store;
|
let currentState = this._store;
|
||||||
this.store.subscribe(ev => {
|
this.storeSubscribe(ev => {
|
||||||
ev.stopImmediatePropagation();
|
ev.stopImmediatePropagation();
|
||||||
if (ev.key !== VARAN_WALLET_LS_KEY) return;
|
if (ev.key !== VARAN_WALLET_LS_KEY) return;
|
||||||
|
|
||||||
@@ -103,7 +108,7 @@ export class WalletStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get<Key extends keyof WalletStoreType>(key: Key): WalletStoreType[Key] {
|
get<Key extends keyof WalletStoreType>(key: Key): WalletStoreType[Key] {
|
||||||
return this._store[key];
|
return this._store[key] || defaultStore[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
set<Key extends keyof WalletStoreType>(key: Key, value: WalletStoreType[Key]): void {
|
set<Key extends keyof WalletStoreType>(key: Key, value: WalletStoreType[Key]): void {
|
||||||
|
|||||||
+1
-4
@@ -5,15 +5,12 @@ declare global {
|
|||||||
interface Window extends InjectedWindow {}
|
interface Window extends InjectedWindow {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WalletStorage = Storage & {
|
export type WalletStorage = Storage;
|
||||||
subscribe: (cb: (ev: StorageEvent) => void) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type InjectionConfig = {
|
export type InjectionConfig = {
|
||||||
callbackUrl: string;
|
callbackUrl: string;
|
||||||
isDev?: boolean;
|
isDev?: boolean;
|
||||||
connectTimeout?: number;
|
connectTimeout?: number;
|
||||||
storage?: WalletStorage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WebApp = typeof WebAppConst;
|
export type WebApp = typeof WebAppConst;
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ const defaultInjectionConfig: Required<InjectionConfig> = {
|
|||||||
callbackUrl: '',
|
callbackUrl: '',
|
||||||
isDev: false,
|
isDev: false,
|
||||||
connectTimeout: 30_000,
|
connectTimeout: 30_000,
|
||||||
storage: {
|
|
||||||
...localStorage,
|
|
||||||
subscribe: (cb) => {
|
|
||||||
window.addEventListener('storage', cb);
|
|
||||||
},
|
|
||||||
} ,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const injectVaranWallet = (webApp: WebApp, config: InjectionConfig = defaultInjectionConfig): void => {
|
const injectVaranWallet = (webApp: WebApp, config: InjectionConfig = defaultInjectionConfig): void => {
|
||||||
|
|||||||
+52
-13
@@ -1,10 +1,11 @@
|
|||||||
import type { ConnectRequest, SignTransactionRequest, WebApp } from "./types";
|
import type { ConnectRequest, SignTransactionRequest, WebApp } from "./types";
|
||||||
import type { InjectionConfig } from "./types";
|
import type { InjectionConfig } from "./types";
|
||||||
import { WalletStore } from "./store";
|
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 { encodeRequest } from "./encryption";
|
||||||
import { SignerPayloadRaw, SignerResult } from "@polkadot/types/types";
|
import { SignerPayloadRaw, SignerResult } from "@polkadot/types/types";
|
||||||
import { generateRequestId, parseSignedTxFromStartParam, parseWalletsFromStartParam } from "./helpers";
|
import { generateRequestId, parseSignedTxFromStartParam, parseWalletsFromStartParam } from "./helpers";
|
||||||
|
import { mockAccountsSubscribe } from "./constants";
|
||||||
|
|
||||||
export class Wallet implements InjectedWindowProvider {
|
export class Wallet implements InjectedWindowProvider {
|
||||||
private readonly varanWalletUrl!: string;
|
private readonly varanWalletUrl!: string;
|
||||||
@@ -15,10 +16,10 @@ export class Wallet implements InjectedWindowProvider {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly webApp: WebApp,
|
private readonly webApp: WebApp,
|
||||||
{ callbackUrl, isDev, connectTimeout, storage }: Required<InjectionConfig>,
|
{ callbackUrl, isDev, connectTimeout }: Required<InjectionConfig>,
|
||||||
) {
|
) {
|
||||||
this.varanWalletUrl = isDev ? 'https://t.me/devReptileBot?startapp=' : 'https://t.me/varanwalletbot?startapp=';
|
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.callbackUrl = callbackUrl;
|
||||||
this.connectTimeout = connectTimeout;
|
this.connectTimeout = connectTimeout;
|
||||||
void this._startParamsCheck();
|
void this._startParamsCheck();
|
||||||
@@ -28,6 +29,12 @@ export class Wallet implements InjectedWindowProvider {
|
|||||||
return '1.0.0';
|
return '1.0.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get signer(): InjectedExtension['signer'] {
|
||||||
|
return {
|
||||||
|
signRaw: (raw) => this.signRawTransaction(raw),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private async _startParamsCheck(): Promise<void> {
|
private async _startParamsCheck(): Promise<void> {
|
||||||
let actions = 0;
|
let actions = 0;
|
||||||
const newWalletAddresses = parseWalletsFromStartParam(this.webApp);
|
const newWalletAddresses = parseWalletsFromStartParam(this.webApp);
|
||||||
@@ -66,7 +73,7 @@ export class Wallet implements InjectedWindowProvider {
|
|||||||
|
|
||||||
|
|
||||||
if (actions) {
|
if (actions) {
|
||||||
this.webApp.close();
|
// this.webApp.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +89,29 @@ export class Wallet implements InjectedWindowProvider {
|
|||||||
return Promise.resolve(accounts.map(this.formatAccount));
|
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<SignerResult> {
|
private async signRawTransaction(raw: SignerPayloadRaw): Promise<SignerResult> {
|
||||||
const accounts = await this.accounts;
|
const accounts = await this.accounts;
|
||||||
if (!accounts.length) throw new Error('No accounts found');
|
if (!accounts.length) throw new Error('No accounts found');
|
||||||
@@ -143,6 +173,8 @@ export class Wallet implements InjectedWindowProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async connect(): Promise<InjectedExtension> {
|
async connect(): Promise<InjectedExtension> {
|
||||||
|
const accounts = await this.accounts;
|
||||||
|
if (!accounts.length) {
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
this._connect(),
|
this._connect(),
|
||||||
new Promise<void>((_, reject) => {
|
new Promise<void>((_, reject) => {
|
||||||
@@ -151,19 +183,26 @@ export class Wallet implements InjectedWindowProvider {
|
|||||||
}, this.connectTimeout);
|
}, this.connectTimeout);
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
name: this.name,
|
name: this.name,
|
||||||
version: this.version,
|
version: this.version,
|
||||||
accounts: {
|
accounts: this.extensionAccounts,
|
||||||
get: () => this.accounts,
|
signer: this.signer,
|
||||||
subscribe: () => {
|
metadata: this.extensionMetadata,
|
||||||
return () => {};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
signer: {
|
|
||||||
signRaw: (raw) => this.signRawTransaction(raw),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async enable(): Promise<Injected> {
|
||||||
|
const accounts = await this.accounts;
|
||||||
|
if (!accounts.length) {
|
||||||
|
throw new Error('Please connect first');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
accounts: this.extensionAccounts,
|
||||||
|
signer: this.signer,
|
||||||
|
metadata: this.extensionMetadata,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user