An attested uptime registry for DePIN networks, built on the Attestcoin Protocol.
DePIN networks (decentralized physical infrastructure; sensor networks, node operators, hardware providers) have a trust problem: most reward systems just trust whatever a node self reports about its uptime. Nothing stops an operator from lying to farm rewards.
Pyro fixes this by requiring every uptime claim to be backed by a real, cryptographically verified cross-chain transaction — not a self-report.
Node sends real tx on Ethereum Sepolia
|
v
Attestcoin Protocol verifies inclusion (Block Prover Precompile, one block, ~15s)
|
v
UptimeRegistry on Creditcoin credits verified uptime
|
v
A node that only self-reports (no real tx) gets flagged automatically
|
v
RewardGate reads that verified state and decides real reward-pool eligibility
DePIN reward systems (Helium, IoTeX, and most others) rely on nodes self-reporting liveness to a centralized or semi-trusted backend. A node operator who wants to farm rewards without actually running real infrastructure just... reports good numbers. There is no trustless way to tell the difference between a node that is actually online and one that is lying, without a centralized auditor.
Pyro requires every uptime claim to be backed by a real transaction on a source chain (Ethereum Sepolia), verified through Creditcoin's Attestcoin Protocol before it counts toward a node's score.
- A node proves liveness by sending a transaction to
HeartbeatBeaconon Sepolia, a real, mined transaction, not a signed message or an API call. - An off-chain worker waits for Creditcoin to attest the block containing that transaction, then fetches a real inclusion proof from Attestcoin's proof service.
- The proof is submitted to
UptimeRegistry, an Attestcoin Smart Contract (ASC) on Creditcoin. The contract calls the Block Prover Precompile to verify the proof in the same transaction synchronous, one block, no async waiting, no oracle, no bridge. - Only after verification succeeds does the node's
verifiedHeartbeatscount increase. - Nodes can also self-report claims (
reportClaimedHeartbeat) with no proof required this exists specifically so the contract can compare claimed vs. verified and flag nodes whose claims outpace their proof (isSuspicious()). RewardGate, a separate additive contract, reads that verified state and answers the question a score alone doesn't: whether a node actually qualifies for a reward pool. It's read-only and gets nothing set directly — eligibility only ever follows fromUptimeRegistry's real verified counters.
This has been proven end-to-end on live testnets, not just designed on paper see Proof it works, below.
This is the core of the project, not a bolted-on feature.
- Source chain: Ethereum Sepolia (
chainKey = 1on Creditcoin CC3 Testnet) - Verification path:
UptimeRegistry.recordHeartbeat()callsINativeQueryVerifier.verifyAndEmit()against the Block Prover Precompile (0x0000000000000000000000000000000000000FD2), synchronously, in the same transaction as the business logic that updates the score. - Why this matters: the verification and the state change happen atomically. There is no window where a proof is "pending" — either the transaction proves inclusion and updates the score, or it reverts.
- Replay protection: every verified transaction is hashed
(
chainKey + blockHeight + encodedTransaction) and recorded inprocessedQueries, so the same Sepolia transaction can never be double-counted. - Event decoding: the contract uses
EvmV1Decoder(from@gluwa/usc-contracts) to extract theHeartbeatevent'snodeIdandtimestampdirectly from the verified transaction's logs, and confirms the log actually originated from our knownHeartbeatBeaconaddress — not just any transaction, the right transaction. - Off-chain proof generation: the worker (
worker/src/worker.ts,worker/src/process-heartbeat.ts) uses@gluwa/usc-sdk'sProofBuilderto wait for attestation and fetch the real Merkle + continuity proof, exactly as documented in Creditcoin's SDK reference.worker.tsis built for unattended, long-running operation — crash-resume state, retry with backoff, graceful shutdown — seeTECH.mdfor detail.
Full technical detail: TECH.md (contract-by-contract
breakdown, gas notes, and design decisions).
These are real, live, currently-verifiable transactions — not staged for this README.
| What | Transaction |
|---|---|
| Node heartbeat on Sepolia | 0x22ca8f05...48a3f943 |
| Same heartbeat, verified on Creditcoin | 0x028f62cf...59444673f |
A node that self-reported 3 claims with zero real Sepolia transactions
behind them was correctly flagged: isSuspicious(99) returns true,
verifiedHeartbeats: 0, claimedHeartbeats: 3 — all on-chain, no manual
intervention.
RewardGate was checked against both real cases: isEligible(1) returns
true (a genuinely verified node), isEligible(99) returns false (the
flagged one) — a concrete, ungameable eligibility decision, not a UI label.
| Contract | Network | Address |
|---|---|---|
HeartbeatBeacon |
Ethereum Sepolia | 0xD3A97BcE1b0964e2959a08d37EE7F3A030CAED4c |
UptimeRegistry (ASC) |
Creditcoin CC3 Testnet | 0xa32659ec3c61E84adceF44cA34AD075949acAC97 |
RewardGate |
Creditcoin CC3 Testnet | 0xa2c082140723E4436F5538761D6F765Cc1004401 |
(pyrocc3.vercel.app) reads live on-chain state, no mock data.
contracts-sepolia/ HeartbeatBeacon.sol; the liveness ping nodes send
contracts-creditcoin/ UptimeRegistry.sol (the ASC) + RewardGate.sol (reward eligibility)
worker/ Off-chain proof pipeline — worker.ts (hardened, continuous) and process-heartbeat.ts (one-shot demo script)
simulator/ Simulates a small fleet of nodes, incl. a "liar" node
pyrodashboard/ Live control-room UI reading real on-chain state
Each subfolder has its own README/SETUP with exact steps. Short version:
# 1. Deploy the beacon (Sepolia)
cd contracts-sepolia && npm install && npx hardhat run scripts/deploy.js --network sepolia
# 2. Deploy the registry (Creditcoin) — auto-picks up the beacon address
cd ..\contracts-creditcoin && npm install && npx hardhat run scripts/deploy.js --network creditcoin_testnet
# 3. Deploy RewardGate auto-picks up the registry address
npx hardhat run scripts/deploy-reward-gate.js --network creditcoin_testnet
# 4. Send a real heartbeat
cd ..\contracts-sepolia && npx hardhat run scripts/pulse.js --network sepolia
# 5. Process it through Attestcoin
cd ..\worker && npm install && npx ts-node src/process-heartbeat.ts <tx-hash-from-step-4>
# 6. View it live
cd ..\pyrodashboard && npm install && npm run devDePIN's core unsolved problem ; proving a node is real and online without a centralized auditor —is exactly the shape of problem Attestcoin's cross-chain verification is built for. Most projects in this space bolt attestation onto a broader product; Pyro is deliberately narrow: one hard trust problem, solved with real cryptographic verification, proven live end-to-end on testnet.
Original work, built for this hackathon. Not a reuse of any prior project.