owned this note
owned this note
Published
Linked with GitHub
# Reactive DOT: funding request for continuation of development
## Introduction
This proposal seeks continued funding for the development and refinement of the Reactive DOT library, building upon the progress made in proposal [#812](https://polkadot.polkassembly.io/referenda/812).
Reactive DOT is a library designed to:
- **Simplify development:** Provide a set of intuitive front-end functions and utilities to facilitate Substrate chain interactions, making development accessible for developers of all skill levels.
- **Enhance developer experience:** Reduce boilerplate code and complexity involved in integrating DApps with Substrate chains, allowing developers to focus on building robust applications.
- **Promote adoption:** Lower the entry barrier for developers through improved tooling and familiar patterns, encouraging the adoption of Polkadot.
The initial phase successfully achieved all outlined goals and stretch objectives, significantly enhancing the development experience for Substrate DApps.
## Achievements
### Main goals
The library was developed to work with [Polkadot-API](https://polkadot-api.github.io/polkadot-api-docs/) instead of [Polkadot.js](https://polkadot.js.org/docs/), achieving the following main goals:
- **[Reading](https://reactivedot.dev/docs/getting-started/query) chain constants, API calls, and storages:**
- Strong TypeScript IntelliSense and autocompletion.
- Caching, persistent storage, and de-duplication of read states.
- Async and error handling via React concurrency primitives (Suspense & Error Boundary).
- **[Multichain support](https://reactivedot.dev/docs/getting-started/multichain).**
- **Documentation and walkthroughs:**
- A [website](https://reactivedot.dev/) for documentation.
- Dynamically generated [API definitions](https://reactivedot.dev/api).
- **Community engagement:**
- Announcement post and feedback gathering [here](https://forum.polkadot.network/t/reactive-dot-a-reactive-library-for-building-substrate-front-ends/8655).
### Stretch goals
Leveraging the extremely well-built and lean core provided by [Polkadot-API](https://polkadot-api.github.io/polkadot-api-docs/), multiple stretch goals were achieved within the first development phase:
- **[Transaction submission](https://reactivedot.dev/docs/getting-started/mutation):**
- Fully typed, utilising return type from PAPI typed API tx.
- Overridable signer via [context](https://reactivedot.dev/docs/getting-started/mutation#1-via-context), [hook](https://reactivedot.dev/docs/getting-started/mutation#2-passing-signer-to-the-hook), and [callback](https://reactivedot.dev/docs/getting-started/mutation#2-passing-signer-to-the-final-submission) options.
- **[Wallet management](https://reactivedot.dev/docs/getting-started/connect-wallets):**
- Support for all browser-injected wallets (Talisman, Nova, Polkadot.js, SubWallet).
- Support WalletConnect via QR code scanning (Nova, SubWallet).
- Developed an accompanying drop-in UI library (WIP) for wallet connection management: [dot-connect](https://github.com/tien/dot-connect).
- Customisable UI solution out of the box.
- Designed to work alongside Reactive DOT.
- Wallets and accounts accessible via Reactive DOT hooks: [`useAccounts`](https://reactivedot.dev/api/react/function/useAccounts), [`useWallets`](https://reactivedot.dev/api/react/function/useWallets), and [`useConnectedWallets`](https://reactivedot.dev/api/react/function/useConnectedWallets).
- Built using [Web Component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) technology, making it framework-agnostic.
- **[Account management](https://reactivedot.dev/docs/getting-started/connect-wallets#display-available-accounts):**
- Dynamic retrieval from all connected wallets.
- Multichain support with automatic filtering based on the chain each account can submit transactions to.
- Unique signer attached to each account, supporting multiple sources and allowing signer selection for transactions.
- **[Utility](https://reactivedot.dev/docs/getting-started/number-utility) to handle planck units:**
- Compatible with native number locale string conversion.
- Uses monadic transformation for arithmetic, supporting both `BigInt` and `Number`.
### Summary of achievements
Reactive DOT now provides all the essential building blocks for developing a Substrate DApp, with walkthroughs guiding developers on:
- Connecting wallets.
- Displaying connected accounts.
- Reading states from the chain.
- Submitting transactions.
This is achieved with complete type safety, autocompletion from TypeScript, centralised async/error handling (set once and forget), and behind-the-scenes caching, de-duplication, and persistence management.
#### Demonstration
The following tutorial demonstrates how quickly a simple DApp can be set up. The DApp will:
- Have a UI dialog for managing wallet connections from injected wallets (extensions) and WalletConnect wallets (mobile).
- Display all accounts' free balances.
- Include a button to submit a simple remark extrinsic.
##### Install dependencies and sync metadata
```sh
yarn add @reactive-dot/react dot-connect polkadot-api
npx papi add dot -n polkadot
npx papi
```
##### Configure chains and wallets
```ts
import type { polkadot } from "@polkadot-api/descriptors";
declare module "@reactive-dot/core" {
export interface Chains {
polkadot: typeof polkadot;
}
}
const config: Config = {
chains: {
polkadot: {
descriptor: polkadot,
provider: WebSocketProvider("wss://polkadot-rpc.publicnode.com"),
},
},
wallets: [
new InjectedWalletAggregator(),
new WalletConnect({
projectId: "WALLET_CONNECT_PROJECT_ID",
providerOptions: {
metadata: {
name: "APP_NAME",
description: "APP_DESCRIPTION",
url: "APP_URL",
icons: ["APP_ICON"],
},
},
chainIds: ["polkadot:91b171bb158e2d3848fa23a9f1c25182"],
}),
],
};
export default config;
```
##### Add top-level context providers
```tsx
// Register dot-connect custom elements and configure supported wallets
// this is the companion UI library for managing wallet connections
registerDotConnect({
wallets: config.wallets,
});
function App() {
return (
<ReDotProvider config={config}>
<ReDotChainProvider chainId="polkadot">
<ErrorBoundary
fallbackRender={() => (
<article>
<p>Sorry, something went wrong!</p>
</article>
)}
>
<Suspense fallback={<progress />}>
<DApp />
</Suspense>
</ErrorBoundary>
</ReDotChainProvider>
</ReDotProvider>
);
}
```
##### Implement DApp logic
```tsx
function FreeBalance(props: { address: string }) {
const chainSpec = useChainSpecData();
const {
data: { free },
} = useLazyLoadQuery((builder) =>
builder.readStorage("System", "Account", [props.address]),
);
const freeBalance = new DenominatedNumber(
free,
chainSpec.properties.tokenDecimals,
chainSpec.properties.tokenSymbol,
);
return (
<div>
{props.address}: {freeBalance.toLocaleString()}
</div>
);
}
function Remark() {
const accounts = useAccounts();
const [selectedAccountIndex, setSelectedAccountIndex] = useState(0);
const selectedAccount = accounts.at(selectedAccountIndex);
const [remarkState, remark] = useMutation(
(tx) =>
tx.System.remark({ remark: Binary.fromText("Hello from reactive-dot!") }),
{ signer: selectedAccount.signer },
);
return (
<section>
<select
onChange={(event) =>
setSelectedAccountIndex(Number(event.target.value))
}
>
{accounts.map((account, index) => (
<option key={index} value={index}>
{account.address}
</option>
))}
</select>
<button onClick={() => remark()} disabled={remarkState === PENDING}>
Hello{remarkState === PENDING ? "..." : ""}
</button>
</section>
);
}
function DApp() {
const accounts = useAccounts();
return (
<div>
{/* Button for managing wallet connection from `dot-connect` */}
{/* it will pop up a modal for you to connect and disconnect wallets */}
<dc-connection-button />
{accounts.map((account, index) => (
<FreeBalance key={index} address={account.address} />
))}
{accounts.length > 0 and <Remark />}
</div>
);
}
```
##### Walkthrough recap
Achieving the same outcome without this library would require substantially more code, while being much harder to maintain and reason with.
## Next steps
This proposal requests continued funding for Reactive DOT development, focusing on:
### Refining existing features
- More documentation.
- Improvements and optimisations based on user feedback.
- Increased testing and refactoring to maintain development velocity and smooth integration of future features.
- Implementation of an automated versioning and publishing strategy.
### Adding new features
#### React 19 support
React 19 will introduce the [`use`](https://react.dev/reference/react/use) API, enabling components to conditionally consume promise results. Reactive DOT currently lazy loads queries (`fetch-on-render`) and will need to expose a promise-centric API to fully utilise React 19 features.
#### Additional framework support
The library's goal is to support building Substrate front-ends beyond just React. Based on the latest [State of JavaScript](https://2023.stateofjs.com/en-US) figures, the next frameworks for support, in order of importance, are:
1. Vue
2. Angular
3. Svelte
Existing work has accounted for this by splitting primitives and functionalities into [`@reactive-dot/core`](https://reactivedot.dev/api/core) and [`@reactive-dot/react`](https://reactivedot.dev/api/react) to prepare for future integrations.
#### Research on server-side rendering (SSR)
Server-side rendering (SSR) is increasingly important, with applications like [Polkassembly](https://polkassembly.io/) and [SubSquare](https://www.subsquare.io/) both built using [Next.js](https://nextjs.org/). However, SSR traditionally presents challenges for Substrate DApps, which rely heavily on live WebSocket data. Potential strategies include:
- Fully opt-in SSR: Faster initial load (`render-as-you-fetch`) but static values.
- Client-side Substrate requests: Live data but potential request waterfalls due to the `fetch-on-render` pattern.
![image](https://hackmd.io/_uploads/HyGl9wzIC.png)
A hybrid approach is proposed, fetching initial values server-side to hydrate the client cache, which then updates with live chain data:
```tsx
async function ServerComponent() {
const preparedQuery = await prepareQuery((builder) =>
builder
.readStorage("SomePallet", "SomeStorage")
.readStorage("SomeOtherPallet", "SomeOtherStorage"),
);
return <ClientComponent query={preparedQuery} />;
}
```
```tsx
"use client";
function ClientComponent(props: { query: PreparedQuery }) {
const resultThatIsInstantAndLive = usePreparedQuery(props.query);
// ...
}
```
Note: The above example illustrates the internal workings of the idea. Ideally, a logic split isn't explicitly required by developers.
#### Community-driven features
In addition to the concrete goals above, feedback is welcomed to determine the focus of future work.
## Summary
#### Build upon
- Maintenance.
- Improvements of existing features pending feedback.
#### Expand upon
- React 19 support.
- Support for additional frameworks, starting with Vue.
- Research and development into hybrid SSR and client updates.
- Features requested by the community.
Fuelled by positive feedback and a clearly defined path forward, I am confident that we can not only match but surpass the frontend developer experience of other ecosystems (i.e. EVM), setting a new industry standard.
## Timeline and budget
The initial [proposal](https://polkadot.polkassembly.io/referenda/812) requested funding for 2 months, which proved inadequate as a buffer due to the proposal process itself taking 1-2 months to conclude. During this time, I continued working without knowing the outcome. Based on that experience, I am now requesting a budget for 4 months, enabling me to fully dedicate my attention to research and development.
- Period: August to November 2024.
- Duration: 4 months / 87 workdays / 696 hours.
- Requested amount: 15,378 DOT (based on Subscan's [EMA7](https://polkadot.subscan.io/tools/charts?type=price) of $6.11 USD per DOT).
- Estimated rate: ~22.09 DOT or ~$134.96 USD per hour.