Skip to main content

Circles: UBI Protocol

The Simple Way
var client = new RpcClient(new Uri("https://rpc.aboutcircles.com/"));
var getTotalBalance = new GetTotalBalanceV2(client);
string balance = await getTotalBalance.SendRequestAsync(avatarAddress);

Query Circles balances and transaction history through the dedicated Circles RPC endpoint — no contract ABI needed.

Circles is a decentralized Universal Basic Income protocol running on Gnosis Chain. Every registered participant ("avatar") receives 1 CRC token per hour, with balances subject to ~7% annual demurrage (time-value decay). Tokens can be transferred through trust networks — you can only send your CRC to someone who trusts you. Nethereum's Nethereum.Circles package provides both contract services for on-chain operations and custom RPC methods for data queries.

dotnet add package Nethereum.Circles

Query Balances

The Circles RPC endpoint (rpc.aboutcircles.com) exposes custom methods beyond standard Ethereum RPC. The simplest way to check a balance is through the V2 RPC:

using Nethereum.JsonRpc.Client;
using Nethereum.Circles.RPC.Requests;

var client = new RpcClient(new Uri("https://rpc.aboutcircles.com/"));

var getTotalBalanceV2 = new GetTotalBalanceV2(client);
string balance = await getTotalBalanceV2.SendRequestAsync("0xAvatarAddress");
Console.WriteLine($"Total CRC Balance: {balance}");

This returns the total balance across all Circles token types the avatar holds — their personal CRC plus any group currencies they've received.

Interact with the Hub Contract

The Hub is the central Circles contract that manages avatar registration, trust relationships, and token minting. Use HubService for on-chain operations:

using Nethereum.Web3;
using Nethereum.Circles.Contracts.Hub;

var web3 = new Web3("https://rpc.aboutcircles.com/");
var hubAddress = "0xc12C1E50ABB450d6205Ea2C3Fa861b3B834d13e8"; // Gnosis Chain V2

var hubService = new HubService(web3, hubAddress);

// Check if an address is registered as a human avatar
bool isHuman = await hubService.IsHumanQueryAsync("0xSomeAddress");

// Check trust between two addresses
bool isTrusted = await hubService.IsTrustedQueryAsync("0xTruster", "0xTrustee");

// Calculate pending CRC issuance for a human avatar
var issuance = await hubService.CalculateIssuanceQueryAsync("0xHumanAddress");

The IsHumanQueryAsync and IsTrustedQueryAsync calls are read-only — no gas needed. CalculateIssuanceQueryAsync returns how much CRC has accumulated since the avatar's last mint.

Mint Personal CRC

Minting claims the CRC that has accumulated since your last mint. Circles avatars typically use a Gnosis Safe wallet, so minting goes through Safe execution:

using Nethereum.Web3.Accounts;
using Nethereum.GnosisSafe;
using Nethereum.Circles.Contracts.Hub;

var privateKey = "0xYOUR_PRIVATE_KEY";
var safeAddress = "0xYOUR_SAFE_ADDRESS";

var web3 = new Web3(new Account(privateKey), "https://rpc.aboutcircles.com/");
var hubService = new HubService(web3, hubAddress);

// Route Hub transactions through the Safe
hubService.ChangeContractHandlerToSafeExecTransaction(safeAddress, privateKey);

// Mint accumulated CRC
await hubService.PersonalMintRequestAndWaitForReceiptAsync();

The ChangeContractHandlerToSafeExecTransaction extension method from Nethereum.GnosisSafe wraps the mint call in a Safe transaction — the Safe is the registered avatar, not the EOA. See the Gnosis Safe guide for more on this pattern.

Query Transaction History

The Circles RPC provides paginated transaction history without needing to scan event logs:

using Nethereum.Circles.RPC.Requests;

var client = new RpcClient(new Uri("https://rpc.aboutcircles.com/"));
var historyQuery = new GetTransactionHistoryQuery(client);

// Get first page (100 results)
var transactions = await historyQuery.SendRequestAsync("0xAvatarAddress", 100);

foreach (var tx in transactions.Response)
{
Console.WriteLine($"Hash: {tx.TransactionHash}");
Console.WriteLine($" From: {tx.From} → To: {tx.To}");
Console.WriteLine($" Value: {tx.Value}");
}

// Get next page
var nextPage = await historyQuery.MoveNextPageAsync(transactions);

The pagination is cursor-based — MoveNextPageAsync uses the cursor from the previous response to fetch the next page.

Query Trust Relationships

Trust is the foundation of Circles — you can only receive someone's personal CRC if you trust them. Query trust relationships:

var trustQuery = new GetTrustRelationsQuery(client);

var relations = await trustQuery.SendRequestAsync("0xAvatarAddress", 20);

foreach (var relation in relations.Response)
{
Console.WriteLine($"Truster: {relation.Truster} → Trustee: {relation.Trustee}");
}

Get Avatar Info

Query metadata about a Circles avatar:

var avatarInfo = new GetAvatarInfoQuery(client);
var info = await avatarInfo.SendRequestAsync("0xAvatarAddress");

This returns the avatar's name, type (human, organization, group), and associated token information.

Contract Addresses

ContractNetworkAddress
Hub V2Gnosis Chain0xc12C1E50ABB450d6205Ea2C3Fa861b3B834d13e8
RPC EndpointGnosis Chainhttps://rpc.aboutcircles.com/
RPC EndpointChiado Testnethttps://chiado-rpc.aboutcircles.com

Token Types

Circles has two ERC-20 token representations:

Token TypeServiceDescription
DemurrageDemurrageCirclesServiceBalances decrease ~7%/year — represents "real" purchasing power
InflationaryInflationaryCirclesServiceNominal balance stays constant — minted amount increases over time

Both are ERC-20 compatible wrappers around the same underlying Circles balance. Most applications use the demurrage representation.

Next Steps