Building upon #812, #948, #1334, and #1477, this proposal requests funding for the continuation of ReactiveDOT, along with its related projects: DOTConsole and DOTConnect.
ReactiveDOT is a library designed to:
As of now, ReactiveDOT provides what is arguably the best-in-class front-end API for smart contracts in any ecosystem.
Improves perceived latency for large multi-queries by enabling partial results to stream in incrementally.
Maintained high test coverage across the codebase.
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
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.
Further research will be conducted to determine whether this direction remains viable or if a different approach should be pursued.
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.
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,
);
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 */
},
},
});
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.
Further enhancements will be guided by community feedback or requirements identified to support the ongoing testing and development of ReactiveDOT.
Threshold
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?