# Quickstart Guide for Circles SDK

This guide explains how to use the latest `@aboutcircles` packages to build a browser-ready Circles dApp. Follow the steps to move from wallet prerequisites to a fully initialised `Sdk` instance capable of handling avatar reads, trust writes, transfers, profile updates, and the auxiliary helper surfaces exposed in v2.

### 1. Prerequisites

* Browser wallet such as MetaMask or Rabby.
* Gnosis Chain (chain ID `100`) configured inside the wallet. Double-check the RPC endpoint, currency symbol (`xDAI`), and block explorer entries via the [Gnosis Chain docs](https://docs.gnosischain.com/).
* A small amount of xDAI for gas (available from the [mainnet faucet](https://gnosisfaucet.com/)).

Keep the wallet unlocked in the same browser context that will load your dApp so the runner can interact to `window.ethereum`.

### 2. Install the Circles SDK Packages

```bash
npm i @aboutcircles/sdk \
      @aboutcircles/sdk-core \
      @aboutcircles/sdk-types \
      @aboutcircles/sdk-runner \
      @aboutcircles/sdk-rpc \
      @aboutcircles/sdk-transfers \
      @aboutcircles/sdk-pathfinder \
      @aboutcircles/sdk-profiles \
      viem
```

Install whichever modules you plan to import directly. `@aboutcircles/sdk` already depends on the others, but pinning them in your app keeps the versions aligned across bundlers.

* `@aboutcircles/sdk` – high-level surface your UI consumes (avatars, registration, helper namespaces).
* `@aboutcircles/sdk-core` – typed contract wrappers plus `circlesConfig`.
* `@aboutcircles/sdk-types` – shared types including `ContractRunner`, `TransactionRequest`, and avatar data models.
* `@aboutcircles/sdk-runner` – production runners (`SafeContractRunner`, `SafeBrowserRunner`) and error helpers.
* `@aboutcircles/sdk-rpc` – typed JSON-RPC client for balances, trust graphs, pathfinding, transactions, and events.
* `@aboutcircles/sdk-transfers` – `TransferBuilder` orchestration around pathfinding + wrapper management; it leans on…
* `@aboutcircles/sdk-pathfinder` – utilities for flow matrices, wrapper lookups, and path manipulation.
* `@aboutcircles/sdk-profiles` – profile pinning client that the SDK uses internally for metadata updates.
* `viem` – RPC + wallet tooling shared by the runner implementations.

### 3. Import the SDK Building Blocks

```typescript
import { Sdk } from '@aboutcircles/sdk';
import { Core, circlesConfig, type CirclesConfig } from '@aboutcircles/sdk-core';
import type { ContractRunner } from '@aboutcircles/sdk-types';
import { createPublicClient, createWalletClient, custom, http } from 'viem';
import { gnosis } from 'viem/chains';

// Optional modules for lower-level access when you need them
import { CirclesRpc } from '@aboutcircles/sdk-rpc';
import { TransferBuilder } from '@aboutcircles/sdk-transfers';
import { Profiles } from '@aboutcircles/sdk-profiles';
```

* `Sdk` is the primary entry point exposing avatar namespaces (`balances`, `trust`, `transfer`, `profile`, etc.).
* `Core`/`circlesConfig` provide production-ready contract addresses, service URLs, and default RPC endpoints.
* `ContractRunner` defines the interface your signing strategy (EOA, Safe, hardware wallet, …) must satisfy.
* `CirclesRpc`, `TransferBuilder`, and `Profiles` are optional direct imports when you need to bypass the high-level helpers (analytics views, offline tooling, custom flows).
* `viem` primitives make the runner portable across browser wallets and Node environments.

Need multisig support? `@aboutcircles/sdk-runner` exports `SafeContractRunner` (backend) and `SafeBrowserRunner` (front-end Safe Apps). Swap your custom runner with those when you integrate Safe-based flows.

### 4. Choose the Right Network Configuration

#### Production (Gnosis Chain Mainnet)

```typescript
const gnosisMainnetConfig = circlesConfig[100];
```

This object already contains:

* Service URLs: `circlesRpcUrl` (aggregated Circles RPC), `pathfinderUrl`, and `profileServiceUrl`.
* Canonical contract addresses: `v1HubAddress`, `v2HubAddress`, `nameRegistryAddress`, `invitationEscrowAddress`, `baseGroupFactoryAddress`, `baseGroupMintPolicy`, `standardTreasury`, `coreMembersGroupDeployer`, and `liftERC20Address`.
* Metadata used internally by `TransferBuilder`, `CirclesRpc`, and the avatar helpers (so you rarely need to hard-code addresses).

### 5. Build a Browser-Friendly Contract Runner

An EOA runner is ideal for MetaMask/Rabby-style single-signers. The snippet below shows a minimal implementation that satisfies the `ContractRunner` interface with the help of `viem`:

```typescript
import { createPublicClient, createWalletClient, custom, http } from 'viem';
import { gnosis } from 'viem/chains';
import type { Address, TransactionReceipt, TransactionRequest } from '@aboutcircles/sdk-types';

const circlesRPC = 'https://rpc.aboutcircles.com';

export const createBrowserRunner = () => {
  const publicClient = createPublicClient({
    chain: gnosis,
    transport: http(circlesRPC),
  });

  const walletClient = createWalletClient({
    chain: gnosis,
    transport: custom(window.ethereum),
  });

  const runner: ContractRunner = {
    publicClient,
    address: walletClient.account?.address,
    async init() {
      const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' });
      this.address = account as Address;

      const currentChain = await walletClient.getChainId();
      if (currentChain !== gnosis.id) {
        throw new Error('Please switch your wallet to Gnosis Chain (chainId 100).');
      }
    },
    estimateGas: (tx: TransactionRequest) =>
      publicClient.estimateGas({ account: runner.address!, ...tx }),
    call: (tx: TransactionRequest) =>
      publicClient.call({ account: tx.from || runner.address!, ...tx }),
    resolveName: (name: string) => publicClient.getEnsAddress({ name }),
    async sendTransaction(txs: TransactionRequest[]): Promise<TransactionReceipt> {
      if (!runner.address) throw new Error('Runner not initialised. Call init() first.');

      let receipt: TransactionReceipt | undefined;
      for (const tx of txs) {
        const hash = await walletClient.sendTransaction({
          account: runner.address,
          ...tx,
        });
        receipt = await publicClient.waitForTransactionReceipt({ hash });
      }

      if (!receipt) {
        throw new Error('No transactions submitted.');
      }
      return receipt;
    },
  };

  return runner;
};
```

Key behaviors:

* `init()` requests wallet access and enforces the correct chain ID before any on-chain action.
* `sendTransaction()` loops through every `TransactionRequest` emitted by avatar helpers or `TransferBuilder`, ensuring multi-step flows (pathfinding, wrapped transfers, etc.) complete in order.
* Gas estimation, read-only calls, and ENS resolution are delegated to `viem` so you do not need to reinvent RPC plumbing.

Prefer a Safe-based UX? Replace the custom runner with `SafeBrowserRunner.create(rpcUrl, window.ethereum, safeAddress, gnosis)` (or the server-side `SafeContractRunner`) from `@aboutcircles/sdk-runner`. Both satisfy the same interface.

### 6. Tap Into Lower-Level Packages

When you need extra control—analytics dashboards, dry-run tooling, custom transfer flows—instantiate the underlying modules alongside the `Sdk`:

```typescript
import { Core, circlesConfig } from '@aboutcircles/sdk-core';
import { CirclesRpc } from '@aboutcircles/sdk-rpc';
import { TransferBuilder } from '@aboutcircles/sdk-transfers';
import { Profiles } from '@aboutcircles/sdk-profiles';

const config = circlesConfig[100];
const core = new Core(config);
const rpc = new CirclesRpc(config.circlesRpcUrl);
const transferBuilder = new TransferBuilder(core);
const profilesClient = new Profiles(config.profileServiceUrl);
```

* `Core` returns raw transaction requests for HubV2, BaseGroups, Lift ERC-20 wrappers, etc.
* `CirclesRpc` streams balances, trust graphs, profile search results, and transaction history straight from the Circles indexers.
* `TransferBuilder` leverages `@aboutcircles/sdk-pathfinder` to create the ordered transaction list (unwraps, approvals, `operateFlowMatrix`) without sending anything.
* `Profiles` is handy for batch jobs or when you want to pin metadata outside of the avatar helpers.

Reuse the same `config` everywhere to avoid mismatched service URLs.

### 7. Initialise the Circles SDK

```typescript
import { Sdk } from '@aboutcircles/sdk';
import { circlesConfig } from '@aboutcircles/sdk-core';

const runner = createBrowserRunner();
await runner.init();

const sdk = new Sdk(circlesConfig[100], runner); // config defaults to mainnet if omitted

const avatar = await sdk.getAvatar(runner.address!);
const balances = await avatar.balances.getTokenBalances();
const trustGraph = await sdk.data.getTrustRelations(avatar.address);
const demurragedWrapper = await sdk.tokens.getDemurragedWrapper(avatar.address);

const members = sdk.groups.getMembers('0xGroupAddress...');
await members.queryNextPage(); // fetch first page when you need it
```

* Passing `circlesConfig[100]` explicitly removes any ambiguity about the targeted environment.
* Provide your custom (or Safe) runner so avatar helpers can sign and broadcast state-changing transactions. If you leave the runner undefined, the SDK functions remain read-only.
* `sdk.data` exposes RPC-backed helpers for avatars, trust, and balances when you do not need a full avatar instance.
* `sdk.tokens` contains convenience helpers for wrappers and token-holder pagination.
* `sdk.groups` helps explore group treasuries, membership lists, and holder breakdowns without writing direct RPC calls.
* `sdk.profiles` offers direct `create/get` helpers powered by `@aboutcircles/sdk-profiles`.

### 8. End-to-End Setup Example

```typescript
import { Sdk } from '@aboutcircles/sdk';
import { circlesConfig } from '@aboutcircles/sdk-core';
import { createBrowserRunner } from './runner'; // use the helper from section 5

async function bootstrapCircles() {
  const runner = createBrowserRunner();
  await runner.init();

  const sdk = new Sdk(circlesConfig[100], runner);
  const avatar = await sdk.getAvatar(runner.address!);

  console.log(await avatar.profile.get());

  const trustGraph = await sdk.data.getTrustRelations(avatar.address);
  console.log(`Trustees: ${trustGraph.length}`);

  const topHolders = sdk.tokens.getHolders(avatar.address, 3);
  await topHolders.queryNextPage();
  console.log('Top holders', topHolders.currentPage?.results ?? []);
}

bootstrapCircles().catch(console.error);
```

This pattern maps cleanly to a React `useEffect`, a Next.js server action (with a server-side runner), or a plain script.

### 9. Choosing SDK Surfaces

Pick the surfaces that match your UX:

* **HumanAvatar / OrganisationAvatar / BaseGroupAvatar** – mint issuance, manage trust, transfer CRC, wrap/unwrap, and maintain profiles with type-specific helpers.
* **`sdk.register`** – onboard new humans, organisations, and base groups while handling invitation escrows and profile pinning.
* **`sdk.data`** – lightweight RPC views for trust graphs, balances, and avatar metadata (great for dashboards).
* **`sdk.tokens`** – wrapper lookups plus cursor-based holder queries for ERC1155/ERC20 representations.
* **`sdk.groups`** – fetch group members, treasury balances, and holder distributions without juggling contracts manually.
* **`sdk.profiles`** – talk to the profile service directly when you need to pin/update metadata outside avatar flows.

Decide which combos your application needs up front so you can import only the modules you plan to expose.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aboutcircles.com/circles-sdk/getting-started-with-the-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
