@elisym/commerce 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/buyer.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { NostrEvent, EventTemplate, VerifiedEvent, Filter } from 'nostr-tools';
2
2
  import { SimplePool } from 'nostr-tools/pool';
3
3
  import { Rpc, SolanaRpcApi, KeyPairSigner } from '@solana/kit';
4
- import { ChainFamily, Network, ChainConfig, Asset, PaymentRequestData } from '@elisym/pay-core';
4
+ import { ChainFamily, Network, ChainConfig, Asset, PaymentRequestData, ParsedPaymentRequestV2 } from '@elisym/pay-core';
5
5
  import { t as OfferWarning, F as FetchLike, b as DomainKeys, X as VerifiedOffer, H as PayoutTarget, r as OfferRefusal, x as OrderStatusMessage } from './verify-offer-BZ_a9x3L.js';
6
+ import { Eip1193Client } from '@elisym/pay-core/evm';
6
7
  import 'zod';
7
8
 
8
9
  /**
@@ -376,8 +377,18 @@ interface OrderRecord {
376
377
  marker?: PaymentMarker;
377
378
  /** The transaction that paid, once found. */
378
379
  paidTx?: string;
380
+ /** Wall-clock seconds when the payment was found (UI only: the "no answer" timer). */
381
+ paidAt?: number;
379
382
  status?: OrderStatus;
383
+ /**
384
+ * Tempo only: why the record ended unpaid, written in the same write and never
385
+ * changed. `over` means a wallet prompt may still be open and could still be approved.
386
+ */
387
+ endedBy?: EndedBy;
388
+ /** Tempo `over` records whose old-prompt warning the buyer confirmed for THIS record. */
389
+ confirmedOverIds?: string[];
380
390
  }
391
+ type EndedBy = 'rejected' | 'over' | 'nothing';
381
392
  declare const TERMINAL_STATES: readonly OrderState[];
382
393
  declare function isTerminal(record: Pick<OrderRecord, 'state'>): boolean;
383
394
  /**
@@ -412,18 +423,22 @@ type StoreWrite = {
412
423
  * `missing`: no such record. `conflict`: the record (its version or its
413
424
  * marker's attempt) is not the one the caller judged. `exclusion`: another
414
425
  * record for this product holds a live payment. `not_ready`: the record's
415
- * state does not allow this write.
426
+ * state does not allow this write. `needs_confirmation`: a Tempo order of
427
+ * this product ended `over` - its wallet prompt may still be approved - and
428
+ * the buyer has not confirmed the warning for it on this record.
416
429
  */
417
- reason: 'missing' | 'conflict' | 'exclusion' | 'not_ready';
430
+ reason: 'missing' | 'conflict' | 'exclusion' | 'not_ready' | 'needs_confirmation';
418
431
  /** For `exclusion`: the order holding it. */
419
432
  holder?: string;
433
+ /** For `needs_confirmation`: the ended orders to confirm. */
434
+ unconfirmed?: string[];
420
435
  };
421
436
  /**
422
437
  * Fields a plain update may change. What the order and its payment were made of
423
438
  * (payout, amount, reference, offer, ...) is fixed when the record is added; the
424
439
  * marker and the version have their own paths.
425
440
  */
426
- type RecordPatch = Partial<Pick<OrderRecord, 'state' | 'paymentRequest' | 'orderWrap' | 'receiptWrap' | 'inboxRelays' | 'acknowledgedRelays' | 'paidTx' | 'status'>>;
441
+ type RecordPatch = Partial<Pick<OrderRecord, 'state' | 'paymentRequest' | 'orderWrap' | 'receiptWrap' | 'inboxRelays' | 'acknowledgedRelays' | 'paidTx' | 'paidAt' | 'status' | 'endedBy' | 'confirmedOverIds'>>;
427
442
  /**
428
443
  * Where order records live. Every money rule is judged by the core (below) on
429
444
  * what `transactProduct` hands it; a backend only makes that read-judge-write
@@ -466,21 +481,21 @@ declare function judgeUpdate(records: readonly OrderRecord[], orderId: string, e
466
481
  * its composed request and no marker - and no OTHER record for the product
467
482
  * holds a live payment (two tabs cannot both pay).
468
483
  */
