Skip to content

Commit

Permalink
fix: allow passing kit functions by reference
Browse files Browse the repository at this point in the history
What
----

Define methods using `methodName = async () => {…}` syntax, rather than `async
methodName() {…}`

Why
---

This allows for better APIs when using StellarWalletsKit. For example, given a
`stellar-wallets-kit.ts` file in my own project with:

```ts
const kit: StellarWalletsKit = new StellarWalletsKit({…});

export const signTransaction = kit.signTransaction;
```

And I then use this in my app:

```ts
const tx = await incrementor.increment();
const { result } = await tx.signAndSend({ signTransaction })
```

Today, the `signAndSend` will throw a runtime error:

```
TypeError: Cannot read properties of undefined (reading 'selectedModule')
```

This is because JavaScript's default behavior is coo coo bananas, no one
understands it, and `this` ends up getting bound to `undefined` if you use the
`async methodName() {…}` syntax and then pass `methodName` as a reference the
way I did.

Today, in order to make my code work, I would need to export the whole `kit` and
then change my `signAndSend` line to:

```ts
const { result } = await tx.signAndSend({
  signTransaction: async (xdr) => {
    return await kit.signTransaction(xdr);
  },
});
```

I don't like this because A) it's ugly and B) I don't think it's good practice
to export the whole `kit`. Within my app, I want to have the ability to wrap
interfaces like `signTransaction`, so that I can always make sure app-specific
logic gets taken care of. Exporting all of `kit` adds more room for error.

The Fix
-------

Using the arrow syntax with `methodName = async (…) => {…}` makes JS use similar
`this`-binding logic to every other language, and makes my pass-by-reference
use-case possible.
  • Loading branch information
chadoh committed Dec 11, 2024
1 parent 97dbed6 commit cfab98e
Showing 1 changed file with 29 additions and 29 deletions.
58 changes: 29 additions & 29 deletions src/stellar-wallets-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class StellarWalletsKit implements KitActions {
* This method will return an array with all wallets supported by this kit but will let you know those the user have already installed/has access to
* There are wallets that are by default available since they either don't need to be installed or have a fallback
*/
public async getSupportedWallets(): Promise<ISupportedWallet[]> {
public getSupportedWallets = async (): Promise<ISupportedWallet[]> => {
return Promise.all(
this.modules.map(async (mod: ModuleInterface): Promise<ISupportedWallet> => {
const timer: Promise<false> = new Promise(r => setTimeout(() => r(false), 500));
Expand All @@ -79,9 +79,9 @@ export class StellarWalletsKit implements KitActions {
};
})
);
}
};

public setWallet(id: string): void {
public setWallet = (id: string): void => {
const target: ModuleInterface | undefined = this.modules.find(
(mod: ModuleInterface): boolean => mod.productId === id
);
Expand All @@ -91,15 +91,15 @@ export class StellarWalletsKit implements KitActions {
}

setSelectedModuleId(target.productId);
}
};

public async getAddress(params?: { path?: string }): Promise<{ address: string }> {
public getAddress = async (params?: { path?: string }): Promise<{ address: string }> => {
const { address } = await this.selectedModule.getAddress(params);
setAddress(address);
return { address };
}
};

public async signTransaction(
public signTransaction = (
xdr: string,
opts?: {
networkPassphrase?: string;
Expand All @@ -108,61 +108,61 @@ export class StellarWalletsKit implements KitActions {
submit?: boolean;
submitUrl?: string;
}
): Promise<{ signedTxXdr: string; signerAddress?: string }> {
): Promise<{ signedTxXdr: string; signerAddress?: string }> => {
return this.selectedModule.signTransaction(xdr, {
...opts,
networkPassphrase: opts?.networkPassphrase || store.getValue().selectedNetwork,
});
}
};

public async signAuthEntry(
public signAuthEntry = (
authEntry: string,
opts?: {
networkPassphrase?: string;
address?: string;
path?: string;
}
): Promise<{ signedAuthEntry: string; signerAddress?: string }> {
): Promise<{ signedAuthEntry: string; signerAddress?: string }> => {
return this.selectedModule.signAuthEntry(authEntry, {
...opts,
networkPassphrase: opts?.networkPassphrase || store.getValue().selectedNetwork,
});
}
};

public async signMessage(
public signMessage = (
message: string,
opts?: {
networkPassphrase?: string;
address?: string;
path?: string;
}
): Promise<{ signedMessage: string; signerAddress?: string }> {
): Promise<{ signedMessage: string; signerAddress?: string }> => {
return this.selectedModule.signMessage(message, {
...opts,
networkPassphrase: opts?.networkPassphrase || store.getValue().selectedNetwork,
});
}
};

async getNetwork(): Promise<{ network: string; networkPassphrase: string }> {
public getNetwork = (): Promise<{ network: string; networkPassphrase: string }> => {
return this.selectedModule.getNetwork();
}
};

async disconnect(): Promise<void> {
public disconnect = async (): Promise<void> => {
removeAddress();
}
};

// ---- Button methods
public isButtonCreated(): boolean {
public isButtonCreated = (): boolean => {
return !!this.buttonElement;
}
};

public async createButton(params: {
public createButton = async (params: {
container: HTMLElement;
onConnect: (response: { address: string }) => void;
onDisconnect: () => void;
horizonUrl?: string;
buttonText?: string;
}): Promise<void> {
}): Promise<void> => {
if (this.buttonElement) {
throw new Error(`Stellar Wallets Kit button is already created`);
}
Expand Down Expand Up @@ -203,14 +203,14 @@ export class StellarWalletsKit implements KitActions {
},
false
);
}
};

/**
* Removes the button elements from the HTML and from the kit's instance.
*
* @param params.skipDisconnect - Set this to `true` if you want to prevent that we disconnect (for example, disconnecting WalletConnect or removing the address)
*/
public async removeButton(params?: { skipDisconnect?: boolean }): Promise<void> {
public removeButton = async (params?: { skipDisconnect?: boolean }): Promise<void> => {
if (!this.buttonElement) {
throw new Error(`Stellar Wallets Kit button hasn't been created yet`);
}
Expand All @@ -221,16 +221,16 @@ export class StellarWalletsKit implements KitActions {

this.buttonElement.remove();
delete this.buttonElement;
}
};
// ---- END Button methods

// ---- Modal methods
public async openModal(params: {
public openModal = async (params: {
onWalletSelected: (option: ISupportedWallet) => void;
onClosed?: (err: Error) => void;
modalTitle?: string;
notAvailableText?: string;
}): Promise<void> {
}): Promise<void> => {
if (this.modalElement && !this.buttonElement) {
throw new Error(`Stellar Wallets Kit modal is already open`);
} else {
Expand Down Expand Up @@ -281,6 +281,6 @@ export class StellarWalletsKit implements KitActions {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.modalElement.addEventListener('modal-closed', errorListener, false);
}
};
// ---- END Modal methods
}

0 comments on commit cfab98e

Please sign in to comment.