types.ts raw

   1  import {
   2    BellIcon,
   3    CirclePlusIcon,
   4    CrownIcon,
   5    HandCoinsIcon,
   6    InfoIcon,
   7    LucideIcon,
   8    NotebookTabsIcon,
   9    PenLineIcon,
  10    SearchIcon,
  11    WalletMinimalIcon,
  12  } from "lucide-react";
  13  
  14  export type BackendType = "LND" | "LDK" | "PHOENIX" | "CASHU" | "CLN" | "BARK";
  15  
  16  export type Nip47RequestMethod =
  17    | "get_info"
  18    | "get_balance"
  19    | "get_budget"
  20    | "make_invoice"
  21    | "pay_invoice"
  22    | "pay_keysend"
  23    | "lookup_invoice"
  24    | "list_transactions"
  25    | "sign_message"
  26    | "multi_pay_invoice"
  27    | "multi_pay_keysend"
  28    | "make_hold_invoice"
  29    | "settle_hold_invoice"
  30    | "cancel_hold_invoice";
  31  
  32  export type BudgetRenewalType =
  33    | "daily"
  34    | "weekly"
  35    | "monthly"
  36    | "yearly"
  37    | "never"
  38    | "";
  39  
  40  export type Scope =
  41    | "pay_invoice" // also used for pay_keysend, multi_pay_invoice, multi_pay_keysend
  42    | "get_balance"
  43    | "get_info"
  44    | "make_invoice"
  45    | "lookup_invoice"
  46    | "list_transactions"
  47    | "sign_message"
  48    | "notifications" // covers all notification types
  49    | "superuser";
  50  
  51  export type Nip47NotificationType = "payment_received" | "payment_sent";
  52  
  53  export type ScopeIconMap = {
  54    [key in Scope]: LucideIcon;
  55  };
  56  
  57  export const scopeIconMap: ScopeIconMap = {
  58    get_balance: WalletMinimalIcon,
  59    get_info: InfoIcon,
  60    list_transactions: NotebookTabsIcon,
  61    lookup_invoice: SearchIcon,
  62    make_invoice: CirclePlusIcon,
  63    pay_invoice: HandCoinsIcon,
  64    sign_message: PenLineIcon,
  65    notifications: BellIcon,
  66    superuser: CrownIcon,
  67  };
  68  
  69  export type WalletCapabilities = {
  70    methods: Nip47RequestMethod[];
  71    scopes: Scope[];
  72    notificationTypes: Nip47NotificationType[];
  73  };
  74  
  75  export const validBudgetRenewals: BudgetRenewalType[] = [
  76    "daily",
  77    "weekly",
  78    "monthly",
  79    "yearly",
  80    "never",
  81  ];
  82  
  83  // Scopes granted to a read-only connection: receive payments and view
  84  // balance/history, but never send/spend.
  85  export const READ_ONLY_SCOPES: Scope[] = [
  86    "get_balance",
  87    "get_info",
  88    "make_invoice",
  89    "lookup_invoice",
  90    "list_transactions",
  91    "notifications",
  92  ];
  93  
  94  export const scopeDescriptions: Record<Scope, string> = {
  95    get_balance: "Read your balance",
  96    get_info: "Read your node info",
  97    list_transactions: "Read transaction history",
  98    lookup_invoice: "Lookup status of invoices",
  99    make_invoice: "Create invoices",
 100    pay_invoice: "Send payments",
 101    sign_message: "Sign messages",
 102    notifications: "Receive wallet notifications",
 103    superuser: "Create other app connections",
 104  };
 105  
 106  export const expiryOptions: Record<string, number> = {
 107    "1 week": 7,
 108    "1 month": 30,
 109    "1 year": 365,
 110  };
 111  
 112  export const budgetOptionsSat: Record<string, number> = {
 113    "10k": 10_000,
 114    "100k": 100_000,
 115    "1M": 1_000_000,
 116  };
 117  
 118  export interface ErrorResponse {
 119    message: string;
 120  }
 121  
 122  export interface App {
 123    id: number;
 124    name: string;
 125    description: string;
 126    appPubkey: string;
 127    uniqueWalletPubkey: boolean;
 128    walletPubkey: string;
 129    createdAt: string;
 130    updatedAt: string;
 131    lastUsedAt?: string;
 132    lastSettledTransactionAt?: string;
 133    expiresAt?: string;
 134    isolated: boolean;
 135    balanceSat: number;
 136    balanceMsat: number;
 137  
 138    scopes: Scope[];
 139    maxAmountSat: number;
 140    maxAmountMsat: number;
 141    budgetUsageSat: number;
 142    budgetUsageMsat: number;
 143    budgetRenewal: BudgetRenewalType;
 144    metadata?: AppMetadata;
 145  }
 146  
 147  export interface AppPermissions {
 148    scopes: Scope[];
 149    maxAmountSat: number;
 150    budgetRenewal: BudgetRenewalType;
 151    expiresAt?: Date;
 152    isolated: boolean;
 153  }
 154  
 155  export interface InfoResponse {
 156    backendType: BackendType;
 157    setupCompleted: boolean;
 158    oauthRedirect: boolean;
 159    albyAccountConnected: boolean;
 160    ldkVssEnabled: boolean;
 161    ldkVssUrl: string;
 162    vssSupported: boolean;
 163    databaseType: string;
 164    running: boolean;
 165    albyAuthUrl: string;
 166    nextBackupReminder: string;
 167    albyUserIdentifier: string;
 168    network?: Network;
 169    version: string;
 170    relays: { url: string; online: boolean }[];
 171    unlocked: boolean;
 172    enableAdvancedSetup: boolean;
 173    startupState: string;
 174    startupError: string;
 175    startupErrorTime: string;
 176    autoUnlockPasswordSupported: boolean;
 177    autoUnlockPasswordEnabled: boolean;
 178    nip07AuthEnabled: boolean;
 179    currency: string;
 180    nodeAlias: string;
 181    mempoolUrl: string;
 182    bitcoinDisplayFormat: BitcoinDisplayFormat;
 183    chainDataSourceType?: string;
 184    chainDataSourceAddress?: string;
 185    jitChannelsLiquiditySource?: string;
 186    jitChannelsMinPaymentSizeMsat?: number;
 187    jitChannelsMaxPaymentSizeMsat?: number;
 188    jitChannelsEnabled: boolean;
 189    hideUpdateBanner: boolean;
 190    supportsBolt12: boolean;
 191    nodeMigrationFileCreated: boolean;
 192  }
 193  
 194  export type BitcoinDisplayFormat = "sats" | "bip177";
 195  
 196  export type HealthAlarmKind =
 197    | "alby_service"
 198    | "node_not_ready"
 199    | "channels_offline"
 200    | "nostr_relay_offline"
 201    | "vss_no_subscription";
 202  
 203  export type HealthAlarm = {
 204    kind: HealthAlarmKind;
 205    rawDetails?: unknown;
 206  };
 207  export type AlbyInfoIncident = {
 208    name: string;
 209    started: string;
 210    status: string;
 211    impact: string;
 212    url: string;
 213  };
 214  
 215  export type HealthResponse = {
 216    alarms: HealthAlarm[];
 217  };
 218  
 219  export type Network = "bitcoin" | "testnet" | "signet";
 220  
 221  export type AppMetadata = {
 222    app_store_app_id?: string;
 223    lud16?: string;
 224  } & Record<string, unknown>;
 225  
 226  export type AutoSwapConfig = {
 227    type: "out";
 228    enabled: boolean;
 229    balanceThresholdSat: number;
 230    swapAmountSat: number;
 231    destination: string;
 232  };
 233  
 234  export type SwapInfo = {
 235    albyServiceFee: number;
 236    boltzServiceFee: number;
 237    boltzNetworkFeeSat: number;
 238    minAmountSat: number;
 239    maxAmountSat: number;
 240  };
 241  
 242  export type BaseSwap = {
 243    id: string;
 244    sendAmountSat: number;
 245    lockupAddress: string;
 246    paymentHash: string;
 247    invoice: string;
 248    autoSwap: boolean;
 249    usedXpub: boolean;
 250    boltzPubkey: string;
 251    createdAt: string;
 252    updatedAt: string;
 253    lockupTxId?: string;
 254    claimTxId?: string;
 255    receiveAmountSat?: number;
 256  };
 257  
 258  export type SwapIn = BaseSwap & {
 259    type: "in";
 260    state: "PENDING" | "SUCCESS" | "FAILED" | "REFUNDED";
 261    refundAddress?: string;
 262  };
 263  
 264  export type SwapOut = BaseSwap & {
 265    type: "out";
 266    state: "PENDING" | "SUCCESS" | "FAILED";
 267    destinationAddress: string;
 268  };
 269  
 270  export type Swap = SwapIn | SwapOut;
 271  
 272  export type SwapResponse = {
 273    swapId: string;
 274    paymentHash: string;
 275  };
 276  
 277  export interface MnemonicResponse {
 278    mnemonic: string;
 279  }
 280  
 281  export interface CreateAppRequest {
 282    name: string;
 283    pubkey?: string;
 284    maxAmountSat?: number;
 285    maxAmountMsat?: number;
 286    budgetRenewal?: BudgetRenewalType;
 287    expiresAt?: string;
 288    scopes: Scope[];
 289    returnTo?: string;
 290    isolated?: boolean;
 291    metadata?: AppMetadata;
 292    unlockPassword?: string; // required to create superuser apps
 293  }
 294  
 295  export interface CreateAppResponse {
 296    id: number;
 297    name: string;
 298    pairingUri: string;
 299    pairingPublicKey: string;
 300    pairingSecretKey: string;
 301    relayUrls: string[];
 302    walletPubkey: string;
 303    lud16: string;
 304    returnTo: string;
 305  }
 306  
 307  export type UpdateAppRequest = {
 308    name?: string;
 309    maxAmountSat?: number;
 310    maxAmountMsat?: number;
 311    budgetRenewal?: string;
 312    expiresAt?: string | undefined;
 313    updateExpiresAt?: boolean;
 314    scopes?: Scope[];
 315    metadata?: AppMetadata;
 316    isolated?: boolean;
 317  };
 318  
 319  export type Channel = {
 320    localBalanceSat: number;
 321    localBalanceMsat: number;
 322    localSpendableBalanceSat: number;
 323    localSpendableBalanceMsat: number;
 324    remoteBalanceSat: number;
 325    remoteBalanceMsat: number;
 326    remotePubkey: string;
 327    id: string;
 328    fundingTxId: string;
 329    fundingTxVout: number;
 330    active: boolean;
 331    public: boolean;
 332    confirmations?: number;
 333    confirmationsRequired?: number;
 334    forwardingFeeBaseMsat: number;
 335    forwardingFeeProportionalMillionths: number;
 336    unspendablePunishmentReserveSat: number;
 337    counterpartyUnspendablePunishmentReserveSat: number;
 338    error?: string;
 339    status: "online" | "opening" | "offline";
 340    isOutbound: boolean;
 341  };
 342  
 343  export type UpdateChannelRequest = {
 344    forwardingFeeBaseMsat: number;
 345  };
 346  
 347  export type Peer = {
 348    nodeId: string;
 349    address: string;
 350    isPersisted: boolean;
 351    isConnected: boolean;
 352  };
 353  
 354  export type NodeConnectionInfo = {
 355    pubkey: string;
 356    address: string;
 357    port: number;
 358  };
 359  
 360  export type ConnectPeerRequest = {
 361    pubkey: string;
 362    address: string;
 363    port: number;
 364  };
 365  
 366  export type SignMessageRequest = {
 367    message: string;
 368  };
 369  
 370  export type SignMessageResponse = {
 371    message: string;
 372    signature: string;
 373  };
 374  
 375  export type PayInvoiceResponse = Transaction;
 376  
 377  export type CreateOfferRequest = {
 378    description: string;
 379  };
 380  
 381  export type CreateInvoiceRequest = {
 382    amountSat?: number;
 383    amountMsat?: number;
 384    description: string;
 385    toAppId?: number;
 386  };
 387  
 388  export type PayInvoiceRequest = {
 389    amountSat?: number;
 390    amountMsat?: number;
 391    metadata?: Record<string, unknown>;
 392    fromAppId?: number;
 393  };
 394  
 395  export type OpenChannelRequest = {
 396    pubkey: string;
 397    amountSats: number;
 398    public: boolean;
 399  };
 400  
 401  export type OpenChannelResponse = {
 402    fundingTxId: string;
 403  };
 404  
 405  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
 406  export type CloseChannelResponse = {};
 407  
 408  export type PendingBalancesDetails = {
 409    channelId: string;
 410    nodeId: string;
 411    amountSat: number;
 412    fundingTxId: string;
 413    fundingTxVout: number;
 414  };
 415  
 416  export type OnchainBalanceResponse = {
 417    spendableSat: number;
 418    totalSat: number;
 419    reservedSat: number;
 420    pendingBalancesFromChannelClosuresSat: number;
 421    pendingBalancesDetails: PendingBalancesDetails[];
 422    pendingSweepBalancesDetails: PendingBalancesDetails[];
 423  };
 424  
 425  // from https://mempool.space/docs/api/rest#get-address-utxo
 426  export type MempoolUtxo = {
 427    txid: string;
 428    vout: number;
 429    status: {
 430      confirmed: boolean;
 431      block_height?: number;
 432      block_hash?: string;
 433      block_time?: number;
 434    };
 435    value: number;
 436  };
 437  
 438  // from https://mempool.space/docs/api/rest#get-node-stats
 439  export type MempoolNode = {
 440    alias: string;
 441    public_key: string;
 442    color: string;
 443    active_channel_count: number;
 444    sockets: string;
 445  };
 446  
 447  // from https://mempool.space/docs/api/rest#get-transaction
 448  export type MempoolTransaction = {
 449    txid: string;
 450    //version: 1,
 451    //locktime: 0,
 452    // vin: [],
 453    //vout: [],
 454    size: number;
 455    weight: number;
 456    fee: number;
 457    status:
 458      | {
 459          confirmed: true;
 460          block_height: number;
 461          block_hash: string;
 462          block_time: number;
 463        }
 464      | { confirmed: false };
 465  };
 466  
 467  export type LongUnconfirmedZeroConfChannel = { id: string; message: string };
 468  
 469  export type SetupNodeInfo = Partial<{
 470    backendType: BackendType;
 471  
 472    mnemonic?: string;
 473    nextBackupReminder?: string;
 474  
 475    lndAddress?: string;
 476    lndCertFile?: string;
 477    lndMacaroonFile?: string;
 478  
 479    phoenixdAddress?: string;
 480    phoenixdAuthorization?: string;
 481  
 482    clnAddress?: string;
 483    clnLightningDir?: string;
 484    clnAddressHold?: string;
 485  }>;
 486  
 487  export type LSPType = "LSPS1" | "LSPS2";
 488  
 489  export type LSPChannelOfferPaymentMethod =
 490    | "card"
 491    | "wallet"
 492    | "prepaid"
 493    | "included";
 494  
 495  export type LSPChannelOffer = {
 496    lspName: string;
 497    lspDescription: string;
 498    lspContactUrl: string;
 499    lspBalanceSat: number;
 500    feeTotalSat: number;
 501    feeTotalUsd: number;
 502    currentPaymentMethod: LSPChannelOfferPaymentMethod;
 503    terms: string;
 504  };
 505  
 506  export type RecommendedChannelPeer = {
 507    network: Network;
 508    image: string;
 509    name: string;
 510    minimumChannelSizeSat: number;
 511    maximumChannelSizeSat: number;
 512    note: string;
 513    publicChannelsAllowed: boolean;
 514    description: string;
 515  } & (
 516    | {
 517        paymentMethod: "onchain";
 518        pubkey: string;
 519        host: string;
 520      }
 521    | ({
 522        paymentMethod: "lightning";
 523        identifier: string;
 524        contactUrl: string;
 525        terms?: string;
 526        pubkey?: string;
 527        maximumChannelExpiryBlocks?: number;
 528        feeTotalSat1m?: number;
 529        feeTotalSat2m?: number;
 530        feeTotalSat3m?: number;
 531      } & (
 532        | { type: "LSPS1" }
 533        | { type: "LSPS2"; nodeAddress: string } // nodeid@ip:port
 534      ))
 535  );
 536  
 537  export type AlbyInfo = {
 538    hub: {
 539      latestVersion: string;
 540      latestReleaseNotes: string;
 541    };
 542  };
 543  
 544  export type BitcoinRate = {
 545    code: string;
 546    symbol: string;
 547    rate: string;
 548    rate_float: number;
 549    rate_cents: number;
 550  };
 551  
 552  export type Currency = {
 553    iso_code: string;
 554    symbol: string;
 555    name: string;
 556    priority: number;
 557  };
 558  
 559  // TODO: use camel case (needs mapping in the Alby OAuth Service - see how AlbyInfo is done above)
 560  export type AlbyMe = {
 561    identifier: string;
 562    nostr_pubkey: string;
 563    lightning_address: string;
 564    email: string;
 565    name: string;
 566    avatar: string;
 567    keysend_pubkey: string;
 568    shared_node: boolean;
 569    hub: {
 570      name?: string;
 571      config?: {
 572        region?: string;
 573      };
 574    };
 575    subscription: {
 576      plan_code: string;
 577    };
 578  };
 579  
 580  export type LSPOrderRequest = {
 581    amountSat?: number;
 582    lspType: LSPType;
 583    lspIdentifier: string;
 584    public: boolean;
 585  };
 586  
 587  export type RedeemOnchainFundsRequest = {
 588    toAddress: string;
 589    amountSat?: number;
 590    feeRate?: number;
 591    sendAll?: boolean;
 592  };
 593  
 594  export type AutoSwapRequest = {
 595    balanceThresholdSat?: number;
 596    swapAmountSat?: number;
 597    destination: string;
 598    destinationType?: string;
 599    unlockPassword?: string;
 600  };
 601  
 602  export type InitiateSwapRequest = {
 603    swapAmountSat?: number;
 604    destination?: string;
 605  };
 606  
 607  export type LSPOrderResponse = {
 608    invoice?: string;
 609    feeSat: number;
 610    invoiceAmountSat: number;
 611    incomingLiquiditySat: number;
 612    outgoingLiquiditySat: number;
 613  };
 614  
 615  export type AutoChannelRequest = {
 616    isPublic: boolean;
 617  };
 618  export type AutoChannelResponse = {
 619    invoice?: string;
 620    feeSat?: number;
 621    channelSizeSat: number;
 622  };
 623  
 624  export type RedeemOnchainFundsResponse = {
 625    txId: string;
 626  };
 627  
 628  export type LightningBalanceResponse = {
 629    totalSpendableSat: number;
 630    totalSpendableMsat: number;
 631    totalReceivableSat: number;
 632    totalReceivableMsat: number;
 633    nextMaxSpendableSat: number;
 634    nextMaxSpendableMsat: number;
 635    nextMaxReceivableSat: number;
 636    nextMaxReceivableMsat: number;
 637    nextMaxSpendableMPPSat: number;
 638    nextMaxSpendableMPPMsat: number;
 639    nextMaxReceivableMPPSat: number;
 640    nextMaxReceivableMPPMsat: number;
 641  };
 642  
 643  export type BalancesResponse = {
 644    onchain: OnchainBalanceResponse;
 645    lightning: LightningBalanceResponse;
 646  };
 647  
 648  export type Transaction = {
 649    id: number;
 650    type: "incoming" | "outgoing";
 651    state: "settled" | "pending" | "failed";
 652    appId: number | undefined;
 653    invoice: string;
 654    description: string;
 655    descriptionHash: string;
 656    preimage: string | undefined;
 657    paymentHash: string;
 658    amountSat: number;
 659    amountMsat: number;
 660    feesPaidSat: number;
 661    feesPaidMsat: number;
 662    updatedAt: string;
 663    createdAt: string;
 664    settledAt: string | undefined;
 665    metadata?: TransactionMetadata;
 666    boostagram?: Boostagram;
 667    failureReason: string;
 668  };
 669  
 670  export type TransactionMetadata = {
 671    comment?: string; // LUD-12
 672    payer_data?: {
 673      email?: string;
 674      name?: string;
 675      pubkey?: string;
 676    }; // LUD-18
 677    recipient_data?: {
 678      identifier?: string;
 679    }; // LUD-18
 680    nostr?: {
 681      pubkey: string;
 682      tags: string[][];
 683    }; // NIP-57
 684    offer?: {
 685      id: string;
 686      payer_note: string;
 687    }; // BOLT-12
 688    swap_id?: string;
 689    user_labels?: Record<string, string>;
 690  } & Record<string, unknown>;
 691  
 692  export type Boostagram = {
 693    appName: string;
 694    name: string;
 695    podcast: string;
 696    url: string;
 697    episode?: string;
 698    feedId?: string;
 699    itemId?: string;
 700    ts?: number;
 701    message?: string;
 702    senderId: string;
 703    senderName: string;
 704    time: string;
 705    action: "boost";
 706    valueSatTotal: number;
 707    valueMsatTotal: number;
 708  };
 709  
 710  export type OnchainTransaction = {
 711    amountSat: number;
 712    amountMsat: number;
 713    createdAt: number;
 714    type: "incoming" | "outgoing";
 715    state: "confirmed" | "unconfirmed";
 716    numConfirmations: number;
 717    txId: string;
 718  };
 719  
 720  export type ListAppsResponse = {
 721    apps: App[];
 722    totalCount: number;
 723    totalBalanceSat?: number;
 724    totalBalanceMsat?: number;
 725  };
 726  
 727  export type ListTransactionsResponse = {
 728    transactions: Transaction[];
 729    totalCount: number;
 730  };
 731  
 732  export type NewChannelOrderStatus = "pay" | "paid" | "success" | "opening";
 733  
 734  type NewChannelOrderCommon = {
 735    amountSat: string;
 736    isPublic: boolean;
 737    status: NewChannelOrderStatus;
 738    fundingTxId?: string;
 739    prevChannelIds: string[];
 740  };
 741  
 742  export type OnchainOrder = {
 743    paymentMethod: "onchain";
 744    pubkey: string;
 745    host: string;
 746  } & NewChannelOrderCommon;
 747  
 748  export type LightningOrder = {
 749    paymentMethod: "lightning";
 750    lspType: LSPType;
 751    lspIdentifier: string;
 752  } & NewChannelOrderCommon;
 753  
 754  export type NewChannelOrder = OnchainOrder | LightningOrder;
 755  
 756  export type AuthTokenResponse = {
 757    token: string;
 758  };
 759  
 760  export type GetForwardsResponse = {
 761    outboundAmountForwardedSat: number;
 762    outboundAmountForwardedMsat: number;
 763    totalFeeEarnedSat: number;
 764    totalFeeEarnedMsat: number;
 765    numForwards: number;
 766  };
 767