For the complete documentation index, see llms.txt. This page is also available as Markdown.

Invitations and Referrals

Use the Circles SDK to spend invite quota that an inviter already holds and register new humans on Circles.

This guide covers two onboarding flows:

  • Existing-wallet users: invite people who already have a Safe wallet.

  • New users: create referral links for people who do not have a wallet yet.

The SDK prepares the required transaction batch. A runner executes that batch atomically through the inviter's Safe. You do not need to call the underlying contracts directly.

Scope This guide assumes that the inviter already has invite quota. For getting quota for your community, please reach out to our team on Telegram.

Overview

The SDK exposes two levels of abstraction:

API
Use it when
Method
Execution behavior

InviteFarm from @aboutcircles/sdk-invitations

You manage transaction execution yourself, use a server relayer, or need to inspect or extend the batch

generateInvites(inviter, invitees) or generateReferrals(inviter, count)

Returns unsigned transactions. You pass them to a runner.

HumanAvatar.invitation from the top-level SDK

You already have a runner-backed HumanAvatar and want a build-and-send flow

avatar.invitation.generateReferrals(count)

Builds and executes the transactions through the avatar's runner.

Prerequisites

Before using InviteFarm, make sure that:

  1. The inviter already has enough quota for the number of invites.

  2. Your configuration includes referralsServiceUrl.

  3. The inviter's Safe has completed the one-time invitation setup.

  4. You have a runner capable of executing the returned transaction array as one atomic Safe batch.

One-time inviter setup

Before the inviter sends their first invitation, their Safe must have the InvitationModule enabled and the required module-organization trust configured.

Use Invitations.ensureInviterSetup(inviter) to generate any missing setup transactions, then execute those transactions once.

Initialize InviteFarm

Create an InviteFarm instance from a CirclesConfig. The config must include referralsServiceUrl, even when you only use farm methods, because InviteFarm internally creates an Invitations instance.

Check available quota

Each quota unit represents one invitation funded with 96 CRC.

Useful helpers:

For batch invitations, validate that the inviter has enough quota for the full batch:

Note A quota check is best-effort. The final debit occurs on-chain when claimInvite() or claimInvites(count) executes. The transaction reverts if the inviter no longer has enough quota.

Invite users who already have a wallet

Use generateInvites for users who already have a Safe wallet but are not yet registered as Circles humans.

The SDK encodes the invitee wallet addresses directly in the transfer data. It does not create accounts for these invitees.

Requirements

  • The invitees array must not be empty.

  • Each invitee must already have a Safe wallet.

  • Each invitee's Safe must already have the InvitationModule enabled. Use the referral flow for brand-new users instead.

Returned transactions

For one invitee, the SDK returns:

For multiple invitees, the SDK returns:

Create referrals for brand-new users

Use generateReferrals for users who do not have a wallet yet.

The SDK creates a temporary keypair for each referral and encodes a ReferralsModule.createAccount() or createAccounts() call. The on-chain flow pre-deploys a claimable Safe for each new user.

generateReferrals returns one referral object per new user:

Store referral secrets securely

Each secret is the only way to claim its corresponding pre-deployed account. Persist every secret and deliver it to the intended user through a referral link or QR code.

Warning If a referral secret is lost, the pre-deployed account cannot be claimed.

How a new user claims a referral

A new user opens a referral link containing the secret and completes the claim flow:

  1. Create a device WebAuthn passkey.

  2. Sign the module's EIP-712 passkey digest with the referral secret.

  3. Relay ReferralsModule.claimAccount(...).

  4. Bind the passkey as the Safe signer.

  5. Receive the 48 CRC welcome bonus.

  6. Complete registration as a self-custodial Circles human with the original inviter recorded as the permanent inviter.

The claim call has the following shape:

Use the high-level referral API

When you already have a runner-backed HumanAvatar, use the high-level API to generate and execute referrals in one call:

The high-level facade also exposes:

For single-invite flows, it also provides:

Execute invitation transactions atomically

Both generateInvites and generateReferrals return exactly two transactions:

Always pass the complete array to a runner in a single call:

Use a runner from @aboutcircles/sdk-runner:

  • SafeContractRunner for server-side execution with a private key.

  • SafeBrowserRunner for browser-wallet execution.

Important Do not send claimTx and transferTx separately. During the claim, the funding bot grants the inviter temporary trust that is valid only for the current block. The InvitationModule checks that trust when the borrowed CRC arrives. If the transactions are split across blocks, the transfer reverts with TrustRequired.

How InviteFarm builds the batch

For every generateInvites or generateReferrals call, InviteFarm performs the following steps:

1. Simulate the claim

The SDK calls simulateClaim(inviter, count), which runs an eth_call for claimInvite() or claimInvites(count) with from: inviter.

This simulation determines which farm-bot token IDs will be allocated. The IDs must be known before execution because a Safe batch cannot pass the runtime return value of claimInvites() into the next transfer call.

Allocation is deterministic from the current chain state, so the simulated IDs match the real claim unless a competing claim changes the state first.

2. Generate referral secrets when needed

For referral flows, the SDK generates one { secret, signer } pair per new user.

3. Build the two transactions

The SDK creates:

Each transfer sends 96 CRC per invitation from the inviter to the InvitationModule.

The transfer data depends on the onboarding flow:

Flow
Encoded transfer data

Existing-wallet user

encodeAbiParameters(['address'], [invitee]) or encodeAbiParameters(['address[]'], [invitees])

New-user referral

encodeAbiParameters(['address', 'bytes'], [referralsModule, createAccount(s)(signers).data])

4. Return the batch

The SDK returns:

On-chain result

For each successful invitation:

  • The inviter's quota decreases by one.

  • The farm bot's 96 CRC funds registration and is returned to the bot.

  • The new human is registered with the original inviter recorded as the permanent inviter.

API reference

InviteFarm

Package: @aboutcircles/sdk-invitations

config must include referralsServiceUrl.

generateInvites

generateReferrals

HumanAvatar.invitation

High-level, runner-backed facade:

Runner execution

Package: @aboutcircles/sdk-runner

Available Safe runners:

Referral storage

Persist and retrieve referral secrets through the top-level SDK:

Errors and troubleshooting

Error or symptom
Cause
Resolution

INVITATION_INVALID_COUNT

count <= 0 or the invitee array is empty

Pass at least one referral or invitee.

TrustRequired

claimTx and transferTx were sent separately

Execute the complete transactions array through one runner.sendTransaction(transactions) call.

ExceedsInviteQuota

The inviter does not have enough quota when the batch executes

Check getQuota(inviter) before generating the batch and retry with a smaller batch or after quota is added.

FarmIsDrained

The invitation farm does not have enough capacity

Retry after the farm has capacity.

InviteFarm cannot be constructed

referralsServiceUrl is missing from the config

Add referralsServiceUrl to the CirclesConfig.

Referral account cannot be claimed

The referral secret was not stored or was lost

Persist every secret immediately after generating referrals.

Implementation checklist

Before shipping an invitation flow, verify that:

  • The inviter has completed one-time setup.

  • The inviter has enough quota for the requested batch.

  • Existing-wallet users go through generateInvites.

  • New users go through generateReferrals.

  • Referral secrets are persisted immediately.

  • The full [claimTx, transferTx] array is executed in one runner call.

  • Errors such as ExceedsInviteQuota, FarmIsDrained, and TrustRequired are surfaced clearly to users.

Last updated

Was this helpful?