Skip to content

Commit

Permalink
feat: event handling in get-starknet
Browse files Browse the repository at this point in the history
  • Loading branch information
khanti42 committed Nov 5, 2024
1 parent abdd77d commit 53d1b9f
Showing 1 changed file with 117 additions and 7 deletions.
124 changes: 117 additions & 7 deletions packages/get-starknet/src/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MutexInterface } from 'async-mutex';
import { Mutex } from 'async-mutex';
import type { WalletEventHandlers } from 'get-starknet-core';
import type { AccountChangeEventHandler, NetworkChangeEventHandler, WalletEventHandlers } from 'get-starknet-core';
import { type RpcMessage, type StarknetWindowObject } from 'get-starknet-core';
import type { AccountInterface, ProviderInterface } from 'starknet';
import { Provider } from 'starknet';
Expand Down Expand Up @@ -49,12 +49,18 @@ export class MetaMaskSnapWallet implements StarknetWindowObject {

#selectedAddress: string;

#latestAddress: string;

#chainId: string;

#network: Network;

lock: MutexInterface;

#networkChangeController: AbortController | undefined;

#accountChangeController: AbortController | undefined;

// eslint-disable-next-line @typescript-eslint/naming-convention, no-restricted-globals
static readonly snapId = process.env.SNAP_ID ?? 'npm:@consensys/starknet-snap';

Expand All @@ -67,6 +73,7 @@ export class MetaMaskSnapWallet implements StarknetWindowObject {
this.metamaskProvider = metamaskProvider;
this.snap = new MetaMaskSnap(MetaMaskSnapWallet.snapId, snapVersion, this.metamaskProvider);
this.isConnected = false;
this.#latestAddress = "0x";

this.#rpcHandlers = new Map<string, IStarknetWalletRpc>([
[RpcMethod.WalletSwitchStarknetChain, new WalletSwitchStarknetChain(this)],
Expand Down Expand Up @@ -184,6 +191,9 @@ export class MetaMaskSnapWallet implements StarknetWindowObject {
this.#provider = undefined;
// account is depends on address and provider, if network changes, address will update,
// hence set account to undefine for reinitialization
// TODO : This should be removed. The walletAccount is created with the SWO as input.
// This means account is not managed from within the SWO but from outside.
// Event handling helps ensure that the correct address is set.
this.#account = undefined;
}

Expand All @@ -208,13 +218,113 @@ export class MetaMaskSnapWallet implements StarknetWindowObject {
return true;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
on<Event extends keyof WalletEventHandlers>(_event: Event, _handleEvent: WalletEventHandlers[Event]): void {
// No operation for now
/**
* Registers an event handler for `accountsChanged` or `networkChanged`.
*
* @param event - The event name ('accountsChanged' or 'networkChanged')
* @param handleEvent - The event handler function
*/
on<Event extends keyof WalletEventHandlers>(event: Event, handleEvent: WalletEventHandlers[Event]): void {
if (event === 'accountsChanged') {
this.onAccountChanged(handleEvent as AccountChangeEventHandler);
} else if (event === 'networkChanged') {
this.onNetworkChanged(handleEvent as NetworkChangeEventHandler);
} else {
throw new Error(`Unsupported event: ${String(event)}`);
}
}

/**
* Removes an event handler for `accountsChanged` or `networkChanged`.
*
* @param event - The event name ('accountsChanged' or 'networkChanged')
* @param _handleEvent
*/
off<Event extends keyof WalletEventHandlers>(event: Event, _handleEvent?: WalletEventHandlers[Event]): void {
if (event === 'accountsChanged') {
this.offAccountChanged();
} else if (event === 'networkChanged') {
this.offNetworkChanged();
} else {
throw new Error(`Unsupported event: ${String(event)}`);
}
}

/**
* Starts polling for account changes and calls the callback when a change is detected.
* @param callback - The function to call when an account change is detected.
*/
onAccountChanged(callback: AccountChangeEventHandler): void {
// Set up an AbortController to manage the polling loop
this.#accountChangeController = new AbortController();
const { signal } = this.#accountChangeController;

const pollForAccountChange = async () => {
while (!signal.aborted) {
const previousNetwork = this.#network;
await this.#init();
if (previousNetwork.chainId !== this.#network.chainId || this.#latestAddress !== this.#selectedAddress) {
this.#latestAddress = this.#selectedAddress;
callback([this.#selectedAddress]);
}

await new Promise((resolve) => setTimeout(resolve, 5000));
}
};

pollForAccountChange().catch((error) => {
if (!signal.aborted) {
console.error('Error in account change polling:', error);
}
});
}

/**
* Stops polling for account changes.
*/
offAccountChanged(): void {
if (this.#accountChangeController) {
this.#accountChangeController.abort();
this.#accountChangeController = undefined;
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
off<Event extends keyof WalletEventHandlers>(_event: Event, _handleEvent?: WalletEventHandlers[Event]): void {
// No operation for now
/**
* Starts polling for network changes and calls the callback when a change is detected.
* @param callback - The function to call when a network change is detected.
*/
onNetworkChanged(callback: NetworkChangeEventHandler): void {
// Set up an AbortController to manage the polling loop
this.#networkChangeController = new AbortController();
const { signal } = this.#networkChangeController;

const pollForNetworkChange = async () => {
while (!signal.aborted) {
const previousNetwork = this.#network;
await this.#init();

if (previousNetwork.chainId !== this.#network.chainId) {
callback(this.#network.chainId, [this.#selectedAddress]);
}

await new Promise((resolve) => setTimeout(resolve, 5000));
}
};

pollForNetworkChange().catch((error) => {
if (!signal.aborted) {
console.error('Error in network change polling:', error);
}
});
}

/**
* Stops polling for network changes.
*/
offNetworkChanged(): void {
if (this.#networkChangeController) {
this.#networkChangeController.abort();
this.#networkChangeController = undefined;
}
}
}

0 comments on commit 53d1b9f

Please sign in to comment.