LogoLogo
WalletsEcosystemStart BuildingJoin the Community
  • Welcome to IoTeX 2.0
    • 💡Why IoTeX
    • 🪙Tokenomics
      • IOTX Utility in IoTeX 2.0
      • IOTX Emission, Deflation, and Re-Staking
    • 📖Whitepaper
    • ⚡Get Started
  • DePIN Infra Modules (DIM)
    • DIMs Overview
    • [IoTeX L1] DePIN Blockchain
      • Core Concepts
        • Consensus Mechanism
        • Voters and Delegates
        • Ethereum Virtual Machine
        • Accounts & Identities
        • Blockchain Actions
        • ERC20 and NFT Tokens
        • Smart Contracts
        • Interoperability
        • Governance
      • The IOTX Token
        • IOTX Token Exchange Support
        • Different Formats of the IOTX Token
        • IOTX Token Contracts
      • Wallets
        • Supported Wallet Apps
          • ioPay Mobile
          • IoTeX Web Wallet
          • OKX Wallet
          • Rabby Wallet
          • Metamask Desktop
          • Ledger Nano S & X
            • Use Ledger with Metamask
            • Use Ledger with Rabby Walet
            • Use Ledger with IoTeX Hub Portal
            • Migrate to the Ethereum Ledger App
          • IoTeX Desktop Wallet
          • 👩‍💻IoTeX HD Derivation Path
        • Buy IOTX Tokens
        • Execute Transactions
          • Transfer IOTX Tokens
          • Transfer ERC20 Tokens
          • Interact with Dapps
          • Explore transactions
        • Migrate Assets to a different wallet
      • Staking & Governance
        • About IoTeX Staking
        • IoTeX Staking Guide
          • Native staking
          • Staking as NFT
        • Join the Governance
          • Marshall DAO
          • Improvement Proposals
      • Exchange Integration
      • 👨‍💻Deploy Dapps on IoTeX
    • [ioID] DePIN Identities
      • ioID Specification
      • Overview of ioID
      • Registering Identities
      • 👩‍💻Integration Guide
        • Register a DePIN Project
        • Bind your Device NFT
        • Reserve Device ioIDs
        • Query Project Status
        • Register a Device
        • ioID Smart contracts quick reference
    • [W3bstream] DePIN Verification
      • Overview of W3bstream
      • Multi-Prover Architecture
      • 👨‍💻Build with W3bstream
        • Get Started
          • Sequencer Options
        • Build the Prover Code
          • Risc Zero
          • Halo2
          • zkWASM
        • Deploy to W3bstream
          • Create the Project File
          • W3bstream Outputs
          • Deploying Projects
          • Interacting with Projects
        • On-chain integration
          • Verify Risc0 Proofs
          • Verify Halo2 Proofs
          • Verify zkWASM profs
        • Sending Messages
      • 👩‍💻Node Operators
        • Configure a ZK Prover Node
        • Register your Node
    • [ioID-SDK] Hardware SDK
      • ioID-SDK Overview
      • Layered Architecture
      • Compatibility
      • Current Development Status
    • [MSP] Modular Security Pool
    • Third-Party DIMs
      • Data Sequencer Infras
      • Data Availability Infras
      • 👨‍💻W3bstream Tasks
  • Ecosystem
    • Assets on IoTeX
      • Mainstream Assets
      • IOTX and Derivatives
      • DePIN Tokens
      • MEME Coins
    • iotube Bridge
    • iotexscan Explorer
    • Ecosystem Apps
      • DePINScan
      • mimo DEX
      • ecosystem.iotex.io
    • "Powered by IoTeX" Devices
      • Pebble Tracker
        • Quick Start
        • Device Registration
        • Online Firmware Update
        • USB Firmware Update
        • Migrating to Pebble v2.0
          • 1.0 Device Registration
        • Tech Specs
        • Network Selection
        • Pebble Configuration
        • Query Pebble Data
        • Troubleshooting
        • Firmware Development
          • Hardware Setup
          • Build the Firmware
          • Flash the firmware
      • SenseCAP Indicator
      • UCam Home Camera
  • Builders
    • IoTeX Developer Portal
    • Dev Chat on Discord
    • Web3 Development
      • RPC Endpoints
      • Set up your Environment
      • Get Testnet IOTX Tokens
      • ioctl CLI
        • Installation
        • Create Accounts
        • Blockchain interaction
          • ioctl command reference
      • Chain Indexing
        • The Graph
        • SubQuery
        • IoTeX Analytics API
      • IoTeXscan API
      • Deterministic Deployment
      • Account Abstraction
        • Components of AA
        • 👩‍💻Creating new Accounts
        • 👨‍💻P256Account Example
      • Blob Transactions (EIP-4844)
      • Multicall3
      • EVM Precompiled Contracts
    • Building DePINs
      • ioID Step by Step Tutorial
        • Integrate ioID in the Device Firmware
        • Integrate ioID in your cloud
      • Decentralized WiFi Connectivity (DeWi)
        • Project Specification
        • The choice of Hardware
        • The Data API Service
        • DePIN Incentives Contract
    • Building DeFi
      • Deploy Tokens
        • Deploy an ERC20 Token
        • Deploy an NFT Token
      • Price Oracles
        • Chainlink Relayer
        • SupraOracles
      • Integrate IoTeX Staking
      • Liquid staking Dapps
    • Launch Dapps on IoTeX
      • Submit Tokens to the IoTeX Ecosystem
      • Submit tokens to the iotube bridge
      • Verify Smart Contracts
      • Audit your Contracts
      • Submit your Dapp to Portals
      • Useful tools
    • Node Operators
      • Fastblocks (Node as a Service)
      • Setup an IoTeX RPC Node
      • Run a Delegate Node
      • Rosetta API
    • Reference Docs
      • ioctl client
        • Accounts
        • HD Wallets
        • Aliases
        • Actions
        • Queries
        • Smart Contracts
        • Staking & Voting
        • Tokens
        • ioID Identities
        • W3bstream
        • Decentralized Identifiers (DID)
        • JWT Auth Tokens
      • Native IoTeX Development
        • IoTeX gRPC API
        • Account Cryptography
        • Address Conversion
        • Create Accounts
        • Estimate Gas Price
        • Make IOTX Transfers
        • Manage ERC20 Tokens
        • Smart Contract Interactions
        • ioPay Desktop
        • DID JWT Tokens
        • Calling any RPC method
      • Embedded Blockchain Clients
        • Arduino IDE
        • Linux Systems
        • PlatformIO
        • Examples
        • Tutorials
  • Participate
    • Crypto's Got Talent (CGT)
      • IoTeX x Polygon DePIN Grant
    • Governance
      • IoTeX Improvement Proposals
      • The Marshall DAO
    • Join the Community
    • Get in Touch
