Integrating hPassport into Your dApp

1. Retrieve User Attributes from hPassport

When a user interacts with your dApp, you can retrieve various attributes from their hPassport to verify identity or personalize the experience.

Example: Retrieve the User's Primary Identity

solidityCopy code// Retrieve the user’s primary identity
(bool primaryID, uint256 expiry, uint256 updatedAt) = proofOfIdentity.getPrimaryID(userAddress);

// Ensure the user is verified
require(primaryID, "User is not verified.");

Example: Retrieve the User's Country of Residence Code

solidityCopy code// Retrieve the user’s country code
(string memory countryCode, uint256 expiry, uint256 updatedAt) = proofOfIdentity.getCountryCode(userAddress);

2. Enforcing Identity Verification in Smart Contracts

To ensure only verified users can interact with your contract, check their hPassport before executing any logic. Here's how you can implement this in your contract:

solidityCopy codepragma solidity ^0.8.0;

import { IProofOfIdentity } from "./IProofOfIdentity.sol";

contract VerifiedAuction {

    IProofOfIdentity proofOfIdentity;

    constructor(address _proofOfIdentity) {
        proofOfIdentity = IProofOfIdentity(_proofOfIdentity);
    }

    modifier onlyVerified(address user) {
        (bool primaryID,,) = proofOfIdentity.getPrimaryID(user);
        require(primaryID, "User is not verified.");
        _;
    }

    function placeBid() external onlyVerified(msg.sender) {
        // auction logic here
    }
}

3. Personalizing User Experiences Based on hPassport Attributes

You can personalize the experience for users based on the anonymized data available on their hPassport. For example, you can restrict certain features based on a user's county of residence, or other attributes.

Example: Regional Restriction

solidityCopy code// Retrieve the user’s country code
(string memory countryCode,,) = proofOfIdentity.getCountryCode(userAddress);

// Check if the user is from an allowed country
require(keccak256(abi.encodePacked(countryCode)) == keccak256(abi.encodePacked("US")), "Service not available in your country.");

4. Handling Suspended Users

To prevent suspended users from interacting with your dApp, you can check the suspension status of the user's hPassport:

solidityCopy code// Check if user account is suspended
bool isSuspended = proofOfIdentity.isSuspended(userAddress);
require(!isSuspended, "User account is suspended.");

5. Multiple Account Support

hPassport allows verified users to have multiple wallets, linking their identity to both a primary account and auxiliary accounts. You can retrieve the auxiliary accounts linked to a user’s hPassport as follows:

solidityCopy code// Retrieve auxiliary accounts linked to a principal account
address[] memory auxAccounts = proofOfIdentity.auxiliaryAccounts(principalAddress);

hPassport API Reference

Below are the key functions available in the hPassport contract:

Identity Verification Functions

  • getPrimaryID(address account): Returns a boolean indicating if the user is verified, along with the expiration and last update timestamp.

    solidityCopy code(bool primaryID, uint256 expiry, uint256 updatedAt) = proofOfIdentity.getPrimaryID(userAddress);
  • getCountryCode(address account): Retrieves the user’s country code (stored as a string).

    solidityCopy code(string memory countryCode, uint256 expiry, uint256 updatedAt) = proofOfIdentity.getCountryCode(userAddress);
  • getProofOfLiveliness(address account): Retrieves whether the user has passed proof of liveliness checks.

    solidityCopy code(bool liveliness, uint256 expiry, uint256 updatedAt) = proofOfIdentity.getProofOfLiveliness(userAddress);
  • getUserType(address account): Retrieves the type of user (e.g., retail, institution).

    solidityCopy code(uint256 userType, uint256 expiry, uint256 updatedAt) = proofOfIdentity.getUserType(userAddress);
  • isSuspended(address account): Checks if the user’s hPassport is suspended.

    solidityCopy codebool suspended = proofOfIdentity.isSuspended(userAddress);

Auxiliary Account Functions

  • auxiliaryAccounts(address principal): Returns auxiliary accounts linked to the principal account.

    solidityCopy codeaddress[] memory auxAccounts = proofOfIdentity.auxiliaryAccounts(principalAddress);

Example Use Case: Auction with Verified Users

This example demonstrates how to build an auction application that only allows verified users to participate. The auction uses hPassport to ensure that only users with a verified identity can place bids. This directory contains this example contract

AuctionPOI.sol: This contract is an implementation of an NFT auction system. It uses the userType of an account to permission the auction process, showcasing how user identity attributes can govern smart contract functionalities.

solidityCopy codepragma solidity ^0.8.0;

import { IProofOfIdentity } from "./IProofOfIdentity.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

contract VerifiedAuction is ReentrancyGuardUpgradeable {

    IProofOfIdentity proofOfIdentity;
    IERC721Upgradeable nft;
    address highestBidder;
    uint256 highestBid;
    uint256 auctionEndTime;

    constructor(address _proofOfIdentity, address _nft) {
        proofOfIdentity = IProofOfIdentity(_proofOfIdentity);
        nft = IERC721Upgradeable(_nft);
    }

    modifier onlyVerified(address user) {
        (bool primaryID,,) = proofOfIdentity.getPrimaryID(user);
        require(primaryID, "User is not verified.");
        _;
    }

    function placeBid() external payable onlyVerified(msg.sender) {
        require(msg.value > highestBid, "Bid too low.");
        require(block.timestamp < auctionEndTime, "Auction has ended.");

        // Refund the previous highest bidder
        if (highestBidder != address(0)) {
            payable(highestBidder).transfer(highestBid);
        }

        highestBid = msg.value;
        highestBidder = msg.sender;
    }

    function endAuction() external {
        require(block.timestamp >= auctionEndTime, "Auction not ended.");
        nft.transferFrom(address(this), highestBidder, 1);
    }
}

Important Notes

  • Demonstration Purpose: These contracts incorporate many Solidity best practices but are intended for demonstration purposes only.

  • Production Considerations:

    • The bid function in AuctionPOI.sol (line 280) should include a reentrancy guard in a production environment.

    • The transfer of H1 tokens in AuctionPOI.sol (lines 454 and 468) should be approached with caution, avoiding optimistic transfers in most cases.

Identity Verification Checks

Both contracts include explicit checks for:

  • The presence of an account’s ID NFT.

  • The suspended status of the account.

In the Haven1 network, these checks would typically be redundant as the network itself restricts transactions for accounts without an ID NFT or with a suspended status. However, they are included in these examples for educational purposes.

Testing

Example tests for both contracts are available in the directory: test/proof-of-identity/examples. These tests can be used as a reference for developing and validating your own contracts that interact with the hPassport.

Last updated