Skip to main content

Overview

The Router Registry is an ERC-721 NFT contract that serves as a decentralized directory. Each NFT represents an Opencharge identity, and the token ID is the OCID.

Contract

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract RouterRegistry is ERC721 {

    mapping(uint256 => string) private _metadataUrls;
    uint256 private _nextTokenId;

    event OCIDRegistered(uint256 indexed ocid, address indexed owner, string metadataUrl);
    event MetadataUrlUpdated(uint256 indexed ocid, string metadataUrl);

    constructor() ERC721("Opencharge Router", "OCID") {}

    /// @notice Register a new OCID
    /// @param metadataUrl URL pointing to the service's metadata JSON
    /// @return ocid The newly minted OCID
    function register(string calldata metadataUrl) external returns (uint256 ocid) {
        ocid = _nextTokenId++;
        _mint(msg.sender, ocid);
        _metadataUrls[ocid] = metadataUrl;
        emit OCIDRegistered(ocid, msg.sender, metadataUrl);
    }

    /// @notice Update metadata URL (owner only)
    function updateMetadataUrl(uint256 ocid, string calldata metadataUrl) external {
        require(ownerOf(ocid) == msg.sender, "Not OCID owner");
        _metadataUrls[ocid] = metadataUrl;
        emit MetadataUrlUpdated(ocid, metadataUrl);
    }

    /// @notice Resolve OCID to metadata URL
    function resolve(uint256 ocid) external view returns (string memory) {
        require(_ownerOf(ocid) != address(0), "OCID does not exist");
        return _metadataUrls[ocid];
    }

    /// @notice Check if OCID exists
    function exists(uint256 ocid) external view returns (bool) {
        return _ownerOf(ocid) != address(0);
    }

    /// @notice Total registered OCIDs
    function totalSupply() external view returns (uint256) {
        return _nextTokenId;
    }
}

Metadata Schema

The metadata URL must return a JSON document:
{
  "opencharge": "0.1",
  "name": "MTN Mobile Money Uganda",
  "description": "Mobile money service for Uganda",
  "icon": "https://mtn.co.ug/icon.png",

  "publicKey": "a34b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b",

  "endpoint": "https://api.mtn.co.ug/opencharge",

  "capabilities": [
    "payment.receive",
    "payment.settle"
  ],

  "settlement": {
    "currencies": ["UGX", "USD"],
    "accepts": [100, 101, 102]
  },

  "contact": "integrations@mtn.co.ug"
}

Field Reference

FieldTypeRequiredDescription
openchargestringYesProtocol version
namestringYesHuman-readable service name
descriptionstringNoService description
iconstringNoURL to service logo
publicKeystringYessecp256k1 public key (128 hex chars, uncompressed without 04 prefix)
endpointstringYesBase URL for Opencharge API
capabilitiesarrayYesList of supported operations
settlement.currenciesarrayYes*Supported currencies
settlement.acceptsarrayYes*OCIDs accepted for settlement
contactstringNoIntegration support contact
*Required if service accepts settlement

Standard Capabilities

CapabilityDescription
payment.createCan create payments (POST /payment/create)
payment.settleCan accept settlement proofs (POST /payment/settle)
payment.receiveCan receive inbound payments (be a recipient)
transfer.createCan execute transfers (POST /transfer/create)
transfer.webhookCan receive transfer notifications (POST /transfer/webhook)
orders.createCan create and sign orders (POST /orders/create)
orders.statusProvides order status (GET /orders//status)
verify.txidProvides transaction verification (GET /verify)

Multiple OCIDs

A single entity MAY register multiple OCIDs for different purposes:
PayPal Holdings
├── OCID 200: PayPal Subscriptions
├── OCID 201: PayPal One-Time Payments
├── OCID 202: PayPal Merchant Services
└── OCID 203: Venmo
This enables isolated security domains, different rate limits, and service-specific configurations.