469
- declare function judgeSetMarker(records: readonly OrderRecord[], orderId: string, expectedVersion: number, marker: PaymentMarker): Judged;
484
+ declare function judgeSetMarker(records: readonly OrderRecord[], orderId: string, expectedVersion: number, marker: PaymentMarker, now?: number): Judged;
470
485
  /**
471
486
  * Change the marker of the attempt `attemptId` - record its signature or hash,
472
487
  * or replace it with a retry's marker (same record, order and reference). Both
473
488
  * the attempt and the record version must be the ones the caller judged: a
474
489
  * signature recorded in between is never overrun.
475
490
  */
476
- declare function judgeUpdateMarker(records: readonly OrderRecord[], orderId: string, expectedVersion: number, attemptId: string, next: PaymentMarker): Judged;
491
+ declare function judgeUpdateMarker(records: readonly OrderRecord[], orderId: string, expectedVersion: number, attemptId: string, next: PaymentMarker, now?: number): Judged;
477
492
  /**
478
493
  * End the attempt `attemptId`, judged at `expectedVersion`: nothing was
479
494
  * requested (`ordered`, the marker is removed), or the attempt provably ended
480
495
  * (`ended-unpaid`, the marker is KEPT - it no longer excludes, but its floor,
481
496
  * signature or hash is what later reconciliation starts from).
482
497
  */
483
- declare function judgeClearMarker(records: readonly OrderRecord[], orderId: string, expectedVersion: number, attemptId: string, nextState: Extract<OrderState, 'ordered' | 'ended-unpaid'>): Judged;
498
+ declare function judgeClearMarker(records: readonly OrderRecord[], orderId: string, expectedVersion: number, attemptId: string, nextState: Extract<OrderState, 'ordered' | 'ended-unpaid'>, endedBy?: Exclude<EndedBy, 'nothing'>): Judged;
484
499
  /**
485
500
  * After a delivery: pin the store's owner, and add every payout of the offer
486
501
  * that delivered to the known ones (pinning only the paid one would flag every
@@ -514,11 +529,11 @@ declare class OrderStore {
514
529
  /** Change plain fields of the record the caller judged at `expectedVersion`. */
515
530
  update(orderId: string, expectedVersion: number, patch: RecordPatch): Promise<StoreWrite>;
516
531
  /** See `judgeSetMarker`. */
517
- setMarker(orderId: string, expectedVersion: number, marker: PaymentMarker): Promise<StoreWrite>;
532
+ setMarker(orderId: string, expectedVersion: number, marker: PaymentMarker, now?: number): Promise<StoreWrite>;
518
533
  /** See `judgeUpdateMarker`. */
519
- updateMarker(orderId: string, expectedVersion: number, attemptId: string, next: PaymentMarker): Promise<StoreWrite>;
534
+ updateMarker(orderId: string, expectedVersion: number, attemptId: string, next: PaymentMarker, now?: number): Promise<StoreWrite>;
520
535
  /** See `judgeClearMarker`. */
521
- clearMarker(orderId: string, expectedVersion: number, attemptId: string, nextState: Extract<OrderState, 'ordered' | 'ended-unpaid'>): Promise<StoreWrite>;
536
+ clearMarker(orderId: string, expectedVersion: number, attemptId: string, nextState: Extract<OrderState, 'ordered' | 'ended-unpaid'>, endedBy?: Exclude<EndedBy, 'nothing'>): Promise<StoreWrite>;
522
537
  pins(storePubkey: string): Promise<StorePinsRecord | undefined>;
523
538
  /** See `mergePins`. */
524
539
  rememberDelivery(storePubkey: string, ownerPubkey: string, payouts: readonly {
@@ -547,7 +562,7 @@ declare class MemoryOrderBackend implements OrderBackend {
547
562
  }): Promise<T>;
548
563
  }
549
564
 
