Files
varan-connect/src/store.ts
T
odiinnn 13eea0bfad Add transaction signing functionality to App component
- Introduced a new button to sign transactions, allowing users to generate a signature for a predefined raw transaction.
- Updated state management to handle the transaction signature and display it in the UI.
- Enhanced connection logic to ensure the user's address is retrieved before signing.
- Modified the WalletStore to improve transaction status handling during updates.
2025-10-06 09:45:39 +03:00

152 lines
5.4 KiB
TypeScript

import type { InjectedMetadataKnown } from "@polkadot/extension-inject/types";
import { VARAN_WALLET_LS_KEY } from "./constants";
import { generateRequestId } from "./helpers";
import { WalletStorage } from "./types";
type WalletStoreType = {
accounts: string[];
injectedMetadataKnown?: InjectedMetadataKnown;
transactions: {
id: number;
signedTx: string;
status: 'signing' | 'success' | 'failed';
}[];
}
const defaultStore: WalletStoreType = {
accounts: [],
injectedMetadataKnown: undefined,
transactions: [],
}
export class WalletStore {
private readonly store: WalletStorage;
private readonly storeSubscribe: (cb: (ev: StorageEvent) => void) => void;
private _store: WalletStoreType;
constructor() {
this.store = window.localStorage as WalletStorage;
this._store = Object.assign(defaultStore, JSON.parse(this.store.getItem(VARAN_WALLET_LS_KEY) || '{}'));
this.storeSubscribe = (cb): void => {
window.addEventListener('storage', cb);
};
this._setupListeners();
}
private callbacks: {
[K in keyof WalletStoreType]: ({
cb: (value: WalletStoreType[K]) => void,
id: number;
})[];
} = {
accounts: [],
injectedMetadataKnown: [],
transactions: [],
};
private _setupListeners(): void {
let currentState = this._store;
this.storeSubscribe(ev => {
ev.stopImmediatePropagation();
if (ev.key !== VARAN_WALLET_LS_KEY) return;
const data = JSON.parse(ev.newValue || '{}') as WalletStoreType;
const keys = Object.keys(data) as (keyof WalletStoreType)[];
for (const key of keys) {
if (key === 'injectedMetadataKnown') continue;
if (key === 'accounts') {
const currentAccounts = currentState[key];
const dataAccounts = data[key];
if (currentAccounts.length !== dataAccounts.length) {
currentState = data;
this._store = data;
this.dispatch(key);
continue;
}
let shouldDispatch = false;
dataAccounts.forEach(account => {
if (!currentAccounts.includes(account)) {
shouldDispatch = true;
}
});
if (shouldDispatch) {
currentState = data;
this._store = data;
this.dispatch(key);
}
continue;
}
if (key === 'transactions') {
const currentTransactions = currentState[key];
const dataTransactions = data[key];
if (currentTransactions.length !== dataTransactions.length) {
currentState = data;
this._store = data;
this.dispatch(key);
continue;
}
let shouldDispatch = false;
dataTransactions.forEach(transaction => {
const currentTransaction = currentTransactions.find(t => t.id === transaction.id);
if (currentTransaction && currentTransaction.status !== transaction.status) {
shouldDispatch = true;
}
});
if (shouldDispatch) {
currentState = data;
this._store = data;
this.dispatch(key);
}
continue;
}
}
});
}
private dispatch<Key extends keyof WalletStoreType>(key: Key): void {
const callbacks = this.callbacks[key];
if (!callbacks || callbacks.length === 0) return;
callbacks.forEach(c => c.cb(this._store[key]));
}
get<Key extends keyof WalletStoreType>(key: Key): WalletStoreType[Key] {
return this._store[key] || defaultStore[key];
}
set<Key extends keyof WalletStoreType>(key: Key, value: WalletStoreType[Key]): void {
this._store[key] = value;
this.dispatch(key);
this.store.setItem(VARAN_WALLET_LS_KEY, JSON.stringify(this._store));
}
remove<Key extends keyof WalletStoreType>(key: Key): void {
const value = this._store[key];
if (value) {
this._store[key] = defaultStore[key];
}
this.store.setItem(VARAN_WALLET_LS_KEY, JSON.stringify(this._store));
}
clear(): void {
this.store.removeItem(VARAN_WALLET_LS_KEY);
}
subscribe<Key extends keyof WalletStoreType>(key: Key, cb: (value: WalletStoreType[Key]) => void): number {
if (this.callbacks[key] == undefined) {
this.callbacks[key] = [];
}
const id = generateRequestId();
this.callbacks[key].push({cb, id});
return id;
}
unsubscribe<Key extends keyof WalletStoreType>(key: Key, id: number): void {
if (this.callbacks[key] == undefined || this.callbacks[key].length === 0) return;
const filtered = this.callbacks[key].filter(c => c.id !== id);
this.callbacks[key] = filtered as typeof this.callbacks[Key];
}
}