Skip to main content
For machines homed on peaq, peaq stays canonical. Satellite run a thin, read-only mirror of peaq’s Tokenomics 1.0 records (IdentityRegistry, IdentityStaking and the DID precompile), kept in sync by a Signer Daemon that watches finalized peaq events, packages them into EIP-712 batches, them with a per-chain push key, and pushes them to satellite Lite contracts. A machine homed on Solana is not mirrored this way: its identity, DID document and NFT are Solana accounts (see Economics 2.0: cross-chain relocation). Two things this page does not cover. Economics 2.0 relocates whole machine records between registered chains through MachineBridgeAdapter and CrossChainMirror over LayerZero V2; that mechanism is switched off on chain today and the SDKs expose status reads only. And the 1.0 Machine NFT bridge (peaq ↔ Base; the Solana lane is closed) is on the Machine NFT page. This means a or app on a satellite chain can resolve a Tokenomics 1.0 machine’s , identity and status (satellites carry no mirror, see Qualify) without an hop to peaq. The satellites today are agung (mirroring peaq mainnet) and Sepolia (mirroring agung); there is no Lite deployment on Base mainnet, Ethereum or Polygon. A read trusts the Signer Daemon’s push key to have pushed peaq state faithfully.

What the mesh looks like

Domain separator: name = "PeaqosLite", version = "1.0.0". Each Lite is identified by (chainId, verifyingContract) per EIP-712.

DIDLite

DIDLite mirrors the peaq DID ’s per-attribute records onto every satellite chain. Consumers on the satellite resolve any peaq DID account’s attributes (including the locked "peaqID" attribute) without an extra hop. Records are written exclusively by signed batches from the Signer Daemon; consumers only read.

Public consumer views

readAttribute LiteIsPaused() while the Lite is paused. readAttributeRaw is an admin/debug carve-out that ignores the gate. lastHomeBlockApplied() is intentionally not pause-gated so consumers can still read the global watermark when reads are paused. To resolve a peaqID, compose: readAttribute(didAccount, "peaqID"). The orchestrator does not ship a dedicated peaqIDOf view; clients decode the 32-byte value themselves.

Consumer view errors

  • AttributeNotFound(address didAccount, bytes attrName)
  • AttributeRemoved(address didAccount, bytes attrName, uint64 removedAtHomeBlock)
  • LiteIsPaused()

IdentityLite

IdentityLite mirrors the peaq IdentityRegistry per-machineId record. Consumers gate writes that depend on having seen a specific peaq approval by reading lastCursorPacked().

Public consumer views

Consumer view errors

  • MachineNotFound(uint256 machineId)
  • LiteUninitialized(address lite): not raised by the Lite itself. Read the public lastBatchAcceptedAt() and require(lastAt > 0, LiteUninitialized(address(this))).
  • LiteIsPaused()

Cold-start pattern

A Lite that has never accepted a batch holds no records, so getIdentity reverts MachineNotFound on a fresh Lite just as it does for an unknown machine. Read the public lastBatchAcceptedAt() first when you need to tell the two apart:

StakingLite

StakingLite mirrors the peaq IdentityStaking per-machine stake record. Consumers gate authorisation or service eligibility on stake state without crossing chains.

Public consumer views

Same cold-start pattern as IdentityLite: getStake and getStakeRaw revert MachineNotFound for an absent stake record, including on a fresh Lite, and isStaked and totalStaked return no timestamp. Read lastBatchAcceptedAt() and require(lastAt > 0, LiteUninitialized(address(this))) before trusting reads. StakingLite has its own pause flag and its own EIP-712 schema (StakingEvent), but shares the PeaqosLite domain and the cross-language daemon parity gate.

EIP-712 schemas

7-field IdentityEvent

txIndex and logIndex make the on-chain cursor sub-block-precise. The daemon-side encoder is bit-identical to Solidity (parity-gated by the EIP-712 fixture suite).

DIDEvent

Both bytes fields are pre-hashed with keccak256(bytes(...)) per EIP-712 dynamic-bytes rule. kind ordinal: 0 = Add, 1 = Update, 2 = Remove. Removes must carry value.length == 0 and validity == 0.

Batch envelope (shared)

Schema version is per-Lite. A typehash bump requires lockstep upgrade of both the Lite and the daemon.

Signer Daemon

Off-chain. Python package, one instance per (home, satellite, Lite) triple. The fleet is six daemons across two pipelines: three for peaq (home) → Agung (satellite) and three for Agung (home) → Base Sepolia (satellite). Each daemon binds to one LITE_NAME (IdentityLite | DIDLite | StakingLite), one push key (currentSigner on the Lite), one HEALTH_PORT, and one CURSOR_FILE_PATH. Six unique push keys total: reuse triggers nonce races.

