Skip to content
How the API is shaped

Progress

Every payment reports its stages through onProgress. Here is every stage, which payments report it, and a message to show.

A payment takes a few seconds, and most of that is the proof. Pass onProgress to show your user what is happening meanwhile.

How onProgress works

Every payment function takes an onProgress option. The SDK calls it once per stage, with an event whose stage names it. The event also carries what that stage produced, such as the fees or a transaction signature.

If your callback throws, the SDK drops the error and carries on. If it returns a promise, the SDK does not wait for it. Your callback cannot stop a payment.

Every stage

The messages are the ones the example app shows.

StageReported byMessage to show
synceddeposit, Private Send, withdrawBrought this device up to date with Solana.
preparedevery paymentPrepared on this device.
endorsedregister, depositThe committee approved the transaction.
provedregister, deposit, Private Send, withdrawThe privacy work on this device finished.
funding-signeddeposit, from a wallet that signs only version 0Your wallet signed the transfer that funds the deposit.
funding-sentdeposit, from a wallet that signs only version 0Sent the funding transfer to Solana.
funding-confirmeddeposit, from a wallet that signs only version 0The funding transfer landed.
signedregister, deposit, refundYour wallet signed the transaction.
sentregister, deposit, refundSent the transaction to Solana.
confirmedregister, deposit, refundThe transaction landed on Solana.
merge-preparedPrivate Send, withdrawCombining part of your private balance so one payment can cover the amount.
merge-relayedPrivate Send, withdrawThe relayer accepted the combining step.
merge-settledPrivate Send, withdrawThe combining step finished.
relayedPrivate Send, withdrawThe relayer accepted the transaction and will send it.
settledPrivate Send, withdrawFollowed the payment until Solana settled it.

"Refund" here is refundStrandedDeposit. A few stages do not always come, or come in a different order:

  • endorsed and proved run at the same time, so they can arrive in either order.
  • A registration with nothing left to send stops after prepared.
  • A transaction that fails, expires or is still pending stops at sent. The result says where it ended up.
  • The merge stages come before the payment's own, once per merge. Each carries a merge number, from 1.
  • settled comes only when the SDK follows the payment, which it does unless you pass follow: false.

A message for every stage

Each payment's stages form a union on stage. A switch over all of them is checked by TypeScript. If the SDK adds a stage, this stops compiling until you give it a message.

type  =
  | 
  | 
  | 
  | 
  | 
  | SyncedStage
  | SettledStage;

function (: ): string {
  switch (.) {
    case "synced":
      return "Brought this device up to date with Solana.";
    case "prepared":
      return "Prepared on this device.";
    case "endorsed":
      return "The committee approved the transaction.";
    case "proved":
      return "The privacy work on this device finished.";
    case "funding-signed":
      return "Your wallet signed the transfer that funds the deposit.";
    case "funding-sent":
      return "Sent the funding transfer to Solana.";
    case "funding-confirmed":
      return "The funding transfer landed.";
    case "signed":
      return "Your wallet signed the transaction.";
    case "sent":
      return "Sent the transaction to Solana.";
    case "confirmed":
      return "The transaction landed on Solana.";
    case "merge-prepared":
      return `Combining part of your private balance, step ${.}.`;
    case "merge-relayed":
      return `The relayer accepted combining step ${.}.`;
    case "merge-settled":
      return `Combining step ${.} finished.`;
    case "relayed":
      return "The relayer accepted the transaction and will send it.";
    case "settled":
      return "Followed the payment until Solana settled it.";
  }
}

A progress list in React

This component runs a deposit and lists each stage as it arrives:

import {  } from "react";
import type {  } from "react";
import {  } from "@umbra/nimbus-solana-web";

export function ({
  ,
  ,
}: {
  : DepositContext;
  : ;
}):  {
  const [, ] = <readonly string[]>([]);
  const [, ] = (false);

  async function (): <void> {
    ([]);
    (true);
    try {
      await (
        ,
        {
          : ,
          : 25_000_000n,
          : ..,
        },
        {
          : () => {
            (() => [..., ()]);
          },
        },
      );
    } finally {
      (false);
    }
  }

  return (
    <>
      < ="button" ={} ={() => void ()}>
        Deposit 25 USDC
      </>
      { && <>Keep this tab open until the deposit finishes.</>}
      <>
        {.((, ) => (
          < ={}>{}</>
        ))}
      </>
    </>
  );
}

The button stays disabled while the deposit runs, so your user cannot start a second one. The result's kind still says how it ended. Show it as the deposit guide does.

Last updated

On this page