Skip to content

Commit

Permalink
refactor!: remove allowlist & denylist functionality (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
tien authored Oct 22, 2024
1 parent 24dd969 commit 9b831f9
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 49 deletions.
6 changes: 6 additions & 0 deletions .changeset/friendly-files-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@reactive-dot/react": minor
"@reactive-dot/vue": minor
---

BREAKING: Removed `allowlist` and `denylist` functionality. This feature was too specific, and it’s now recommended for users to implement it as a recipe in their own applications if needed.
70 changes: 55 additions & 15 deletions apps/docs/docs/guides/multichain.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@ function Component() {

## Chain narrowing

By default, ReactiveDOT provides type definitions based on the merged definitions of all chains in the config. For example, if your DApp is set up to be used with Polkadot, Kusama, and Westend, the following code will not work because the Bounties pallet only exists on Polkadot and Kusama, not on Westend:
By default, ReactiveDOT merges type definitions from all the chains in the config. For instance, if your DApp is set up to work with Polkadot, Kusama, and Westend, the following code will fail because the Bounties pallet is available only on Polkadot and Kusama, not on Westend:

```tsx
function Component() {
// Since `Bounties` pallet doesn't exist on Westend, this will:
// 1. Raise a TypeScript error
// 2. Throw an error during runtime if Westend is selected
// Since the `Bounties` pallet doesn't exist on Westend, this will:
// 1. Trigger a TypeScript error
// 2. Cause a runtime error if Westend is selected
const bountyCount = useLazyLoadQuery((builder) =>
builder.readStorage("Bounties", "BountyCount", []),
);
Expand All @@ -134,7 +134,7 @@ function Component() {
}
```

You have the option of either explicitly specifying the chain to query, which will override the chain ID provided via context:
To resolve this, you can explicitly specify the chain to query, which will override the chain ID provided by context:

```tsx
function Component() {
Expand All @@ -147,21 +147,31 @@ function Component() {
}
```

Or, to continue using the chain ID provided via context, you can use the [`useChainId`](/api/react/function/useChainId) hook along with its allowlist/denylist functionality:
Alternatively, if you want to keep using the chain ID provided by context, you can use the following pattern:

```tsx
function useBountiesChainId() {
const chainId = useChainId();

switch (chainId) {
case "polkadot":
case "kusama":
return chainId;
default:
throw new Error("This chain does not support bounties", {
cause: chainId,
});
}
}

function BountiesPalletRequiredComponent() {
const bountyCount = useLazyLoadQuery(
(builder) => builder.readStorage("Bounties", "BountyCount", []),
{
// `useChainId` with the allow/deny list will:
// 1. Throw an error if the context's chain ID conflicts with the list(s)
// 2. Restrict descriptors used by `useLazyLoadQuery` to provide correct intellisense
chainId: useChainId({
allowlist: ["polkadot", "kusama"],
// Or
denylist: ["westend"],
}),
// This will:
// 1. Throw an error if the chain ID does not support bounties
// 2. Restrict the possible chain types for better intellisense
chainId: useBountiesChainId(),
},
);

Expand All @@ -171,7 +181,7 @@ function BountiesPalletRequiredComponent() {
function App() {
// ...

// Only use compatible chain IDs, else an error will be thrown
// Use only compatible chain IDs, otherwise an error will be thrown
const bountiesEnabledChainIds = ["polkadot", "kusama"] satisfies ChainId[];

return (
Expand All @@ -186,3 +196,33 @@ function App() {
);
}
```

Finally, if your application primarily uses a few chains but interacts with many other supporting chains, you can use the `targetChains` option:

```ts
import { defineConfig } from "@reactive-dot/core";

const config = defineConfig({
chains: {
polkadot: {
// ...
},
polkadot_asset_hub: {
// ...
},
polkadot_people: {
// ...
},
polkadot_collectives: {
// ...
},
polkadot_bridge_hub: {
// ...
},
},
// This will restrict the default chain types used by hooks
// to just Polkadot when no explicit `chainId` is provided
targetChains: ["polkadot"],
// ...
});
```
19 changes: 2 additions & 17 deletions packages/react/src/hooks/use-chain-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,16 @@ export function useChainIds() {
/**
* Hook for getting the current chain ID.
*
* @param options - Additional options
* @returns The current chain ID
*/
export function useChainId<
const TAllowList extends ChainId[],
const TDenylist extends ChainId[] = [],
>(options?: { allowlist?: TAllowList; denylist?: TDenylist }) {
export function useChainId() {
const chainId = useContext(ChainIdContext);

if (chainId === undefined) {
throw new ReactiveDotError("No chain ID provided");
}

if (options?.allowlist?.includes(chainId) === false) {
throw new ReactiveDotError("Chain ID not allowed", { cause: chainId });
}

if (options?.denylist?.includes(chainId)) {
throw new ReactiveDotError("Chain ID denied", { cause: chainId });
}

return chainId as Exclude<
Extract<ChainId, TAllowList[number]>,
TDenylist[number]
>;
return chainId as ChainId;
}

/**
Expand Down
19 changes: 2 additions & 17 deletions packages/vue/src/composables/use-chain-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ export function useChainIds() {
/**
* Composable for getting the current chain ID.
*
* @param options - Additional options
* @returns The current chain ID
*/
export function useChainId<
const TAllowList extends ChainId[],
const TDenylist extends ChainId[] = [],
>(options?: { allowlist?: TAllowList; denylist?: TDenylist }) {
export function useChainId() {
const injectedChainId = inject(chainIdKey);

return computed(() => {
Expand All @@ -32,18 +28,7 @@ export function useChainId<
throw new ReactiveDotError("No chain ID provided");
}

if (options?.allowlist?.includes(chainId) === false) {
throw new ReactiveDotError("Chain ID not allowed", { cause: chainId });
}

if (options?.denylist?.includes(chainId)) {
throw new ReactiveDotError("Chain ID denied", { cause: chainId });
}

return chainId as Exclude<
Extract<ChainId, TAllowList[number]>,
TDenylist[number]
>;
return chainId as ChainId;
});
}

Expand Down

0 comments on commit 9b831f9

Please sign in to comment.