Powered by GitBook
LogoLogo

This documentation portal is currently undergoing updates to align with the IoTeX 2.0 Whitepaper release. Information provided here may be incomplete, or out-of-date. Please use this portal for preliminary reference only, and check out the official IoTeX 2.0 Whitepaper for updated information.

  • .

2025 | IoTeX

On this page
  • Assumptions
  • The code

Was this helpful?

Export as PDF
  1. Builders
  2. Building DePINs
  3. Decentralized WiFi Connectivity (DeWi)

DePIN Incentives Contract

PreviousThe Data API ServiceNextBuilding DeFi

Last updated 8 months ago

Was this helpful?

This documentation is work in progress.

In previous tutorials, we covered how to create the device firmware for a WiFi access point for our demo DeWi infrastructure, and how to write and deploy the W3bstream prover logic to compute rewards generated per device.

In this tutorial, we will take the next step by creating a smart contract that implements basic DePIN incentives for the owners of the WiFi routers in our network.

Assumptions

  1. Device Tokenization: a Device NFT contract for our WiFi routers has already been deployed on IoTeX. This contract tokenizes each device on-chain and the token ID represents our custom ID for the device (e.g.a serial nomber)

  2. Identity Registration: Both the devices and their owners have their identities registered in the IoTeX .

  3. Device Messages: These devices send messages about their online status and the number of WiFi clients they have served. These messages have been processed by W3bstream using a Risc0 ZK prover to determine the amount of rewards accumulated by each device based on their activity.

  4. A DePIN token (ERC20) to be used for incentivising device owners is already deployed on IoTeX.

The computation results and their ZK proofs are sent to our smart contract by W3bstream. Our contract below will verify the proof, lookup device owners in the ioID registry, and distribute the rewards as verifiably computed by W3bstream.

The code

References

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

// Importing the Risc0 verifier contract interface to verify ZK proofs.
import {IRiscZeroVerifier} from "./IRiscZeroVerifier.sol";

// Importing the JournalParser library to decode reward data from the W3bstream output.
// This library is used to parse the Risc0 journal, which contains a mapping
// of device IDs to their respective rewards. For example: {"0":45,"3":24,"2":53,"1":62}.
import "./lib/JournalParser.sol";

// Importing the ERC721 interface to interact with the tokenized devices.
// The contract interacts with tokenized devices to find their ioID identities.
// It is assumed that the W3bstream output returns a custom device ID instead
// of the device DID, for gas efficiency.
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

// Importing the ioID registry interface to look up device identities.
// The contract uses the ioID registry to find the ioID identity associated with a given device NFT.
import "./interfaces/IioIDRegistry.sol";

// Importing the ioID contract interface to find device owners.
// The contract interacts with the ioID contract to look up the owner accounts of devices.
import "./interfaces/IioID.sol";