550
- type ReadyOffer$1 = Extract<LoadedOffer, {
565
+ type ReadyOffer$2 = Extract<LoadedOffer, {
551
566
  ok: true;
552
567
  }>;
553
568
  /** The receipt `medium` of a chain: `solana`, `solana-devnet`, `tempo`, `tempo-moderato`. */
@@ -563,10 +578,10 @@ declare function clockAgrees(chainTime: number, deviceTime: number): boolean;
563
578
  * and price and no new warning to confirm (`same`); something the buyer must
564
579
  * look at again (`changed`); or the chosen payout is gone (`gone`).
565
580
  */
566
- declare function compareOffers(shown: PricedPayout, confirmed: readonly OfferWarning[], fresh: ReadyOffer$1): 'same' | 'changed' | 'gone';
581
+ declare function compareOffers(shown: PricedPayout, confirmed: readonly OfferWarning[], fresh: ReadyOffer$2): 'same' | 'changed' | 'gone';
567
582
  interface PlaceOrderInput {
568
583
  /** A FRESH verified offer (at most two minutes old). */
569
- offer: ReadyOffer$1;
584
+ offer: ReadyOffer$2;
570
585
  payout: PricedPayout;
571
586
  email?: string;
572
587
  /** Chain time read just before ordering (seconds). */
@@ -651,7 +666,7 @@ declare function listenForStatus(record: OrderRecord, relays: readonly string[],
651
666
  close(): void;
652
667
  };
653
668
 
654
- type ReadyOffer = Extract<LoadedOffer, {
669
+ type ReadyOffer$1 = Extract<LoadedOffer, {
655
670
  ok: true;
656
671
  }>;
657
672
  /**
@@ -703,7 +718,7 @@ interface SolanaPayDeps extends OrderDeps {
703
718
  }
704
719
  interface PayInput {
705
720
  /** A FRESH verified offer (at most two minutes old): the payout and price are checked against it. */
706
- fresh: ReadyOffer;
721
+ fresh: ReadyOffer$1;
707
722
  /** Chain time read just before (seconds). */
708
723
  chainTime: number;
709
724
  }
@@ -731,7 +746,12 @@ type SolanaPayRefusal =
731
746
  /** A retry before the last attempt provably ended. */
732
747
  | 'still_waiting' | 'already_paid'
733
748
  /** The caller's spend limit refused the attempt's costs (`reserve` threw). Nothing was recorded. */
734
- | 'spend_limit';
749
+ | 'spend_limit'
750
+ /**
751
+ * A Tempo order of this product ended with its wallet prompt still open:
752
+ * the buyer confirms the warning (`confirmedOverIds`) before this request.
753
+ */
754
+ | 'needs_confirmation';
735
755
  type SolanaPayResult = {
736
756
  ok: true;
737
757
  record: OrderRecord;
@@ -742,6 +762,8 @@ type SolanaPayResult = {
742
762
  record?: OrderRecord;
743
763
  /** For `exclusion`: the order holding it. */
744
764
  holder?: string;
765
+ /** For `needs_confirmation`: the ended orders to confirm. */
766
+ unconfirmed?: string[];
745
767
  /** For `insufficient_*`: what the payment needs and what the payer has, in subunits / lamports. */
746
768
  needed?: bigint;
747
769
  available?: bigint;
@@ -901,6 +923,8 @@ declare function onOtherTerms(record: OrderRecord, payout: PricedPayout): boolea
901
923
  type EndDeps = Pick<SolanaPayDeps, 'store' | 'readClient' | 'clientFor' | 'now' | 'canProveOver'> & {
902
924
  /** The order's own network's RPC, or `undefined` when the caller has none for it. */
903
925
  rpc: SolanaPayDeps['rpc'] | undefined;
926
+ /** For a Tempo order: a read RPC of its own chain, or `undefined` when the caller has none. */
927
+ tempo?: Eip1193Client;
904
928
  store: OrderStore;
905
929
  };
906
930
  /**
@@ -918,4 +942,166 @@ declare function endOrder(record: OrderRecord, deps: EndDeps): Promise<{
918
942
  record: OrderRecord;
919
943
  }>;
920
944
 
921
- export { type AuthSigner, CONFIRM_WARNINGS, DEFAULT_RELAYS, type EndDeps, type LoadOfferOptions, type LoadedOffer, MAX_CLOCK_SKEW_SECS, MAX_RELAY_URL_LENGTH, MERCHANT_CATCH_UP_SECS, MemoryOrderBackend, OFFER_SNAPSHOT_MAX_AGE_SECS, ORDER_ACK_TARGET, type OrderBackend, type OrderDeps, type OrderRecord, type OrderState, type OrderStatus, OrderStore, PAYMENT_SCAN_MARGIN_SECS, PAY_CUTOFF_SECS, type PayInput, type PaymentCosts, type PaymentMarker, type PlaceOrderInput, type PlaceOrderResult, type PoolLike, type PricedPayout, type PublishResult, RELAY_CONNECT_MAX_WAIT_MS, RELAY_PUBLISH_DEADLINE_MS, RELAY_QUERY_DEADLINE_MS, RELAY_QUERY_MAX_WAIT_MS, type RecordPatch, type RelayClient, type RelayClientOptions, type RelayLike, SOLANA_COMPUTE_UNIT_LIMIT, STORE_RELAY_CAP, STORE_WRITE_ATTEMPTS, SUBSCRIBE_RETRY_MAX_MS, SUBSCRIBE_RETRY_MS, SUBSCRIBE_STABLE_MS, type SignedRefusal, type SolanaPayDeps, type SolanaPayRefusal, type SolanaPayResult, type SolanaWallet, type SolanaWatch, type StoreInbox, type StorePins, type StorePinsRecord, type StoreRelaySources, type StoreWrite, TERMINAL_STATES, WRAP_BACKDATE_SECS, type WidgetRefusal, applyStatus, cancelledUnpaid, checkBeforePaying, checkSignedTransaction, clockAgrees, compareOffers, composeOrderPayment, createPool, createRelayClient, deliveryLink, endOrder, endSolanaOrder, gone, holdsPayExclusion, isEventShaped, isGenuineEvent, isPageOrigin, isSnapshotStale, isTerminal, judgeAdd, judgeClearMarker, judgeSetMarker, judgeUpdate, judgeUpdateMarker, listenForStatus, loadOffer, loadOfferForAgent, localSolanaWallet, mediumOf, mergePins, newestGenuine, newestStoreInbox, normalizeRelayUrl, nowSecs, onOtherTerms, payWithSolana, placeOrder, readChainTime, readRelays, readStoreInbox, recordToShow, relayHost, resumeOrder, retryWithSolana, sendReceipt, statusFor, storeRelays, storedSolanaRequest, uniqueRelays, watchSolanaPayment };
945
+ /**
946
+ * Paying an acknowledged order on Tempo, and reconciling it.
947
+ *
948
+ * The rules differ from Solana's where the chain does: a Tempo wallet prompt
949
+ * has no deadline and a relayer can land an approved payment under a new
950
+ * hash, so there is no retry here - an attempt holding a sent hash stays live
951
+ * until it is found, and an attempt proven unpaid (`over`) ends the order with
952
+ * its prompt still open (the store asks for confirmation before any other
953
+ * payment of the product, see `judgeSetMarker`).
954
+ */
955
+
956
+ type ReadyOffer = Extract<LoadedOffer, {
957
+ ok: true;
958
+ }>;
959
+ interface TempoPayDeps extends OrderDeps {
960
+ /** A read RPC of the record's own Tempo chain. */
961
+ client: Eip1193Client;
962
+ /** The device clock (seconds): the marker's `setAt`, the receipt's date. */
963
+ now?: () => number;
964
+ newAttemptId?: () => string;
965
+ }
966
+ /** An EIP-1193 wallet, reduced to what one payment needs. */
967
+ interface TempoWallet {
968
+ /** The payer, 0x. */
969
+ address: string;
970
+ /** `eth_chainId` as the WALLET answers it. */
971
+ chainId(): Promise<number>;
972
+ /**
973
+ * `eth_sendTransaction` of one call; resolves the hash the wallet returned.
974
+ * A user refusal rejects with an error carrying `code: 4001`.
975
+ */
976
+ sendCall(call: {
977
+ from: string;
978
+ to: string;
979
+ data: string;
980
+ chainId: string;
981
+ }): Promise<string>;
982
+ }
983
+ type TempoPayRefusal =
984
+ /** The record cannot take a payment now (state, request, the store closed it). */
985
+ 'not_payable'
986
+ /** The offer snapshot is older than two minutes: verify again. */
987
+ | 'stale_offer'
988
+ /** The store no longer offers this payout at this price: end this order and start a new one. */
989
+ | 'offer_changed'
990
+ /** Too close to the merchant's catch-up end, or to the request's deadline: a new order. */
991
+ | 'too_late'
992
+ /** The payee is a Tempo system address or a coin contract: nothing can pay it. */
993
+ | 'unpayable' | 'self_payment' | 'insufficient_token'
994
+ /** The recipient's receive policy refuses this payer: the money would sit with the guard. */
995
+ | 'policy_blocked'
996
+ /** The read RPC, or the wallet, is on another chain. */
997
+ | 'wrong_chain'
998
+ /** A chain read failed; nothing was requested. */
999
+ | 'rpc_error' | 'exclusion' | 'needs_confirmation' | 'conflict'
1000
+ /** The buyer refused in the wallet (4001): nothing was signed, the order ended. */
1001
+ | 'rejected'
1002
+ /** The wallet did not answer with a hash: the attempt stays live ("check your wallet"). */
1003
+ | 'wallet_failed';
1004
+ type TempoPayResult = {
1005
+ ok: true;
1006
+ record: OrderRecord;
1007
+ hash: string;
1008
+ /** The hash could not be stored yet: keep it in memory and pass it to the watch. */
1009
+ hashUnsaved?: boolean;
1010
+ } | {
1011
+ ok: false;
1012
+ reason: TempoPayRefusal;
1013
+ record?: OrderRecord;
1014
+ holder?: string;
1015
+ unconfirmed?: string[];
1016
+ /** For `insufficient_token`: subunits. */
1017
+ needed?: bigint;
1018
+ available?: bigint;
1019
+ };
1020
+ /** What the buyer keeps beyond the price for the wallet's own fee (MetaMask takes it in the coin). */
1021
+ declare function tempoFeeMargin(decimals: number): bigint;
1022
+ /** The request stored on the record, as the schema reads it. */
1023
+ declare function storedTempoRequest(record: OrderRecord): ParsedPaymentRequestV2 | undefined;
1024
+ /** The chain's time, from its finalized head: what a Tempo order rumor is dated with. */
1025
+ declare function readTempoChainTime(client: Eip1193Client): Promise<number>;
1026
+ /** Store the hash of attempt `attemptId`, re-reading on a lost compare-and-swap. */
1027
+ declare function saveTempoHash(record: OrderRecord, attemptId: string, hash: string, deps: Pick<TempoPayDeps, 'store'>): Promise<{
1028
+ saved: boolean;
1029
+ record: OrderRecord;
1030
+ stopped?: boolean;
1031
+ }>;
1032
+ /**
1033
+ * Pay an acknowledged order: checks, the request, the pay floor, the marker
1034
+ * (test-and-set with the product exclusion and the old-prompt confirmation),
1035
+ * the wallet's chain re-read, ONE `eth_sendTransaction`. A proving rejection
1036
+ * ends the order; any other failure keeps the attempt live.
1037
+ */
1038
+ declare function payWithTempo(record: OrderRecord, wallet: TempoWallet, fresh: ReadyOffer, deps: TempoPayDeps): Promise<TempoPayResult>;
1039
+ type TempoWatch =
1040
+ /** The payment was found and recorded. */
1041
+ {
1042
+ state: 'paid';
1043
+ record: OrderRecord;
1044
+ }
1045
+ /**
1046
+ * Nothing yet, or a sent hash still unresolved: keep watching. `pastDeadline`:
1047
+ * the request's late deadline passed and a hash is still unresolved (the
1048
+ * "check your wallet, or contact the store" case).
1049
+ */
1050
+ | {
1051
+ state: 'waiting';
1052
+ record: OrderRecord;
1053
+ pastDeadline?: boolean;
1054
+ }
1055
+ /** No hash, no pending call, and a vouched "not paid" past the late deadline. */
1056
+ | {
1057
+ state: 'over';
1058
+ record: OrderRecord;
1059
+ }
1060
+ /** The money sits with the recipient's transfer-policy guard. */
1061
+ | {
1062
+ state: 'blocked';
1063
+ record: OrderRecord;
1064
+ }
1065
+ /** The chain answered something no verdict rests on: keep watching, say so after a while. */
1066
+ | {
1067
+ state: 'unsure';
1068
+ record: OrderRecord;
1069
+ }
1070
+ /** Delivered or refunded: nothing is left to watch. */
1071
+ | {
1072
+ state: 'closed';
1073
+ record: OrderRecord;
1074
+ };
1075
+ interface TempoWatchOptions {
1076
+ /** A hash returned in this session that is not stored yet: it counts as a pending call. */
1077
+ pendingHash?: string;
1078
+ /** A wallet call of this session is still unanswered. */
1079
+ callPending?: boolean;
1080
+ }
1081
+ /**
1082
+ * One reconciliation step for a Tempo attempt, or for a Tempo order that ended
1083
+ * `over` (its prompt can still be approved). Only `none` with no hash, no
1084
+ * pending call and a live attempt - the verifier vouches `none` only past the
1085
+ * late deadline - is `over`.
1086
+ */
1087
+ declare function watchTempoPayment(record: OrderRecord, deps: TempoPayDeps, options?: TempoWatchOptions): Promise<TempoWatch>;
1088
+ /** The late deadline of a request: after it a vouched "not paid" is final for an attempt with no hash. */
1089
+ declare function tempoLateDeadline(request: ParsedPaymentRequestV2): number;
1090
+ /**
1091
+ * End a Tempo order that will not be paid: at once when nothing was requested;
1092
+ * with an attempt, only once the watch proves it over - it ends `over`, its
1093
+ * prompt still open.
1094
+ */
1095
+ declare function endTempoOrder(record: OrderRecord, deps: TempoPayDeps, options?: TempoWatchOptions): Promise<{
1096
+ ended: boolean;
1097
+ record: OrderRecord;
1098
+ }>;
1099
+ /**
1100
+ * Whether an ended Tempo order may still be paid: it ended `over` (or with no
1101
+ * reason, fail closed) inside the merchant's catch-up, judged on the device
1102
+ * clock with the skew allowance. The same predicate as the store's
1103
+ * confirmation, for the per-load reconciliation.
1104
+ */
1105
+ declare function mayStillBePaid(record: OrderRecord, now: number): boolean;
1106
+
1107
+ export { type AuthSigner, CONFIRM_WARNINGS, DEFAULT_RELAYS, type EndDeps, type EndedBy, type LoadOfferOptions, type LoadedOffer, MAX_CLOCK_SKEW_SECS, MAX_RELAY_URL_LENGTH, MERCHANT_CATCH_UP_SECS, MemoryOrderBackend, OFFER_SNAPSHOT_MAX_AGE_SECS, ORDER_ACK_TARGET, type OrderBackend, type OrderDeps, type OrderRecord, type OrderState, type OrderStatus, OrderStore, PAYMENT_SCAN_MARGIN_SECS, PAY_CUTOFF_SECS, type PayInput, type PaymentCosts, type PaymentMarker, type PlaceOrderInput, type PlaceOrderResult, type PoolLike, type PricedPayout, type PublishResult, RELAY_CONNECT_MAX_WAIT_MS, RELAY_PUBLISH_DEADLINE_MS, RELAY_QUERY_DEADLINE_MS, RELAY_QUERY_MAX_WAIT_MS, type RecordPatch, type RelayClient, type RelayClientOptions, type RelayLike, SOLANA_COMPUTE_UNIT_LIMIT, STORE_RELAY_CAP, STORE_WRITE_ATTEMPTS, SUBSCRIBE_RETRY_MAX_MS, SUBSCRIBE_RETRY_MS, SUBSCRIBE_STABLE_MS, type SignedRefusal, type SolanaPayDeps, type SolanaPayRefusal, type SolanaPayResult, type SolanaWallet, type SolanaWatch, type StoreInbox, type StorePins, type StorePinsRecord, type StoreRelaySources, type StoreWrite, TERMINAL_STATES, type TempoPayDeps, type TempoPayRefusal, type TempoPayResult, type TempoWallet, type TempoWatch, type TempoWatchOptions, WRAP_BACKDATE_SECS, type WidgetRefusal, applyStatus, cancelledUnpaid, checkBeforePaying, checkSignedTransaction, clockAgrees, compareOffers, composeOrderPayment, createPool, createRelayClient, deliveryLink, endOrder, endSolanaOrder, endTempoOrder, gone, holdsPayExclusion, isEventShaped, isGenuineEvent, isPageOrigin, isSnapshotStale, isTerminal, judgeAdd, judgeClearMarker, judgeSetMarker, judgeUpdate, judgeUpdateMarker, listenForStatus, loadOffer, loadOfferForAgent, localSolanaWallet, mayStillBePaid, mediumOf, mergePins, newestGenuine, newestStoreInbox, normalizeRelayUrl, nowSecs, onOtherTerms, payWithSolana, payWithTempo, placeOrder, readChainTime, readRelays, readStoreInbox, readTempoChainTime, recordToShow, relayHost, resumeOrder, retryWithSolana, saveTempoHash, sendReceipt, statusFor, storeRelays, storedSolanaRequest, storedTempoRequest, tempoFeeMargin, tempoLateDeadline, uniqueRelays, watchSolanaPayment, watchTempoPayment };