app.gainforest.wallet.pendingSend

gainforest.earth

{
  "id": "app.gainforest.wallet.pendingSend",
  "defs": {
    "main": {
      "key": "literal:self",
      "type": "record",
      "record": {
        "type": "object",
        "required": [
          "token",
          "to",
          "amountUnits",
          "userOp",
          "hash",
          "lightHash",
          "threshold",
          "approvals",
          "createdBy",
          "createdAt"
        ],
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient address (0x…, 20 bytes). Redundant with callData, for display; the server re-derives it from the operation."
          },
          "hash": {
            "type": "string",
            "description": "Full EntryPoint v0.7 userOp hash — signed by the final approver."
          },
          "token": {
            "enum": [
              "ETH",
              "USDC",
              "USDT"
            ],
            "type": "string",
            "description": "What is being sent."
          },
          "userOp": {
            "ref": "#userOp",
            "type": "ref"
          },
          "approvals": {
            "type": "array",
            "items": {
              "ref": "#approval",
              "type": "ref"
            },
            "description": "Light-hash approvals collected so far, in signing order (at most threshold − 1; the final approval is never stored)."
          },
          "createdAt": {
            "type": "string",
            "format": "datetime"
          },
          "createdBy": {
            "type": "string",
            "format": "did",
            "description": "DID of the signed-in account that started the transfer."
          },
          "lightHash": {
            "type": "string",
            "description": "SmartVault light userOp hash — signed by every earlier approver."
          },
          "threshold": {
            "type": "integer",
            "maximum": 255,
            "minimum": 2,
            "description": "Approval requirement of the wallet when this transfer was started; a mismatch with the current wallet invalidates the transfer."
          },
          "amountUnits": {
            "type": "string",
            "description": "Raw token units as a decimal string. Redundant with callData, for display."
          }
        }
      },
      "description": "A transfer from the account's donation wallet (app.gainforest.wallet.primary) that still needs more passkey approvals. Multi-approval wallets (threshold > 1) collect approvals asynchronously: the initiator stores the exact unsigned ERC-4337 UserOperation here together with their own approval, remaining passkey holders approve from their own devices, and the final approver signs the full userOp hash which submits the operation on-chain and deletes this record. Every stored approval is a WebAuthn assertion over the operation's LIGHT hash (the SmartVault scheme where all but the last signer sign a gas-bounded subset of the operation). Approvals are verified off-chain before being stored and re-verified before submission, so a hand-crafted record cannot forge or brick a transfer. Fixed rkey `self`: one pending transfer per wallet at a time."
    },
    "userOp": {
      "type": "object",
      "required": [
        "sender",
        "nonce",
        "callData",
        "callGasLimit",
        "verificationGasLimit",
        "preVerificationGas",
        "maxFeePerGas",
        "maxPriorityFeePerGas"
      ],
      "properties": {
        "nonce": {
          "type": "string",
          "description": "EntryPoint nonce at preparation time; consumed nonces invalidate the transfer."
        },
        "sender": {
          "type": "string",
          "description": "The wallet's vault address."
        },
        "factory": {
          "type": "string",
          "description": "SmartVaultFactory address — present only while the vault is undeployed."
        },
        "callData": {
          "type": "string",
          "description": "vault.execute(...) calldata — exactly one ETH/USDC/USDT transfer."
        },
        "factoryData": {
          "type": "string",
          "description": "createAccount calldata deploying the vault on first send."
        },
        "callGasLimit": {
          "type": "string"
        },
        "maxFeePerGas": {
          "type": "string"
        },
        "preVerificationGas": {
          "type": "string"
        },
        "maxPriorityFeePerGas": {
          "type": "string"
        },
        "verificationGasLimit": {
          "type": "string"
        }
      },
      "description": "The unsigned ERC-4337 v0.7 UserOperation, exactly as it will be submitted. Gas and fee fields are decimal strings."
    },
    "approval": {
      "type": "object",
      "required": [
        "credentialId",
        "authenticatorData",
        "clientDataJSON",
        "challengeIndex",
        "typeIndex",
        "r",
        "s",
        "addedBy",
        "addedAt"
      ],
      "properties": {
        "r": {
          "type": "string",
          "description": "secp256r1 signature r, decimal string."
        },
        "s": {
          "type": "string",
          "description": "secp256r1 signature s (low-s), decimal string."
        },
        "addedAt": {
          "type": "string",
          "format": "datetime"
        },
        "addedBy": {
          "type": "string",
          "format": "did",
          "description": "DID of the signed-in account that added this approval."
        },
        "typeIndex": {
          "type": "integer",
          "description": "Index of \"type\" in clientDataJSON."
        },
        "credentialId": {
          "type": "string",
          "description": "WebAuthn credential id of the enrolled signer that approved."
        },
        "challengeIndex": {
          "type": "integer",
          "description": "Index of \"challenge\" in clientDataJSON."
        },
        "clientDataJSON": {
          "type": "string",
          "description": "Client data JSON of the assertion."
        },
        "authenticatorData": {
          "type": "string",
          "description": "Authenticator data of the assertion, hex."
        }
      },
      "description": "A WebAuthn assertion over the light userOp hash by one enrolled passkey signer."
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}

Validate Record

Validate a record against app.gainforest.wallet.pendingSend

Validation Options
Treat any remaining unresolved references as valid

Metadata

DID
did:plc:qoti4acfmc5wg6zzmtix6hse
CID
bafyreifbn4qtg4nu5k7z62hktlcwf3bsqsdrx74rsnzxvbagj2ijhoo6kq
Indexed At
2026-07-17 15:04 UTC
AT-URI
at://did:plc:qoti4acfmc5wg6zzmtix6hse/com.atproto.lexicon.schema/app.gainforest.wallet.pendingSend

Lexicon Garden

@