# app.gainforest.wallet.splitsVault

> Published by [gainforest.earth](https://lexicon.garden/identity/did:plc:qoti4acfmc5wg6zzmtix6hse)

✓ This is the authoritative definition for this NSID.

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:plc:qoti4acfmc5wg6zzmtix6hse/app.gainforest.wallet.splitsVault)
- [Documentation](https://lexicon.garden/lexicon/did:plc:qoti4acfmc5wg6zzmtix6hse/app.gainforest.wallet.splitsVault/docs)
- [Examples](https://lexicon.garden/lexicon/did:plc:qoti4acfmc5wg6zzmtix6hse/app.gainforest.wallet.splitsVault/examples)

## Definitions

### `app.gainforest.wallet.splitsVault`

**Type**: `record`

LEGACY — superseded by app.gainforest.wallet.primary; existing records are still read and are migrated to the primary collection on their next write. An organization's shared donation wallet: a Splits SmartVault (ERC-4337 passkey multisig) whose address is derived deterministically with CREATE2 from the organization DID and the founding signer set. Because owner, signers, threshold, and the salt scheme are all recorded here, anyone can recompute SmartVaultFactory.getAddress(...) and verify that `address` really belongs to this organization — the derivation is the proof; no signature is needed. Fixed rkey `self`: one canonical wallet per organization. While no code exists at the address the signer set may still change (the address is re-derived); once the vault is deployed on-chain this record is frozen and signer changes happen on-chain.

**Key**: `literal:self`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | `string` | No | Plain-language wallet label. |
| `owner` | `string` | Yes | The vault's Ownable superuser slot. Always the zero address: only the signer set controls the vault. |
| `address` | `string` | Yes | Predicted deterministic vault address (0x…, 20 bytes). |
| `chainId` | `integer` | Yes | EVM chain id the donation flow settles on (the address is identical on every chain where the factory is deployed). |
| `factory` | `string` | Yes | SmartVaultFactory address the prediction was made against. |
| `signers` | `array` | Yes | Founding signer set, in derivation order — a CREATE2 input. |
| `createdAt` | `string` (datetime) | Yes |  |
| `threshold` | `integer` | Yes | Number of signer approvals required per operation. |
| `saltScheme` | `string` | Yes | Versioned salt derivation label; the CREATE2 salt is keccak256(saltScheme + ':' + organization DID). |

### `app.gainforest.wallet.splitsVault#passkeySigner`

**Type**: `object`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `kind` | `string` | Yes |  |
| `label` | `string` | No | Plain-language signer label. |
| `addedAt` | `string` (datetime) | Yes |  |
| `memberDid` | `string` (did) | Yes | DID of the organization member this passkey belongs to. |
| `publicKeyX` | `string` | Yes | 32-byte hex, secp256r1 public key X coordinate (SmartVault Signer slot1). |
| `publicKeyY` | `string` | Yes | 32-byte hex, secp256r1 public key Y coordinate (SmartVault Signer slot2). |
| `credentialId` | `string` | Yes | WebAuthn credential id (base64url) so the member's browser can find the passkey again. |

## Raw Schema

```json
{
  "id": "app.gainforest.wallet.splitsVault",
  "defs": {
    "main": {
      "key": "literal:self",
      "type": "record",
      "record": {
        "type": "object",
        "required": [
          "address",
          "factory",
          "chainId",
          "owner",
          "threshold",
          "saltScheme",
          "signers",
          "createdAt"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 800,
            "description": "Plain-language wallet label.",
            "maxGraphemes": 80
          },
          "owner": {
            "type": "string",
            "description": "The vault's Ownable superuser slot. Always the zero address: only the signer set controls the vault."
          },
          "address": {
            "type": "string",
            "description": "Predicted deterministic vault address (0x…, 20 bytes)."
          },
          "chainId": {
            "type": "integer",
            "description": "EVM chain id the donation flow settles on (the address is identical on every chain where the factory is deployed)."
          },
          "factory": {
            "type": "string",
            "description": "SmartVaultFactory address the prediction was made against."
          },
          "signers": {
            "type": "array",
            "items": {
              "ref": "#passkeySigner",
              "type": "ref"
            },
            "minLength": 1,
            "description": "Founding signer set, in derivation order — a CREATE2 input."
          },
          "createdAt": {
            "type": "string",
            "format": "datetime"
          },
          "threshold": {
            "type": "integer",
            "minimum": 1,
            "description": "Number of signer approvals required per operation."
          },
          "saltScheme": {
            "type": "string",
            "description": "Versioned salt derivation label; the CREATE2 salt is keccak256(saltScheme + ':' + organization DID)."
          }
        }
      },
      "description": "LEGACY — superseded by app.gainforest.wallet.primary; existing records are still read and are migrated to the primary collection on their next write. An organization's shared donation wallet: a Splits SmartVault (ERC-4337 passkey multisig) whose address is derived deterministically with CREATE2 from the organization DID and the founding signer set. Because owner, signers, threshold, and the salt scheme are all recorded here, anyone can recompute SmartVaultFactory.getAddress(...) and verify that `address` really belongs to this organization — the derivation is the proof; no signature is needed. Fixed rkey `self`: one canonical wallet per organization. While no code exists at the address the signer set may still change (the address is re-derived); once the vault is deployed on-chain this record is frozen and signer changes happen on-chain."
    },
    "passkeySigner": {
      "type": "object",
      "required": [
        "kind",
        "publicKeyX",
        "publicKeyY",
        "credentialId",
        "memberDid",
        "addedAt"
      ],
      "properties": {
        "kind": {
          "enum": [
            "passkey"
          ],
          "type": "string"
        },
        "label": {
          "type": "string",
          "maxLength": 800,
          "description": "Plain-language signer label.",
          "maxGraphemes": 80
        },
        "addedAt": {
          "type": "string",
          "format": "datetime"
        },
        "memberDid": {
          "type": "string",
          "format": "did",
          "description": "DID of the organization member this passkey belongs to."
        },
        "publicKeyX": {
          "type": "string",
          "description": "32-byte hex, secp256r1 public key X coordinate (SmartVault Signer slot1)."
        },
        "publicKeyY": {
          "type": "string",
          "description": "32-byte hex, secp256r1 public key Y coordinate (SmartVault Signer slot2)."
        },
        "credentialId": {
          "type": "string",
          "description": "WebAuthn credential id (base64url) so the member's browser can find the passkey again."
        }
      }
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}
```
