Create block-tick and scheduled subscriptions using SDK
The @somnia-chain/reactivity TypeScript SDK can create on-chain subscriptions owned by an externally-owned account (EOA). This tutorial covers the two system event helpers:
scheduleSubscriptionAtBlock
scheduleSubscriptionAtTimestamp
Use these helpers when a wallet or backend should own and pay for an on-chain callback, while a Solidity handler contract receives the reactive transaction.
System events are synthetic logs emitted by the reactivity precompile at 0x0100.
Helper
System event
Behavior
scheduleSubscriptionAtBlock
BlockTick(uint64)
Every block if blockNumber is omitted, or once at the specified block.
scheduleSubscriptionAtTimestamp
Schedule(uint256)
Once, when block time first reaches the requested millisecond timestamp.
The handler contract must implement onEvent(address,bytes32[],bytes). The usual way to do that is to inherit from SomniaEventHandler, as shown in the Solidity on-chain tutorial.
This example uses Somnia Testnet. For mainnet, use the mainnet chain ID, currency and RPC URL from Network Info.
Step 2: Subscribe to Block Ticks
Omit blockNumber for a recurring every-block subscription. Use this carefully: it can invoke your handler every block until the subscription is removed. See the on-chain Reactivity development advice before using a recurring system-event subscription in production.
Pass blockNumber for a one-shot subscription to a specific future block:
Internally, the SDK sets:
emitter to the reactivity precompile address
eventTopics[0] to the BlockTick(uint64) selector
eventTopics[1] to the block number, or zero for every block
handlerFunctionSelector to ISomniaEventHandler.onEvent.selector when you omit it
Step 3: Schedule a One-Off Callback
scheduleSubscriptionAtTimestamp creates a one-shot Schedule(uint256) subscription. The timestamp is an absolute Unix timestamp in milliseconds.
The SDK returns an Error when timestampMs < Date.now() + 12_000, so schedule at least 12 seconds ahead. It does not throw for that validation path, so always check instanceof Error.
Full Script
Save this as cron.ts:
Run it:
Cancel from TypeScript
The SDK can also cancel subscriptions owned by the same wallet client. Pass the subscription ID, not the creation transaction hash:
Equivalent Solidity Helpers
If a Solidity contract owns the subscription, prefer SomniaExtensions from inside that contract instead of the TypeScript SDK. The snippets below assume options is a SomniaExtensions.SubscriptionOptions value.
One-shot block subscription:
One-shot timestamp subscription:
Recurring every-block subscription:
The scheduleSubscriptionAt* Solidity helpers are one-shot. For recurring every-block or every-epoch subscriptions, build the filter and call SomniaExtensions.subscribe directly.
// Any future block works. This example uses a small offset for easy testing.
uint256 subscriptionId = SomniaExtensions.scheduleSubscriptionAtBlock(
address(this),
uint64(block.number + 20),
options
);