The DePIN Framework: Specialized Libraries

evire
10 min readJul 2, 2024

--

Example: Physical Infrastructure Management Library

Decentralized Physical Infrastructure Networks (DePIN) present a groundbreaking method for overseeing and upkeeping physical resources using blockchain technology. By making use of the decentralized aspect of blockchain, DePIN guarantees the integrity, security and transparency of data, all vital for effective infrastructure management. This system allows for the inclusion of IoT devices for live monitoring, streamlines processes with smart contracts and supports decentralized governance, making it a valuable tool for handling extensive physical assets.

Evire is dedicated to tapping into the possibilities offered by DePIN through its specialized libraries that equip developers with robust resources to construct and oversee decentralized infrastructure initiatives. The Evire DePIN framework is crafted to cater to various applications, ranging from managing urban infrastructure to maintaining industrial assets. It offers a flexible and expandable platform that can be customized according to specific project needs.

A standout feature in this framework is the Physical Infrastructure Management Libraries. These libraries are tailored to manage intricate operations related to overseeing physical assets while ensuring data integrity. They also facilitate seamless integration with IoT data sources for real-time monitoring and decision-making. Through ready-to-use smart contract modules, Evire empowers developers to effectively handle tasks like asset lifecycle management, maintenance procedures, and resource allocation on the blockchain. The flexible design of these libraries makes them simple to tailor and expand, meeting the specific requirements of various infrastructure projects.

Example: Physical Infrastructure Management Library

This library is created to manage infrastructure tasks maintain data accuracy and enable connection, with data sources to monitor activities in time and make informed decisions. Developers can expand the library to suit their project needs due, to its customizable design.

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