// Importing the ERC20 interface to distribute rewards in the form of tokens.
// The contract uses an ERC20 token to distribute rewards to device owners.
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// Importing the Ownable contract to manage ownership and administrative functions.
// The Ownable contract is used to restrict access to certain functions to the contract owner.
import "@openzeppelin/contracts/access/Ownable.sol";

contract DePINDappContract is Ownable {
    // Reference to the Risc0 Verifier contract used for verifying ZK proofs.
    IRiscZeroVerifier private verifier;
    // The image ID of the Risc0 prover program.
    bytes32 imageId;
    // Reference to the ioID NFT identity contract.
    IioID public ioID;
    // Reference to the ioID registry contract.
    IioIDRegistry public ioIDRegistry;
    // Reference to the ERC20 token used for distributing rewards.
    IERC20 private token;

    // Event emitted when a proof is successfully verified.
    event ProofVerified(address sender, bytes32 imageId, bytes32 postStateDigest);
    // Event emitted when rewards are distributed to device owners.
    event RewardsDistributed(address receiver, uint256 amount);

    // Constructor to initialize the contract with the necessary addresses.
    // Takes addresses of the verifier, token, ioID, and ioID registry contracts as input.
    constructor(
        address _verifierAddress,
        address _tokenAddress,
        address _ioIDAddress,
        address _ioIDRegistryAddress
    ) {
        verifier = IRiscZeroVerifier(_verifierAddress);
        ioID = IioID(_ioIDAddress);
        ioIDRegistry = IioIDRegistry(_ioIDRegistryAddress);
        token = IERC20(_tokenAddress);
    }

    // Function to verify the ZK proof and distribute rewards based on the journal data.
    // Takes project ID, prover ID, task ID, and encoded data containing the proof and journal as input.
    function verifyAndExecute(
        uint256 _projectId,
        uint256 _proverId, 
        uint256 _taskId, 
        bytes calldata _data
    ) external {
        // Decode the input data to extract the proof seal and journal.
        (bytes memory proof_snark_seal, bytes memory proof_snark_journal) = abi.decode(_data, (bytes, bytes));
        
        // Calculate the SHA-256 hash of the proof journal.
        bytes32 proof_journal_hash = sha256(proof_snark_journal);

        // Verify the ZK proof using the Risc0 verifier contract.
        require(verifier.verifySnark(proof_snark_seal, imageId, proof_journal_hash), "Proof verification failed.");
        
        // Emit the ProofVerified event upon successful verification.
        emit ProofVerified(msg.sender, imageId, proof_journal_hash);

        // Decode the deviceID-rewards mapping from the journal data.
        (JournalParser.Device[] memory devices, uint256 devicesLen) = JournalParser.parseDeviceJson(proof_snark_journal);

        // Distribute rewards to the owners of the devices.
        _distributeRewards(devices, devicesLen);
    }

    // Internal function to distribute rewards to device owners.
    // Takes an array of devices with their rewards and the length of the array as input.
    function _distributeRewards(JournalParser.Device[] memory devices, uint256 devicesLen) internal {
        for (uint256 i = 0; i < devicesLen; i++) {
            uint256 deviceId = devices[i].id;

            // Get the ioID token ID associated with the device ID.
            uint256 ioIDTokenId = ioIDRegistry.deviceTokenId(deviceId);

            // Get the owner of the ioID token ID.
            address owner = ioID.ownerOf(ioIDTokenId);

            // Transfer the reward amount to the device owner.
            require(token.transfer(owner, devices[i].reward), "Token transfer failed");
            // Emit the RewardsDistributed event after successful transfer.
            emit RewardsDistributed(owner, devices[i].reward);
        }
    }

    // Function to update the verifier contract address (only callable by the owner).
    // Takes the new verifier contract address as input.
    function updateVerifierAddress(address newVerifierAddress) external onlyOwner {
        verifier = IRiscZeroVerifier(newVerifierAddress);
    }

    // Function to update the token contract address (only callable by the owner).
    // Takes the new token contract address as input.
    function updateTokenAddress(address newTokenAddress) external onlyOwner {
        token = IERC20(newTokenAddress);
    }
    
    // Function to set the image ID of the Risc0 prover (only callable by the owner).
    // Takes the new image ID as input.
    function setImageId(bytes32 _imageId) public onlyOwner {
        imageId = _imageId;
    }

    // Function to get the image ID of the Risc0 prover.
    // Returns the current image ID.
    function getImageId() public view returns (bytes32) {
        return imageId;
    }
}
ioID Identity Module
Build a W3bstream prover using Risc0
Risc0 Verifier contract deployment on IoTeX Testnet
Risc0 Verifier source code
Library to parse the Journal output created by our DeWi prover