Skip to content

Supplemental Economics Example

This example focuses only on economics support behavior.
It does not change protocol authority semantics.

import {
  assembleDirectSpendTx,
  buildDirectSpendPlan,
  type DirectSpendWalletRuntimeExecutorV1,
} from "@bch-stealth/direct-spend-wallet";
import {
  prepareDirectSpendProofInput,
  proveDirectSpend,
  verifyDirectSpend,
} from "@bch-stealth/prover-runtime";

type EconomicsInputs = {
  authoritativeProtocolSourceOutpointRef: string;
  protocolAuthorityInputSats: number;
  continuationShellOutputSats: number;
  minerFeeSats: number;
  piv1Bytes: Uint8Array;
  witnessBytes: Uint8Array;
};

type SupplementalFundingResolution =
  | { used: false }
  | { used: true; outpointRef: string; inputSats: number; changeSats: number };

function resolveSupplementalEconomics(inputs: EconomicsInputs): SupplementalFundingResolution {
  const required = inputs.continuationShellOutputSats + inputs.minerFeeSats;
  if (inputs.protocolAuthorityInputSats >= required) {
    return { used: false };
  }

  // Example static resolver: replace with wallet/provider resolver implementation.
  const requiredAdditionalSats = required - inputs.protocolAuthorityInputSats;
  const resolvedInputSats = requiredAdditionalSats + 1000;
  const changeSats = resolvedInputSats - requiredAdditionalSats;
  return {
    used: true,
    outpointRef: "replace-with-supplemental-utxo-txid:vout",
    inputSats: resolvedInputSats,
    changeSats,
  };
}

export async function runDirectSpendWithOptionalSupplementalTopUp(
  inputs: EconomicsInputs,
) {
  const proofInput = prepareDirectSpendProofInput({
    piv1Bytes: inputs.piv1Bytes,
    witnessBytes: inputs.witnessBytes,
    determinism: { mode: "deterministic" },
  });
  const proved = await proveDirectSpend(proofInput);
  const verify = await verifyDirectSpend(proved);
  if (!verify.ok) throw new Error(verify.reason ?? "verifyDirectSpend failed");

  const runtimeExecutor: DirectSpendWalletRuntimeExecutorV1 = async () => ({
    request: proofInput,
    estimate: {
      backendId: proved.prove.backendId,
      estimatedProofBytes: proved.prove.estimatedProofBytes,
      estimatedProofBlobBytes: proved.prove.pbv1Bytes.length,
    },
    prove: proved.prove,
    verify,
  });

  const supplemental = resolveSupplementalEconomics(inputs);
  const plan = buildDirectSpendPlan({
    request: proofInput,
    runtimeExecutor,
    hostChecks: {
      transcriptBinding: () => undefined,
      ofm2v2: () => undefined,
      continuationShell: () => undefined,
      malformedCarrier: () => undefined,
      routingCompatibility: () => undefined,
    },
    assembleTx: (run) => ({
      protocolAuthorityOutpointRef: inputs.authoritativeProtocolSourceOutpointRef,
      supplementalEconomicsOutpointRef: supplemental.used ? supplemental.outpointRef : null,
      proofBytes: run.prove.proofBytes,
      pbv1Bytes: run.prove.pbv1Bytes,
    }),
    broadcastTx: async (txPlan) => ({
      txidHex: "replace-with-broadcast-txid",
      txPlan,
    }),
  });

  return {
    supplemental,
    assembled: await assembleDirectSpendTx(plan),
  };
}

Truth Requirements

  • Supplemental input supports shell + fee feasibility only.
  • It is not hidden transfer semantics.
  • External integrations should use package-root façade exports only, not deep src/* imports.
  • Artifacts should separately expose:
  • protocol authority source
  • supplemental funding usage and amounts
  • continuation shell sats
  • miner fee sats