/// @title InfrastructureManagement
/// @notice This library provides reusable smart contract modules for managing physical infrastructure on the blockchain.
library InfrastructureManagement {

struct Asset {
string name;
uint256 id;
address owner;
uint256 createdAt;
uint256 updatedAt;
bool active;
AssetType assetType;
}

struct MaintenanceRecord {
uint256 assetId;
uint256 maintenanceDate;
string description;
address performedBy;
MaintenanceStatus status;
}

struct ResourceAllocation {
uint256 assetId;
uint256 resourceId;
uint256 quantity;
uint256 allocatedAt;
bool active;
}

struct EventRecord {
uint256 assetId;
uint256 timestamp;
EventType eventType;
string data;
}

struct UserAuthorization {
address user;
bool authorized;
UserRole role;
}

enum AssetType { Building, Equipment, Vehicle, Other }
enum MaintenanceStatus { Scheduled, InProgress, Completed, Cancelled }
enum EventType { Failure, Repair, Upgrade, Inspection }
enum UserRole { Admin, Operator, Maintainer, Viewer }

event AssetCreated(uint256 indexed assetId, string name, address indexed owner, AssetType assetType);
event AssetUpdated(uint256 indexed assetId, string name, address indexed owner, bool active);
event AssetTransferred(uint256 indexed assetId, address indexed from, address indexed to);
event MaintenanceScheduled(uint256 indexed assetId, uint256 maintenanceDate, string description, address indexed performedBy);
event MaintenanceStatusUpdated(uint256 indexed assetId, uint256 maintenanceDate, MaintenanceStatus status);
event ResourceAllocated(uint256 indexed assetId, uint256 indexed resourceId, uint256 quantity, uint256 allocatedAt);
event ResourceDeallocated(uint256 indexed assetId, uint256 indexed resourceId, uint256 quantity, uint256 deallocatedAt);
event EventRecorded(uint256 indexed assetId, uint256 timestamp, EventType eventType, string data);
event UserAuthorized(address indexed user, UserRole role);
event UserRevoked(address indexed user);

error AssetAlreadyExists(uint256 assetId);
error AssetDoesNotExist(uint256 assetId);
error UnauthorizedAccess(address user);
error InvalidInput();

modifier assetExists(mapping(uint256 => Asset) storage assets, uint256 assetId) {
if (assets[assetId].id == 0) revert AssetDoesNotExist(assetId);
_;
}

modifier onlyAuthorized(mapping(address => UserAuthorization) storage userAuthorizations, address user, UserRole requiredRole) {
if (!isUserAuthorized(userAuthorizations, user) || userAuthorizations[user].role != requiredRole) {
revert UnauthorizedAccess(user);
}
_;
}

function createAsset(
mapping(uint256 => Asset) storage assets,
uint256 assetId,
string memory name,
address owner,
AssetType assetType
) public {
if (assets[assetId].id != 0) revert AssetAlreadyExists(assetId);
if (owner == address(0)) revert InvalidInput();

assets[assetId] = Asset({
name: name,
id: assetId,
owner: owner,
createdAt: block.timestamp,
updatedAt: block.timestamp,
active: true,
assetType: assetType
});

emit AssetCreated(assetId, name, owner, assetType);
}

function updateAsset(
mapping(uint256 => Asset) storage assets,
uint256 assetId,
string memory name,
address owner,
bool active
) public assetExists(assets, assetId) {
if (owner == address(0)) revert InvalidInput();

Asset storage asset = assets[assetId];
asset.name = name;
asset.owner = owner;
asset.updatedAt = block.timestamp;
asset.active = active;

emit AssetUpdated(assetId, name, owner, active);
}

function transferAsset(
mapping(uint256 => Asset) storage assets,
uint256 assetId,
address newOwner
) public assetExists(assets, assetId) {
if (newOwner == address(0)) revert InvalidInput();

Asset storage asset = assets[assetId];
address previousOwner = asset.owner;
asset.owner = newOwner;
asset.updatedAt = block.timestamp;

emit AssetTransferred(assetId, previousOwner, newOwner);
}

function scheduleMaintenance(
mapping(uint256 => MaintenanceRecord[]) storage maintenanceRecords,
uint256 assetId,
uint256 maintenanceDate,
string memory description,
address performedBy
) public {
if (maintenanceDate < block.timestamp) revert InvalidInput();

maintenanceRecords[assetId].push(MaintenanceRecord({
assetId: assetId,
maintenanceDate: maintenanceDate,
description: description,
performedBy: performedBy,
status: MaintenanceStatus.Scheduled
}));

emit MaintenanceScheduled(assetId, maintenanceDate, description, performedBy);
}

function updateMaintenanceStatus(
mapping(uint256 => MaintenanceRecord[]) storage maintenanceRecords,
uint256 assetId,
uint256 maintenanceDate,
MaintenanceStatus newStatus
) public {
MaintenanceRecord[] storage records = maintenanceRecords[assetId];
for (uint256 i = 0; i < records.length; i++) {
if (records[i].maintenanceDate == maintenanceDate) {
records[i].status = newStatus;
emit MaintenanceStatusUpdated(assetId, maintenanceDate, newStatus);
break;
}
}
}

function allocateResource(
mapping(uint256 => ResourceAllocation[]) storage resourceAllocations,
uint256 assetId,
uint256 resourceId,
uint256 quantity
) public {
if (quantity == 0) revert InvalidInput();

resourceAllocations[assetId].push(ResourceAllocation({
assetId: assetId,
resourceId: resourceId,
quantity: quantity,
allocatedAt: block.timestamp,
active: true
}));

emit ResourceAllocated(assetId, resourceId, quantity, block.timestamp);
}

function deallocateResource(
mapping(uint256 => ResourceAllocation[]) storage resourceAllocations,
uint256 assetId,
uint256 resourceId,
uint256 quantity
) public {
ResourceAllocation[] storage allocations = resourceAllocations[assetId];
for (uint256 i = 0; i < allocations.length; i++) {
if (allocations[i].resourceId == resourceId && allocations[i].quantity == quantity && allocations[i].active) {
allocations[i].active = false;
emit ResourceDeallocated(assetId, resourceId, quantity, block.timestamp);
break;
}
}
}

function recordEvent(
mapping(uint256 => EventRecord[]) storage eventRecords,
uint256 assetId,
EventType eventType,
string memory data
) public {
eventRecords[assetId].push(EventRecord({
assetId: assetId,
timestamp: block.timestamp,
eventType: eventType,
data: data
}));

emit EventRecorded(assetId, block.timestamp, eventType, data);
}

function authorizeUser(
mapping(address => UserAuthorization) storage userAuthorizations,
address user,
UserRole role
) public {
if (user == address(0)) revert InvalidInput();

userAuthorizations[user] = UserAuthorization({
user: user,
authorized: true,
role: role
});

emit UserAuthorized(user, role);
}

function revokeUser(
mapping(address => UserAuthorization) storage userAuthorizations,
address user
) public {
if (user == address(0)) revert InvalidInput();

delete userAuthorizations[user];

emit UserRevoked(user);
}

function isUserAuthorized(
mapping(address => UserAuthorization) storage userAuthorizations,
address user
) public view returns (bool) {
return userAuthorizations[user].authorized;
}

function getUserRole(
mapping(address => UserAuthorization) storage userAuthorizations,
address user
) public view returns (UserRole) {
return userAuthorizations[user].role;
}
}

