Primcast
中文

For developers

Primcast is EVM-equivalent (Arbitrum Nitro), so your existing tools work: Foundry, Hardhat, viem, ethers and wagmi.

Endpoints and addresses

See Network for RPC, WebSocket, explorer and chain IDs, and for the live contract addresses. The deployment artifact contracts/deployments/<chainId>.json in the Primcast repository has the same data in machine-readable form.

ABIs

Build with forge build in contracts/, or use the generated portal/lib/abi.ts, which exports identityRegistryAbi, rwaTokenAbi, offeringAbi, assetHubAbi, rwaTokenFactoryAbi and systemRegistryAbi.

Check eligibility before acting

const ok = await client.readContract({
  address: token, abi: rwaTokenAbi, functionName: "canReceive", args: [wallet, amount],
});

canReceive runs the full receiver check, including freeze, sanctions, KYC, accreditation, jurisdiction and holder cap, without reverting. Use IdentityRegistry.complianceOf(wallet) to explain why it fails.

Sending transactions

  • Approvals: the settlement tokens are ordinary ERC-20s. Approve the Offering contract before subscribe, and the token before distributeDividend or fundRedemptionPool. AssetHub needs approval for bonds.
  • Gas: transactions pay for L1 data as well as execution. Let the node estimate gas. With Foundry, always broadcast with --skip-simulation --slow, otherwise the node rejects transactions with intrinsic gas too low.
  • Errors: contracts revert with typed errors: Unauthorized, NotFound, AlreadyExists, LimitExceeded, InvalidArgument(string), InvalidStatus, Sanctioned(address), AccountFrozen(address), KYCRequired(address), AccreditedRequired(address), JurisdictionDenied(address), InsufficientBalance, Paused and ZeroAmount.

Indexing

Every state change emits an event. There is no hidden state to reconstruct. The core events are listed at the end of each system's page (Identity, RWA token, Offerings, AssetHub). Ids are 1-indexed, and short strings such as jurisdictions, asset classes, units and device types are left-aligned bytes32.

Integrating a protocol

If your contract will hold RWA units (a pool, vault or market):

  1. Ask each token's admin to call setVenue(yourContract, true).
  2. If your contract can claim dividends and pass them to depositors, ask for setVenueDividends(yourContract, true) and call claimDividends() from your contract.
  3. Expect transfers to ineligible users to revert, and surface canReceive in your UI.
  4. After maturity, your contract can still send units to eligible holders; design withdrawals around that.

Running keepers

Call Offering.processAll(n) (or process(ids) with ids from isDue) and RWAToken.checkMaturity(). Both are permissionless and never revert for items that have nothing due.

Local development

make local                    # anvil + deploy + smoke (+ DEX if checked out alongside)
make local-demo               # seed demo issuers, investors, offerings, devices and readings
make portal-dev               # this portal on http://localhost:3002 with dev wallets

The dev wallet offers the anvil accounts in the roles the demo seed gives them (authority, issuer, registrar, investors, meter operator, oracle). No private keys reach the browser.