Approving new tokens

A token can only move between the Rayls Sovereign chains of a Rayls Private Network once the Private Network operator has approved it on the Private Network Hub. Approval gives the token a resource ID that every chain recognises.

The issuing institution registers and submits the token from its own Rayls Sovereign chain (Privacy Node in the code). The operator then approves it on the Hub, and the Hub tells the issuer's chain that the token is active.

The flow

StepWhoWhereCallResult
1. DeployIssuerIssuer's chainDeploy the token. Enygma tokens must be deployed through the chain's contract factory.
2. RegisterIssuerIssuer's chainregisterToken(tokenAddress) on the chain's token registry (PNTokenRegistryV1)Chain status WAITING_APPROVAL
3. Authorise locallyIssuer's chain administratorIssuer's chainupdatePrivacyNodeStatus(tokenAddress, 2)Chain status AUTHORIZED
4. SubmitIssuer's chain administratorIssuer's chainsubmitToHub(tokenAddress)Hub status on the chain: WAITING_APPROVAL. A registration message goes to the Hub.
5. RecordHubHubThe message calls addToken on the Hub's TokenRegistryThe token gets a resource ID. Hub status NEW.
6. ApprovePrivate Network operatorHubupdateStatus(resourceId, 1) on the Hub's TokenRegistryHub status ACTIVE. An activation message goes to the issuer's chain.
7. ActivateHubIssuer's chainThe message calls activateTokenThe token takes its resource ID. Hub status on the chain: AUTHORIZED. The token can now move.

Other participants don't register the token. The first time a chain receives it, a copy is deployed there automatically.

What the Hub checks at step 5

When the registration message reaches the Hub, addToken:

  • accepts it only if the issuing chain is an active participant with the ISSUER role (see Adding new participants); otherwise the registration fails on the Hub, and the token stays WAITING_APPROVAL on the issuer's chain;
  • rejects a token whose name is already registered on the Hub. Names are unique across the network;
  • assigns the resource ID and records the token with status NEW;
  • for an Enygma token, creates the token's Enygma contract on the Hub; for a delivery-versus-payment (DvP) ERC-721 or ERC-1155 token, creates its DvP contract on the Hub.

Supported standards are ERC-20, ERC-721, ERC-1155, Enygma, and the DvP versions of ERC-721 and ERC-1155. See Supported token standards.

The statuses

The issuer's chain tracks two statuses for each token; the Hub tracks one.

RegistryFieldValues
Issuer's chain (PNTokenRegistryV1)privacyNodeStatusUNDEFINED (0), WAITING_APPROVAL (1), AUTHORIZED (2), UNAUTHORIZED (3), FROZEN (4)
Issuer's chainhubStatusSame values as above
Hub (TokenRegistryV1)statusNEW (0), ACTIVE (1), INACTIVE (2)

On the issuer's chain, a token can move to other chains once both its privacyNodeStatus and its hubStatus are AUTHORIZED.

Approve a token

1. Find tokens waiting for approval

With the governance API:

curl "http://<governance-api>/audit/tokens?status=new"
{
  "data": [
    {
      "resourceId": "9f4c…",
      "name": "Bank B Deposit Token",
      "symbol": "BBDT",
      "metadataURL": "",
      "decimals": 2,
      "issuerId": "200002",
      "status": "new",
      "ercStandard": "erc20",
      "totalSupply": "0",
      "circulatingSupply": [],
      "frozenChainIds": [],
      "createdAt": "2026-10-06T10:02:13Z",
      "updatedAt": "2026-10-06T10:02:13Z"
    }
  ],
  "total": 1,
  "limit": 10,
  "page": 1
}

GET /audit/tokens also filters by name, symbol, issuerId, ercStandard, decimals, createdAfter and createdBefore, and pages with page and limit (up to 100). GET /audit/tokens/{resourceId} returns one token.

To read the Hub directly, run npx hardhat getAllTokens. It prints each token's resource ID, name, symbol, and whether it is approved.

2. Check the token

There is no automatic check. Before approving, confirm with the issuer that the name, symbol, standard, decimals and issuing chain (issuerId) are the ones it intended.

3. Approve it

Set the token's Hub status to ACTIVE (1) with the operator's ADMIN account, or an account with the optional PRIVATE_NETWORK_OPERATOR role. In a Hardhat script, with operator and registry set up as in Adding new participants:

const tokenRegistry = await ethers.getContractAt('TokenRegistryV1', await registry.getContract('TokenRegistry'), operator);
await (await tokenRegistry.updateStatus(resourceId, 1)).wait();

The Hardhat tasks in rayls-sovereign-contracts do the same. They use PNH_RPC_URL, PNH_DEPLOYMENT_PROXY_REGISTRY and PRIVATE_KEY_SYSTEM.

TaskWhat it approves
tokens:approve-hub --symbol <SYMBOL>The token whose resource ID is in the TOKEN_<SYMBOL>_RESOURCE_ID environment variable
tokens:approve-last-hubThe most recently registered token on the Hub
tokens:approve-last-batch-hub --n <N>The N most recently registered tokens
tokens:approve-all-hubEvery registered token that isn't approved yet
🚧

Approve deliberately

The last tasks approve whatever the Hub registered most recently, and the all task approves everything pending, from any issuer, without showing you the tokens first. On a shared network, list the pending tokens and approve them one at a time.

4. Confirm activation

The Hub records the approval at once: GET /audit/tokens/{resourceId} shows "status": "active" after the listener has indexed it. The token can move only after the activation message has reached the issuer's chain. On that chain, getHubStatus(tokenAddress) on PNTokenRegistryV1 returns AUTHORIZED (2), and tokens:statuses --pn <ID> --token-address <address> prints the token's statuses.

Not approving a token

The Hub has no rejection. A token you don't approve stays NEW on the Hub and WAITING_APPROVAL on the issuer's chain, and can't move. The issuer's chain administrator can mark it locally with rejectToken(tokenAddress), which sets its Hub status on that chain to UNAUTHORIZED.

Stopping an approved token

To stop an approved token, freeze it for the participants concerned. See Freezing tokens.

For the issuer

The issuer's steps use roles on its own chain: TOKEN_CREATOR for registerToken, and PN_TOKEN_REGISTRY_ADMIN for updatePrivacyNodeStatus, submitToHub and rejectToken. If the chain's business roles are active, PRIVACY_NODE_OPERATOR can also call updatePrivacyNodeStatus and submitToHub (see Private Network roles). The Hardhat tasks for them are tokens:register, tokens:approve-pn and submitTokenToHub.

The Rayls Sovereign Ops API, an optional service for a Rayls Sovereign chain, exposes the same steps:

StepOps API call
RegisterPOST /api/tokens/{address}/register
Authorise locallyPATCH /api/v1/admin/tokens/{address}/status with {"status": "authorized"}
Submit to the HubPOST /api/v1/admin/tokens/{address}/submit with {"target": "hub"}
List tokens waiting for local approvalGET /api/tokens/registry/pending

For an Enygma token from end to end, see Running Rayls Enygma.


Did this page help you?