The provided code defines a Solidity library named InfrastructureManagement for managing physical infrastructure on the blockchain. This library includes several key components:

Data Structures:

  • Asset: Represents physical assets with attributes like name, ID, owner, creation and update timestamps, activity status, and type.
  • MaintenanceRecord: Logs maintenance activities with details like asset ID, maintenance date, description, performer, and status.
  • ResourceAllocation: Tracks resources allocated to assets, including asset ID, resource ID, quantity, allocation timestamp, and activity status.
  • EventRecord: Records events related to assets, including asset ID, timestamp, event type, and data.
  • UserAuthorization: Manages user permissions, including user address, authorization status, and role.

Enumerations:

  • AssetType: Defines types of assets (Building, Equipment, Vehicle, Other).
  • MaintenanceStatus: Specifies maintenance statuses (Scheduled, InProgress, Completed, Cancelled).
  • EventType: Categorizes events (Failure, Repair, Upgrade, Inspection).
  • UserRole: Defines user roles (Admin, Operator, Maintainer, Viewer).

Events:

  • Events like AssetCreated, AssetUpdated, AssetTransferred, MaintenanceScheduled, MaintenanceStatusUpdated, ResourceAllocated, ResourceDeallocated, EventRecorded, UserAuthorized, and UserRevoked are defined to log significant actions.

Errors:

  • Custom errors such as AssetAlreadyExists, AssetDoesNotExist, UnauthorizedAccess, and InvalidInput provide detailed failure information.

Modifiers:

  • assetExists: Ensures an asset exists before proceeding with an operation.
  • onlyAuthorized: Ensures a user has the necessary authorization for an operation.

Functions:

  • createAsset: Creates a new asset, ensuring it doesn’t already exist and the owner address is valid.
  • updateAsset: Updates an existing asset’s details.
  • transferAsset: Transfers ownership of an asset to a new owner.
  • scheduleMaintenance: Schedules maintenance for an asset.
  • updateMaintenanceStatus: Updates the status of a maintenance record.
  • allocateResource: Allocates resources to an asset.
  • deallocateResource: Deallocates resources from an asset.
  • recordEvent: Records an event related to an asset.
  • authorizeUser: Authorizes a user with a specific role.
  • revokeUser: Revokes a user’s authorization.
  • isUserAuthorized: Checks if a user is authorized.
  • getUserRole: Retrieves a user’s role.

Example of Usage

To showcase how the InfrastructureManagement library is put into practice lets look at an example involving a contract. This contract, called PhysicalInfrastructureManager makes use of the library to effectively oversee infrastructure assets. It handles tasks like managing the lifecycle of assets, scheduling maintenance, allocating resources and granting user access. By harnessing the capabilities of the InfrastructureManagement library this contract ensures security, efficiency and adaptability, in managing different aspects of physical infrastructure on the blockchain. Here is how the PhysicalInfrastructureManager smart contract is implemented:

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

import "./DePINFW/InfrastructureManagement.sol";