Health endpoint

Each daemon exposes a loopback-only /health (default port unique per instance, conventionally 8080–8085):

Pause and emergency model

Every Lite has two independent pause flags and one emergency flag, all external onlyOwner:
Routine setSigner rotation opens a GRACE_BLOCKS = 600 (~1h) window where the previous PUSH_KEY remains valid so in-flight signed batches do not fail mid-flight. Emergency rotation does not keep the previous key valid.

EmergencyMode

EmergencyMode is one boolean plus a snapshot , not an enum, next to the two pause booleans:
A first pauseLite or pauseApplyBatch sets inEmergencyMode = true and snapshots emergencyEnteredBySigner = currentSigner. To exit, the owner calls emergencyRotatePushKey(newKey) (rotation must actually change the signer) then exitEmergencyMode(). Pause flags are not auto-cleared.

Hot/cold key collapse defense

The cold key is owner() (admin and upgrade authority). The hot key is currentSigner (the PUSH_KEY on the daemon server). A single must never collapse them onto the same address. Enforcement points:
  • initialize(owner_, pushKey_) reverts if pushKey_ == owner_.
  • setSigner(newSigner) reverts if newSigner ∈ {owner(), pendingOwner()}.
  • emergencyRotatePushKey(newPushKey) reverts on the same membership check.
  • transferOwnership / _transferOwnership reject newOwner ∈ {currentSigner, previousSigner}.
  • renounceOwnership is permanently disabled.
A stolen daemon key cannot also seize upgrade authority.

Staleness policy

The Lite does not staleness-revert, and the SDKs do not wrap it. Compare lastBatchAcceptedAt to block.timestamp and reject reads older than your own SLO. The Lite only blocks cold-start via the consumer-side sentinel pattern.

Soft delete (DIDLite)

Removed DID attributes stay in storage with removed = true and value = "". readAttribute reverts AttributeRemoved(...) for these. readAttributeRaw returns them as-is for admin/debug.

What an integrator does

The Lites carry Tokenomics 1.0 records only: machineId is the IdentityRegistry ID and didAccount is the address behind a did:peaq:<0x-address> DID. An Economics 2.0 machine ID has no record on them.
  1. Resolve a peaqID on a satellite chain. Call readAttribute(didAccount, "peaqID") and decode the returned bytes as a bytes32. A fresh Lite reverts AttributeNotFound; read lastBatchAcceptedAt() first if you need to tell a cold Lite from a missing attribute.
  2. Read identity status. getIdentity(machineId) returns the full record. Same cold-start check. Or use the granular home-style getters: getOwnerIfExists, operatorOf, getMachineStatus, getMachineURI.
  3. Read stake state. StakingLite.getStake(machineId), isStaked(machineId), isAuthorized(wallet), or totalStaked().
  4. Gate on a specific peaq approval. Read IdentityLite.lastCursorPacked() >= myExpectedCursor before letting a satellite action depend on it. Use the unpaused lastCursor() view if you need the unpacked form.
  5. Apply your own staleness SLO. Compare lastBatchAcceptedAt to block.timestamp. The Lite intentionally does not enforce one.

Solana

Solana is the first non-EVM chain peaqOS reaches, and the first chain besides peaq where an Economics 2.0 machine can live. The eleven Economics 2.0 programs are deployed on Solana mainnet-beta (addresses on Smart contracts). The Tokenomics 1.0 mirror programs (identity AWGibJPvQnj8mhfK8QWdUhvJBySCcwYadqAdtj2N137m, stake 4PyqZKtej7CWcV1jZ5h5FMd8EoR5edTTaZxAxEQmVDvs, DID attributes AMQgyqNcWSJy6cK2wSmXRykgjoPhSroKkjKtN8Y11WMc) and the address-binding program GrsCoPkeLUAoXjuwPfCcuch77Chco1Gx95zCCQNYGqG6 are closed on mainnet-beta: their program data no longer exists, so they cannot be called and receive no pushes. What is reachable today: The Economics 2.0 messages between peaq and Solana (reservation mirror, link push) travel over LayerZero. There is no peaqos solana command group: Solana is selected per command (peaqos activate --chain solana, peaqos stream pay --chain solana).

Addresses

The agung and Base Sepolia Lite proxy addresses are not published, and the released SDKs carry no satellite registry. Solana program IDs: Solana mainnet addresses.