Kernel Core Contracts
The kernel components are responsible for managing the unified state and executing essential logic. The components on the hub are:- Kernel Manager (control plane): The entrypoint for intents. It checks permissions, routes calls and emits tasks (including reverts).
- Kernel Logic/State (data plane): This contains your app’s storage and core math.
- Shared infra: This includes a mailbox/registry for executors and endpoints.

Kernel Diagram
Bytes-first messaging
All cross-boundary payloads arebytes. Each app defines its own encoding and math.
Cross-VM addresses as bytes32
- Ethereum/EVM: 20 bytes left-padded to 32.
- Solana (SVM): base58 pubkey decoded to 32 bytes.
- Sui/Aptos (Move): already 32 bytes; store as-is.
bytes32.
Settlement, failure, refunds
- Success: task targets a specific
destChainIdanddestVmType; periphery gateway verifies and settles from staged funds. - Failure (correct): kernel emits a revert task back to the source periphery. That periphery runs the app’s refund logic for that action only.
- Idempotent: both settlement and revert must be safe to replay and must reject duplicates by
actionId.
Action identity and chain ids
- Action ID: unique per origin chain, computed as a hash of
(actionCount || chainId). - Chain ids (wrappers used for SVM/Move where needed):
CHAIN enum
How any app uses this
- Periphery: stage assets (if any), pack action bytes, emit events.
- Kernel manager: validate, call core logic, emit task(s) with the right
destChainId. - Core logic/state: keep all app state on the hub.
- Periphery gateway: verify task, settle or refund only that action.
Kernel Composition
Here’s how the kernel fits together. It links user wallets across chains, accepts signed intents from apps, emits tasks for off-chain executors, and tracks settlement.What each contract does
- AccountRegistry: Binds a user’s wallets across VM types (EVM and non-EVM) into one account.
- MessageBox: Validates an intent, prevents duplicates, emits tasks, and marks them as settled.
- SkateApp (base): App scaffold. Runs app logic, returns tasks, and hands them to MessageBox.
How they work together
- The relayer registers VM types and maps chain IDs.
- A user links wallets. EVM signatures are checked on-chain. Non-EVM is recorded for off-chain checks.
- The user signs an intent. The app calls
processIntent. - App logic returns
Task[].MessageBoxverifies the intent and emitsTaskSubmittedevents. - Executors pick up tasks and execute on the target chain(s).
- The relayer calls
setTaskAsExecutedto mark completion.
AccountRegistry
AccountRegistry
Goal: Keep one account number per user across VMs.What it stores:
- VM list:
vm[vmType]andvmCount. - Chain → VM type:
chainIdToVmType. - Wallet → account:
references[keccak256(vmType, wallet)]. - Account → wallets:
accounts[accountNumber](array of{vmType, addr}). - Admin:
_relayer.
initialize(relayer): sets the relayer and seeds VM type 1 as “EVM”.registerVm(name): add a VM type (relayer only).setVmTypesToChainIds(vmTypes[], chainIds[]): map chains (relayer only).bindWallet(vmType1, wallet1, vmType2, wallet2, sig1, sig2):- VM types must be registered and in increasing order.
- If
vmType1 == 1,sig1must recover towallet1using the bind hash. - If both wallets are new → create a new account and attach both.
- If one is already bound → attach the other to the same account.
- If both are already bound (to anything) → reject (no merging two existing accounts).
getWallets, getWalletBindingStatus, getAccountNumber, getVmTypeByChainId, getVmCount.Signature preimage (EVM binding):
getBindEVMHash(wallet1, vmType2, wallet2) encodes (0, wallet1, vmType2, wallet2) and uses the standard Ethereum signed message prefix.Permissions:- Owner: upgrades, set relayer.
- Relayer: VM admin + wallet binding entrypoint.
MessageBox
MessageBox
Goal: Be the outbox everyone trusts. Validate once. Emit tasks once. Mark settlement once.What it stores:
_executorRegistry: who can originate task submissions (tx.originis checked)._relayer: marks settlement._taskId: running counter._isTaskExecuted[taskId]: settlement flag._isActionExecuted[chainId][actionId] → taskId: global dedup index._nonce[user]: per-user nonces for replay protection.
submitTasks(tasks, intent):- Caller must be the app:
msg.sender == intent.intentData.appAddress. tx.originmust be an approved executor.intent.vmTypemust be non-zero.- If EVM (
vmType == 1) andintent.signatureis present:- Recover signer from
keccak256( user, nonce[user], appAddress, keccak256(intentCalldata) )with the Ethereum signed message prefix. - Signer must equal
user.
- Recover signer from
- Non-EVM signatures: emitted as an event for off-chain checks.
- Increments the user nonce after checks.
- Dedup rule: for each
(srcChainId, actionId), ensure it wasn’t executed before. Duplicates inside the same batch are allowed and skip the history check. - Emits one
TaskSubmittedper task and recordsactionId → taskId.
- Caller must be the app:
setTaskAsExecuted(taskId, settlementInfo):- Relayer marks a task as executed. Emits
TaskExecuted.
- Relayer marks a task as executed. Emits
executorRegistry, taskId, isTaskExecuted(taskId), isActionExecuted(chainId, actionId), nonce(user), getDataHashForUser(...).Why it’s safe:
App-only submission, executor allow-list, per-user nonce, and (chainId, actionId) dedup keep intents honest and idempotent.SkateApp (abstract base)
SkateApp (abstract base)
Goal: Make writing apps simple. You focus on building tasks; the kernel handles the rest.What it stores:
_messageBoxand_accountRegistry._chainIdToPeripheryContract[chainId] → bytes32._chainIds[]for discovery.
__SkateApp_init(messageBox, accountRegistry): wire dependencies.setChainToPeripheryContract(chainId, peripheryContract):- Set or clear the periphery address for a chain.
- Keeps
_chainIdsin sync.
processIntent(intent):- Calls
address(this).functionCall(intent.intentData.intentCalldata). - Expects your function to return
IMessageBox.Task[]. - Submits those tasks to
MessageBox.
- Calls
onlyContract modifier is available for internal orchestration.Lookups: chainIdToPeripheryContract, messageBox, accountRegistry, getChainIds.Roles
- Owner (per contract): Upgrades and wiring.
- Relayer: Registry admin; marks settlement in MessageBox.
- Executor (EOA): Must be whitelisted; originates task submissions.
- App contract: Must be the direct caller of
submitTasks.