/// @title Physical Infrastructure Management Smart Contract
/// @notice This contract manages physical infrastructure assets, including their lifecycle, maintenance, and resource allocation.
contract PhysicalInfrastructureManager {
using InfrastructureManagement for mapping(uint256 => InfrastructureManagement.Asset);
using InfrastructureManagement for mapping(uint256 => InfrastructureManagement.MaintenanceRecord[]);
using InfrastructureManagement for mapping(uint256 => InfrastructureManagement.ResourceAllocation[]);
using InfrastructureManagement for mapping(uint256 => InfrastructureManagement.EventRecord[]);
using InfrastructureManagement for mapping(address => InfrastructureManagement.UserAuthorization);

mapping(uint256 => InfrastructureManagement.Asset) private assets;
mapping(uint256 => InfrastructureManagement.MaintenanceRecord[]) private maintenanceRecords;
mapping(uint256 => InfrastructureManagement.ResourceAllocation[]) private resourceAllocations;
mapping(uint256 => InfrastructureManagement.EventRecord[]) private eventRecords;
mapping(address => InfrastructureManagement.UserAuthorization) private userAuthorizations;

address public admin;
uint256 private nextAssetId;

event AdminChanged(address indexed previousAdmin, address indexed newAdmin);
event UnauthorizedAccess(address indexed caller, bytes4 indexed functionSelector);

error Unauthorized(address caller);
error InvalidInput();
error AssetNotFound(uint256 assetId);

modifier onlyAdmin() {
if (msg.sender != admin) revert Unauthorized(msg.sender);
_;
}

modifier onlyAuthorized(InfrastructureManagement.UserRole requiredRole) {
if (!userAuthorizations.isUserAuthorized(msg.sender) && msg.sender != admin) {
revert Unauthorized(msg.sender);
}
if (userAuthorizations.getUserRole(msg.sender) < requiredRole && msg.sender != admin) {
revert Unauthorized(msg.sender);
}
_;
}

modifier assetExists(uint256 assetId) {
if (assets[assetId].id == 0) revert AssetNotFound(assetId);
_;
}

constructor() {
admin = msg.sender;
nextAssetId = 1;
emit AdminChanged(address(0), msg.sender);
}

function changeAdmin(address newAdmin) external onlyAdmin {
if (newAdmin == address(0)) revert InvalidInput();
emit AdminChanged(admin, newAdmin);
admin = newAdmin;
}

function authorizeUser(address user, InfrastructureManagement.UserRole role) external onlyAdmin {
userAuthorizations.authorizeUser(user, role);
}

function revokeUser(address user) external onlyAdmin {
userAuthorizations.revokeUser(user);
}

function createAsset(string memory name, address owner, InfrastructureManagement.AssetType assetType)
external
onlyAuthorized(InfrastructureManagement.UserRole.Operator)
returns (uint256)
{
uint256 assetId = nextAssetId++;
assets.createAsset(assetId, name, owner, assetType);
return assetId;
}

function updateAsset(uint256 assetId, string memory name, address owner, bool active)
external
onlyAuthorized(InfrastructureManagement.UserRole.Operator)
assetExists(assetId)
{
assets.updateAsset(assetId, name, owner, active);
}

function transferAsset(uint256 assetId, address newOwner)
external
onlyAuthorized(InfrastructureManagement.UserRole.Admin)
assetExists(assetId)
{
assets.transferAsset(assetId, newOwner);
}

function getAsset(uint256 assetId) external view assetExists(assetId) returns (InfrastructureManagement.Asset memory) {
return assets[assetId];
}

function scheduleMaintenance(uint256 assetId, uint256 maintenanceDate, string memory description, address performedBy)
external
onlyAuthorized(InfrastructureManagement.UserRole.Maintainer)
assetExists(assetId)
{
maintenanceRecords.scheduleMaintenance(assetId, maintenanceDate, description, performedBy);
}

function updateMaintenanceStatus(uint256 assetId, uint256 maintenanceDate, InfrastructureManagement.MaintenanceStatus newStatus)
external
onlyAuthorized(InfrastructureManagement.UserRole.Maintainer)
assetExists(assetId)
{
maintenanceRecords.updateMaintenanceStatus(assetId, maintenanceDate, newStatus);
}

function getMaintenanceRecords(uint256 assetId) external view assetExists(assetId) returns (InfrastructureManagement.MaintenanceRecord[] memory) {
return maintenanceRecords[assetId];
}

function allocateResource(uint256 assetId, uint256 resourceId, uint256 quantity)
external
onlyAuthorized(InfrastructureManagement.UserRole.Operator)
assetExists(assetId)
{
resourceAllocations.allocateResource(assetId, resourceId, quantity);
}

function deallocateResource(uint256 assetId, uint256 resourceId, uint256 quantity)
external
onlyAuthorized(InfrastructureManagement.UserRole.Operator)
assetExists(assetId)
{
resourceAllocations.deallocateResource(assetId, resourceId, quantity);
}

function getResourceAllocations(uint256 assetId) external view assetExists(assetId) returns (InfrastructureManagement.ResourceAllocation[] memory) {
return resourceAllocations[assetId];
}

function recordEvent(uint256 assetId, InfrastructureManagement.EventType eventType, string memory data)
external
onlyAuthorized(InfrastructureManagement.UserRole.Operator)
assetExists(assetId)
{
eventRecords.recordEvent(assetId, eventType, data);
}

function getEventRecords(uint256 assetId) external view assetExists(assetId) returns (InfrastructureManagement.EventRecord[] memory) {
return eventRecords[assetId];
}

function getAssetsByOwner(address owner) external view returns (InfrastructureManagement.Asset[] memory) {
uint256 count;
for (uint256 i = 1; i < nextAssetId; i++) {
if (assets[i].owner == owner) {
count++;
}
}

InfrastructureManagement.Asset[] memory result = new InfrastructureManagement.Asset[](count);
uint256 index;
for (uint256 i = 1; i < nextAssetId; i++) {
if (assets[i].owner == owner) {
result[index] = assets[i];
index++;
}
}

return result;
}

function getActiveAssets() external view returns (InfrastructureManagement.Asset[] memory) {
uint256 count;
for (uint256 i = 1; i < nextAssetId; i++) {
if (assets[i].active) {
count++;
}
}

InfrastructureManagement.Asset[] memory result = new InfrastructureManagement.Asset[](count);
uint256 index;
for (uint256 i = 1; i < nextAssetId; i++) {
if (assets[i].active) {
result[index] = assets[i];
index++;
}
}

return result;
}
}

