> ## Documentation Index
> Fetch the complete documentation index at: https://docs.raze.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# Funding & Bubblemap

> Funding ancestry, cluster detection, and direct holder transfer edges over GraphQL

The same composable funding primitives that power the REST `/api/sol/funding/*` endpoints, exposed over GraphQL. GraphQL is the preferred surface for **large** wallet sets: REST caps at 150 wallets per request to fit under proxy URL-length limits, while GraphQL takes the same `[String!]!` list in the JSON body with no URL-length constraint. The same per-request work cap (150) still applies inside the resolver.

All five fields share two side effects with their REST twins:

* **`enrichmentEnqueued`**: any wallet without an observed funding row is queued for an async RPC backfill. The next request returns the resolved event (or a terminal `rpc_unresolved` row).
* **CEX noise filter** (`fundingCluster` only): a "cluster" covering more than 50% of the input wallets is treated as a CEX/exchange hot wallet, dropped, and its members demoted to `unclustered`.

***

## `fundingLookup`

For each wallet, returns the first observed inbound SOL funding event.

### Arguments

| Name      | Type         | Required | Description                                   |
| --------- | ------------ | -------- | --------------------------------------------- |
| `wallets` | `[String!]!` | yes      | 1–150 wallet addresses. Duplicates collapsed. |

### Return type

```graphql theme={null}
type FundingLookupResult {
  fundings: [FundingLookupEntry!]!
  missing: [String!]!
  enrichmentEnqueued: [String!]!
}

type FundingLookupEntry {
  wallet: String!
  funding: Funding
}

type Funding {
  funder: String!
  fundedAt: String!     # RFC-3339
  signature: String!
  slot: Int!
  lamports: String!     # u64 as string to avoid JS precision loss
  solAmount: Float!
  source: String!       # "observed" | "rpc_backfilled" | "rpc_unresolved"
}
```

### Example

```graphql theme={null}
query {
  fundingLookup(wallets: ["3ixtZX...", "4wuudp..."]) {
    fundings {
      wallet
      funding { funder fundedAt solAmount source }
    }
    missing
    enrichmentEnqueued
  }
}
```

***

## `fundedBy`

Reverse lookup — for each funder, the wallets it has funded, ordered by `fundedAt` DESC.

### Arguments

| Name      | Type         | Required | Description                                                                                              |
| --------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------- |
| `funders` | `[String!]!` | yes      | 1–150 funder addresses.                                                                                  |
| `limit`   | `Int`        | no       | Per-funder cap. Default `100`, max `1000`.                                                               |
| `before`  | `String`     | no       | Pagination cursor — millisecond timestamp from previous page (passed as a string to avoid Int overflow). |

### Return type

```graphql theme={null}
type FundedByResult {
  funded: [FundedByGroup!]!
}

type FundedByGroup {
  funder: String!
  wallets: [FundedByEdge!]!
  nextCursor: String
  more: Boolean!
}

type FundedByEdge {
  wallet: String!
  fundedAt: String!
  signature: String!
  slot: Int!
  lamports: String!
  solAmount: Float!
  source: String!
}
```

### Example

```graphql theme={null}
query {
  fundedBy(funders: ["FuNdR..."], limit: 200) {
    funded {
      funder
      more
      nextCursor
      wallets { wallet fundedAt solAmount }
    }
  }
}
```

***

## `fundingChain`

Walks funding ancestry up to `depth` levels for each input wallet. One ClickHouse round trip per level (batched across all chain heads).

### Arguments

| Name      | Type         | Required | Description             |
| --------- | ------------ | -------- | ----------------------- |
| `wallets` | `[String!]!` | yes      | 1–150 wallet addresses. |
| `depth`   | `Int`        | no       | 1–10. Default `5`.      |

### Return type

```graphql theme={null}
type FundingChainResult {
  chains: [FundingChainEntry!]!
  enrichmentEnqueued: [String!]!
}

type FundingChainEntry {
  wallet: String!
  steps: [FundingChainStep!]!
}

type FundingChainStep {
  wallet: String!       # this hop's wallet (closest funder first)
  fundedBy: String!
  fundedAt: String!
  signature: String!
  slot: Int!
  lamports: String!
  solAmount: Float!
  source: String!
}
```

The chain stops at a wallet with no observed funder or when `depth` is exceeded.

***

## `fundingCluster`

Groups wallets that share a common funding ancestor within `depth` levels. The single most useful primitive — bubblemap clustering, sniper-farm detection, and "wallets bought from the same dispenser" all reduce to this.

### Arguments

| Name      | Type         | Required | Description             |
| --------- | ------------ | -------- | ----------------------- |
| `wallets` | `[String!]!` | yes      | 1–150 wallet addresses. |
| `depth`   | `Int`        | no       | 1–5. Default `2`.       |

### Return type

```graphql theme={null}
type FundingClusterResult {
  clusters: [FundingCluster!]!
  unclustered: [String!]!
  enrichmentEnqueued: [String!]!
  noiseDropped: Int!     # count of wallets demoted by the CEX noise filter
}

type FundingCluster {
  rootFunder: String!
  depth: Int!
  wallets: [String!]!
}
```

***

## `holderEdges`

Direct user-to-user transfer edges among a wallet set, scoped to one mint. Edges are canonical (`a < b` lex), undirected, and aggregated — repeated transfers between the same pair collapse to one row with a `transfers` count.

### Arguments

| Name      | Type         | Required | Description                   |
| --------- | ------------ | -------- | ----------------------------- |
| `mint`    | `String!`    | yes      | Token mint to scope edges to. |
| `wallets` | `[String!]!` | yes      | 1–150 wallet addresses.       |

### Return type

```graphql theme={null}
type HolderEdgesResult {
  mint: String!
  edges: [HolderEdge!]!
}

type HolderEdge {
  a: String!            # canonical: a < b lex
  b: String!
  kind: String!         # "token" (SPL transfer) | "sol" (native SOL)
  transfers: String!    # u64 as string
  firstSeen: String!
  lastSeen: String!
}
```

### Example: bubblemap one-shot

```graphql theme={null}
query Bubblemap($mint: String!, $wallets: [String!]!) {
  fundingCluster(wallets: $wallets, depth: 3) {
    clusters { rootFunder depth wallets }
    unclustered
  }
  fundingChain(wallets: $wallets, depth: 5) {
    chains { wallet steps { fundedBy solAmount } }
  }
  holderEdges(mint: $mint, wallets: $wallets) {
    edges { a b kind transfers }
  }
}
```

A single round trip pulls every primitive the bubblemap renders.
