app.gainforest.wallet.primary

gainforest.earth

Schema Diff

+9 -1

From

CID
bafyreiaelezzvhs...
Indexed At
2026-07-17 15:04 UTC
View this version

To

CID
bafyreibqn5w6rbd...
Indexed At
2026-07-17 20:17 UTC
View this version

Compatibility Analysis

Backward Compatible

Backward compatible. 5 non-breaking changes.

Non-Breaking Changes (5)
  • AddedVertex AddedVertex { vertex_id: "app.gainforest.wallet.primary:body.addedSigners" }
  • AddedVertex AddedVertex { vertex_id: "app.gainforest.wallet.primary:body.addedSigners:items" }
  • AddedEdge AddedEdge { src: "app.gainforest.wallet.primary:body", tgt: "app.gainforest.wallet.primary:body.addedSigners", kind: "prop", name: Some("addedSigners") }
  • AddedEdge AddedEdge { src: "app.gainforest.wallet.primary:body.addedSigners", tgt: "app.gainforest.wallet.primary:body.addedSigners:items", kind: "items", name: None }
  • AddedEdge AddedEdge { src: "app.gainforest.wallet.primary:body.addedSigners:items", tgt: "app.gainforest.wallet.primary#passkeySigner", kind: "ref", name: None }

Migration Guidance

Added Elements

  • AddedVertex { vertex_id: "app.gainforest.wallet.primary:body.addedSigners" }
  • AddedVertex { vertex_id: "app.gainforest.wallet.primary:body.addedSigners:items" }

Additional Notes

  • Non-breaking: AddedEdge { src: "app.gainforest.wallet.primary:body", tgt: "app.gainforest.wallet.primary:body.addedSigners", kind: "prop", name: Some("addedSigners") }
  • Non-breaking: AddedEdge { src: "app.gainforest.wallet.primary:body.addedSigners", tgt: "app.gainforest.wallet.primary:body.addedSigners:items", kind: "items", name: None }
  • Non-breaking: AddedEdge { src: "app.gainforest.wallet.primary:body.addedSigners:items", tgt: "app.gainforest.wallet.primary#passkeySigner", kind: "ref", name: None }
1 1
{
2 2
  "id": "app.gainforest.wallet.primary",
3 3
  "defs": {
4 4
    "main": {
5 5
      "key": "literal:self",
6 6
      "type": "record",
7 7
      "record": {
8 8
        "type": "object",
9 9
        "required": [
10 10
          "address",
11 11
          "factory",
12 12
          "chainId",
13 13
          "owner",
14 14
          "threshold",
15 15
          "saltScheme",
16 16
          "signers",
17 17
          "createdAt"
18 18
        ],
19 19
        "properties": {
20 20
          "name": {
21 21
            "type": "string",
22 22
            "maxLength": 800,
23 23
            "description": "Plain-language wallet label.",
24 24
            "maxGraphemes": 80
25 25
          },
26 26
          "owner": {
27 27
            "type": "string",
28 28
            "description": "The vault's Ownable superuser slot. Always the zero address: only the signer set controls the vault."
29 29
          },
30 30
          "address": {
31 31
            "type": "string",
32 32
            "description": "Predicted deterministic vault address (0x…, 20 bytes)."
33 33
          },
34 34
          "chainId": {
35 35
            "type": "integer",
36 36
            "description": "EVM chain id the donation flow settles on (the address is identical on every chain where the factory is deployed)."
37 37
          },
38 38
          "factory": {
39 39
            "type": "string",
40 40
            "description": "SmartVaultFactory address the prediction was made against."
41 41
          },
42 42
          "signers": {
43 43
            "type": "array",
44 44
            "items": {
45 45
              "ref": "#passkeySigner",
46 46
              "type": "ref"
47 47
            },
48 48
            "minLength": 1,
49 -
            "description": "Founding signer set, in derivation order — a CREATE2 input."
49 +
            "description": "Founding signer set, in derivation order — a CREATE2 input, frozen once the vault is deployed."
50 50
          },
51 51
          "createdAt": {
52 52
            "type": "string",
53 53
            "format": "datetime"
54 54
          },
55 55
          "threshold": {
56 56
            "type": "integer",
57 57
            "maximum": 255,
58 58
            "minimum": 1,
59 59
            "description": "Number of distinct passkey approvals required per operation (m-of-n). A CREATE2 input — changing it re-derives the address."
60 60
          },
61 61
          "saltScheme": {
62 62
            "type": "string",
63 63
            "description": "Versioned salt derivation label; the CREATE2 salt is keccak256(saltScheme + ':' + account DID)."
64 +
          },
65 +
          "addedSigners": {
66 +
            "type": "array",
67 +
            "items": {
68 +
              "ref": "#passkeySigner",
69 +
              "type": "ref"
70 +
            },
71 +
            "description": "Passkeys enrolled ON-CHAIN after deployment — a metadata directory only (labels + WebAuthn credential ids). The chain is the authority for which signers are live; append-only, removals need no record change."
64 72
          }
65 73
        }
66 74
      },
67 75
      "description": "An account's canonical donation wallet (personal profile or organization): a Splits SmartVault (ERC-4337 passkey multisig) whose address is derived deterministically with CREATE2 from the account 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 account — the derivation is the proof; no signature is needed. Fixed rkey `self`: one canonical wallet per account. While no code exists at the address and it holds no funds, the signer set and threshold may still change (the address is re-derived); once the vault is deployed on-chain this record is frozen and changes happen on-chain. Succeeds the legacy `app.gainforest.wallet.splitsVault` collection: records are read from both and migrated here on their next write."
68 76
    },
69 77
    "passkeySigner": {
70 78
      "type": "object",
71 79
      "required": [
72 80
        "kind",
73 81
        "publicKeyX",
74 82
        "publicKeyY",
75 83
        "credentialId",
76 84
        "memberDid",
77 85
        "addedAt"
78 86
      ],
79 87
      "properties": {
80 88
        "kind": {
81 89
          "enum": [
82 90
            "passkey"
83 91
          ],
84 92
          "type": "string"
85 93
        },
86 94
        "label": {
87 95
          "type": "string",
88 96
          "maxLength": 800,
89 97
          "description": "Plain-language signer label.",
90 98
          "maxGraphemes": 80
91 99
        },
92 100
        "addedAt": {
93 101
          "type": "string",
94 102
          "format": "datetime"
95 103
        },
96 104
        "memberDid": {
97 105
          "type": "string",
98 106
          "format": "did",
99 107
          "description": "DID of the account member this passkey belongs to."
100 108
        },
101 109
        "publicKeyX": {
102 110
          "type": "string",
103 111
          "description": "32-byte hex, secp256r1 public key X coordinate (SmartVault Signer slot1)."
104 112
        },
105 113
        "publicKeyY": {
106 114
          "type": "string",
107 115
          "description": "32-byte hex, secp256r1 public key Y coordinate (SmartVault Signer slot2)."
108 116
        },
109 117
        "credentialId": {
110 118
          "type": "string",
111 119
          "description": "WebAuthn credential id (base64url) so the member's browser can find the passkey again."
112 120
        }
113 121
      }
114 122
    }
115 123
  },
116 124
  "$type": "com.atproto.lexicon.schema",
117 125
  "lexicon": 1
118 126
}

Compare Other Versions

Lexicon Garden

@