The PhysicalInfrastructureManager smart contract is designed to manage physical infrastructure assets on the blockchain. It provides a comprehensive system for tracking, maintaining, and allocating resources to various physical assets. This contract is particularly useful for organizations dealing with large-scale infrastructure management, such as cities, utilities, or large corporations with significant physical assets.

Key Features

  1. Asset Management: Create, update, and transfer ownership of physical assets.
  2. Maintenance Tracking: Schedule and update maintenance activities for assets.
  3. Resource Allocation: Allocate and deallocate resources to specific assets.
  4. Event Logging: Record important events related to assets.
  5. Role-Based Access Control: Ensure that only authorized users can perform specific actions.
  6. Asset Querying: Retrieve information about assets, including filtering by owner or active status.

Contract Structure

The contract uses the InfrastructureManagement library to define data structures and implement core functionality. It maintains several mappings to store asset data, maintenance records, resource allocations, and event logs.

Key Components:

  • assets: Stores information about each asset.
  • maintenanceRecords: Keeps track of maintenance activities for assets.
  • resourceAllocations: Manages resource allocations to assets.
  • eventRecords: Logs important events related to assets.
  • userAuthorizations: Manages user roles and permissions.

Access Control

The contract implements a role-based access control system:

  • admin: Has full access to all functions.
  • Operator: Can create and update assets, allocate resources, and record events.
  • Maintainer: Can schedule and update maintenance activities.
  • Admin: Can transfer asset ownership.

Key Functions

  1. createAsset: Creates a new asset with a unique ID.
  2. updateAsset: Modifies an existing asset's information.
  3. transferAsset: Changes the ownership of an asset.
  4. scheduleMaintenance: Schedules a maintenance activity for an asset.
  5. updateMaintenanceStatus: Updates the status of a scheduled maintenance.
  6. allocateResource and deallocateResource: Manage resource allocation to assets.
  7. recordEvent: Logs important events related to an asset.
  8. getAssetsByOwner and getActiveAssets: Query functions to retrieve asset information.

Security Measures

  • Custom error messages for better gas efficiency and clarity.
  • Modifiers to check authorization and asset existence before executing functions.
  • Role-based access control to restrict function access based on user roles.

Scalability and Efficiency

  • Uses a nextAssetId variable to efficiently manage asset IDs.
  • Implements gas-efficient loops in query functions.

PhysicalInfrastructureManager contract showcases the functionalities of the InfrastructureManagement library in the DePIN framework. By utilizing this library developers can effectively oversee the lifecycle, upkeep and resource distribution of infrastructure assets, on the blockchain. The contract illustrates the implementation of security protocols like role based access control and thorough error management to ensure that authorized users can carry out specific tasks. This inclusive system is especially advantageous for organizations handling large scale infrastructure projects equipping them with tools for real time monitoring, informed decision making and seamless integration with data sources. The librarys flexibility and scalability enable effortless customization and expansion making it a valuable resource, for an array of projects and deployment scenarios.

--

--

evire

Evire is a layer 1 blockchain that aims to provide native support for AI, gaming, RWA and DePIN, empowering developers to build efficient, cutting-edge dApps.