Continue funding for ReactiveDOT & related developments
Building upon #812, #948, #1334, and #1477, this proposal requests funding for the continuation of ReactiveDOT, along with its related projects: DOTConsole and DOTConnect.
Project goals
ReactiveDOT 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.
Previously completed goals
Ink! contract support
As of now, ReactiveDOT provides what is arguably the best-in-class front-end API for smart contracts in any ecosystem.
- Announcement: https://x.com/TienNguyenK/status/1930861744391623006
- Pull request: https://github.com/tien/reactive-dot/pull/632
- Documentation: https://reactivedot.dev/react/guides/smart-contract
Incremental loading
Improves perceived latency for large multi-queries by enabling partial results to stream in incrementally.
- Pull request: https://github.com/tien/reactive-dot/pull/727
- Documentation: https://reactivedot.dev/react/guides/incremental-loading
≥ 90% test coverage
Maintained high test coverage across the codebase.
Miscellaneous contributions
Beyond my own projects, I contribute to various efforts in the Polkadot ecosystem whenever possible. You can see my recent activity here:
https://github.com/tien?tab=overview
In-progress
Query composition
Most of the current research has focused on enabling stable cached Promises within render logic to leverage native React 19 support for use
.
The goal is to allow developers to compose logic on top of these cached Promises.
Research findings so far:
- Creating stable Promises outside the React render cycle is too memory-expensive, as a new cache entry is required for every permutation of hook arguments.
- Creating stable cache entries within the render cycle is potentially feasible, but very complex. The cache must remain stable across multiple suspense cycles while also being weakly held (not strongly referenced), allowing it to be garbage collected.
Further research will be conducted to determine whether this direction remains viable or if a different approach should be pursued.
Planned works
Solidity-based contract support
In anticipation of the upcoming Polkadot Hub launch with PalletRevive, similar support for Ink! contracts will be extended to Solidity contracts that expose ABIs. The goal is to maintain a unified developer experience and API regardless of contract implementation.
Granular cache manipulation
As usage around smart contract grows, many interactions will become pull-based (as opposed to reactive storage push-based). As such, manual cache control becomes essential.
Proposed API:
const loader = useQueryLoader();
// Eagerly load queries into cache
loader.loadQuery((query) => query.runtimeApi(/* ... */));
// Refresh active queries
loader.refresh((query) => query.runtimeApi(/* ... */));
/**
* Mark queries as invalid:
* - New data will be fetched on the next render
* - If there's no active query, the cache will be removed
*/
loader.invalidate((query) => query.runtimeApi(/* ... */));
Additional filtering-based lookup will also be supported:
const queryLoader = useQueryLoader();
// Invalidate all queries, akin to a garbage collection cycle
loader.invalidate.all();
// Invalidate all balance-related caches
loader.refresh.all((entry) => entry.pallet === "Balances");
// Especially useful for smart contracts
loader.refresh.all(
(entry) =>
entry.instruction === "contract-read" &&
entry.address === SOME_CONTRACT_ADDRESS,
);
Auto-refresh/refetch for contract queries
Since all interactions are cached and serialized, ReactiveDOT can track all contract reads and provide configurable auto-refresh behavior:
import { contracts } from "@polkadot-api/descriptors";
const psp22 = defineContract({
descriptor: contracts.psp22,
// Refresh strategy can be:
autoRefresh: {
// After each mutation
postMutation: true,
// After every `x` blocks
everyBlockCount: 5,
// Potentially more advance strategies
inResponseToEvent: (event) => {
/* TBD */
},
},
});
Incremental loading for single query
Much like incremental loading for multi-queries, an escape hatch could be provided for single-query scenarios. While ReactiveDOT remains committed to a suspense-first design, careful consideration will be given as to whether and how this feature should be implemented.
Continued improvements to DOTConnect & DOTConsole
Further enhancements will be guided by community feedback or requirements identified to support the ongoing testing and development of ReactiveDOT.
Funding request
- Period: July 2025 – October 2025
- Duration: 4 months (89 workdays / 712 hours)
- Hourly rate: 125 USDC
- Total requested: 89,000 USDC
Comments (1)
Progress seems solid. Could you please mention some of the challenges you may have encountered during implementation and how you were able to resolve them?