To build a flying car that actually flies:
-
Make sure that the car is drivable at all times.
-
Ensure that the modularity inspires maintainable reusability.
-
Meditate.
Use node version ^18.12
- Install dependencies
pnpm install
- Refresh known Schains
pnpm compile:chains- Run DApp locally
pnpm dev:app- Or, Build for production
pnpm build:appBuild output goes to app/dist, from where it can be deployed to any static host.
This repo follows a lite microfrontend architecture, which means there will be parallels in design decisions, but not a zealous overlap. On further reviews, if enough antipatterns are found, a suitable name for this architecture should be meshfrontend.
The aim is to strike a balance between:
- Re-usability of features by ecosystem projects
- Maintainable contributions from across communities
For re-usability across the ecosystem, following is distinctly made available from the repository.
๐ฆ Intuitive react hook libraries integrated with SKALE Network - @skalenetwork/feat
๐ฎ UI compositions including various flows for Schain management - @skalenetwork/admin-ui/screens
๐งฑ Reusable common components following SKALE's design system, built with headless accessible libraries - @skalenetwork/ux/components
๐ง JSX UI Elements with some context dependency - @skalenetwork/ux/elements
๐ฅฝ Well-typed interfaces exported alongside relevant modules
๐ Package exports can currently only be imported as TS, and require necessary aliasing in
tsconfig, and in js bundling. Example with vite+TS can be found in/app
SKALE Network capabilities are divided into features by usability domains.
All features require wagmi + react-query context, exporting:
- TypeScript utility functions
- React TS hooks
Current features include:
- network (primitives)
- control
- analytics
- bridge (token bridging)
- icm (interchain messaging)
- multisig
- storage
Following is a breakdown of the foundational feature.
@/features/network
Network feature offers extensive support for network building blocks, such as SKALE pre-deployed contracts.
All transactional operations are integrated with SKALE access control.
- Use typed contracts
- Use utility APIs on top of contracts
- Use convenience hooks
Network feature is based on a configuration layer.
๐ Configuration layer is independently scalable. It employs the least common format, which can be versioned, and extended to match change in the network complexity.
None-to-slow-changing data
address.tsAll unique preset addresseschains/*.tsRecognized SChains using a standardChaintype, IDed bychainName.
Slow-to-medium-changing data
Manifests cater to contracts, ABIs, and wrapper APIs.
๐ Manifests can best evolve to become compile-targets of releases made within
skalenetwork/*. Following that, they may become a standalone distribution.
-
manifest.tsRe-export of manifests and utility methods -
contract.tsEntry point of following manifests, indexing pre-deployed and other known network contracts withContractId -
abi/abi.tsRe-export of individual ABIsabi/abi-*.ts, indexed byContractId -
api.tsRe-export of standard initiators for individual APIs imported from various ecosystem libraries, indexed byContractId
Why redistribute JSON ABIs as .ts files? We need the narrowest
Abitype, producible by aconstassertion. TS currently doesn't (want to) support JSONas constmicrosoft/TypeScript#32063
Example usage of exposed getters:
const address = getSContractProp('CONFIG_CONTROLLER', 'address');
const abi = getAbi('CONFIG_CONTROLLER');
// and reverse
const contractId = build.contractIdFromAddress(address);
const { abi, address } = build.addressAbiPair(contractId);Medium-to-fast changing data
Registry is a loose implementation around the idea of registering off-chain / near-chain metadata within a module.
Presently registered metadata includes:
- chainlists
skale-network:metadata/mainnet/chains.jsonadmin-ui:metadata/roles.json
It may help to think of screens as portals to stateful features.
Screens are composed of UI widgets linked to UI flows that execute operations on SChain.
They are like pages served in any frontend; Except, all screens are exported independent of each other, and usable in any DApp.
pnpm install -P @skalenetwork/featAll react hooks are operational only within wagmi context.
/** in your entrypoint file **/
// within main renderer
<WagmiConfig client={wagmiClient}>
<App />
</WagmiConfig>Refer to wagmi docs for complete setup example.
Read a single value from a pre-deployed contract
const { data } = useSContractRead('TOKEN_MANAGER_ERC20', {
name: 'automaticDeploy',
});Read multiple values from a pre-deployed contract
// multi-read fits best with TS for similarly typed return values
const { data, status, refetch } = useSContractReads('CONFIG_CONTROLLER', {
reads: [
{
name: 'isMTMEnabled',
},
{
name: 'isFCDEnabled',
},
],
});Write to a pre-deployed contract
import { useSContractWrite } from '@skalenetwork/admin-ui/features';
const writer = useSContractWrite('TOKEN_MANAGER_LINKER', {
name: 'connectSChain',
args: ['staging-aware-chief-gianfar'],
});handle with side effects
const { isLoading, isSuccess, isConfirmed, receipt } = writer;
useEffect(() => {
// when confirmed
}, [receipt]);
const handleSubmit = useCallback(() => {
writer?.write();
}. [writer.write]);handle with promises
const handleSubmitWithConfirm = useCallback(async () => {
if (!writer.writeAsync) return;
const receipt = await writer.writeAsync(true);
}, [writer.writeAsync]);What else is in the writer?
writer exposes status of the contract mutation through its lifecycle.
- from
idle - through
loading - to
successorerror - back to
idleif auto or manuallyreset()
const { eoa, mnm, ...rest } = writer;-
eoawriter where Externally Owned Account (EOA) is signer -
mnmwriter where EOA is owner ofMultiSig, and submits a transaction that is routed throughMarionette -
restis copy of eithereoaormnm, whichever is authorized, where precedence is given toeoa
writer.writeAsync or writer.write execute an already prepared transaction. These methods will only be available if:
argsare passed as expected intouseSContractWriteoptions- there are no authorization exceptions
- there are no
requirefailures in method call
๐ SKALE Contract writer hook performs eager validation on destination method call. This validation works as expected in case of EOA-signed transactions.
โ๏ธ Learn more about underlying contract call preparation done bywagmi.
โ ๏ธ The eager validation may cause wallet injected scripts to log errors pre-emptively in console. Example:MetaMask - RPC Error
Both writers extend the return data of wagmi.useContractWrite, with more state values.
const { action, multisigData, receipt, isConfirmed, isFailed } = rest;
const natureOfDestinationContractCallThroughMariontteViaMultisig = {
isConfirmExistingIdenticalTx: action === 'confirm',
isExecuteExistingIdenticalTx: action === 'execute',
isSubmitNewTx: action === 'submit',
};
const countMultisigConfirmations = multisigData?.countConfirmed;
const countMultisigRequiredConfirmations = multisigData?.countRequired;Guard UI actions from unready writer
<button disabled={!!writer.writeAsync}>Guarded Action</button>Guard and guide action with a well-formatted button using SButton element from @skalenetwork/ux/elements
<SButton writer={writer}>Guarded Action</SButton>Preview a guarded action button without writer execution on click
// usage as a preview that opens a separate flow
<SButton writer={writer} noWrite onClick={(e) => openModal()}>
Open Modal
</SButton>@/features/icm
Among features, ICM (inter-chain messaging) is a domain that would horizontally complete @/features.
Diagram highlighting typical cross-chain interaction. On the contrary, arbitrary message passing is more suitable for icm whereas multsig could be one of the consumers of icm when supporting foreign multisigs.

