@unilogin/sdk
Version:
SDK is a JS library, that communicates with relayer. SDK allows managing contract, by creating basic contract-calling messages.
78 lines (67 loc) • 3.05 kB
text/typescript
import {BlockchainService} from '@unilogin/contracts';
import {WalletEventCallback, WalletEventFilter, WalletEventType} from '../models/events';
import {WalletEventsObserver} from './WalletEventsObserver';
import {Callback} from 'reactive-properties';
import {ensureNotNullish, Nullable} from '@unilogin/commons';
import {InvalidObserverState, MissingParameter} from '../utils/errors';
import {BlockNumberState} from '../states/BlockNumberState';
import {IStorageService} from '../models/IStorageService';
import {StorageEntry} from '../services/StorageEntry';
import {MemoryStorageService} from '../services/MemoryStorageService';
import {asNumber} from '@restless/sanitizers';
const STORAGE_KEY = 'LAST_BLOCK_NUMBER';
class WalletEventsObserverFactory {
protected observers: Record<string, WalletEventsObserver> = {};
private unsubscribe: Nullable<Callback> = null;
private blockNumberStorage: StorageEntry<number>;
constructor(
private blockchainService: BlockchainService,
private currentBlock: BlockNumberState,
storageService: IStorageService = new MemoryStorageService(),
) {
this.blockNumberStorage = new StorageEntry(STORAGE_KEY, asNumber, storageService);
}
async start() {
this.currentBlock.set(await this.blockchainService.getBlockNumber());
if (!this.blockNumberStorage.get()) {
this.blockNumberStorage.set(this.currentBlock.get());
}
this.unsubscribe = this.currentBlock.subscribe(() => this.fetchEvents());
}
async fetchEvents() {
ensureNotNullish(this.currentBlock.get(), InvalidObserverState);
if (Object.keys(this.observers).length === 0) {
return;
}
await this.fetchEventsOfTypes(['KeyAdded', 'KeyRemoved', 'AddedOwner', 'RemovedOwner']);
}
async fetchEventsOfTypes(types: WalletEventType[]) {
const currentBlockNumber = this.currentBlock.get();
const storageBlockNumber = this.blockNumberStorage.get();
ensureNotNullish(currentBlockNumber, InvalidObserverState);
ensureNotNullish(storageBlockNumber, MissingParameter, 'storageBlockNumber');
if (currentBlockNumber === storageBlockNumber) {
return;
}
this.blockNumberStorage.set(currentBlockNumber);
for (const contractAddress of Object.keys(this.observers)) {
await this.observers[contractAddress].fetchEvents(storageBlockNumber + 1, types);
}
}
subscribe(eventType: WalletEventType, filter: WalletEventFilter, callback: WalletEventCallback) {
this.observers[filter.contractAddress] = this.observers[filter.contractAddress] || new WalletEventsObserver(filter.contractAddress, this.blockchainService);
const observableRecord = {key: filter.key, callback};
const unsubscribe = this.observers[filter.contractAddress].subscribe(eventType, observableRecord);
this.fetchEvents();
return unsubscribe;
}
stop() {
ensureNotNullish(this.unsubscribe, InvalidObserverState);
this.unsubscribe();
this.unsubscribe = null;
}
finalizeAndStop() {
this.stop();
}
}
export default WalletEventsObserverFactory;