@mooring-live/x402-client 0.0.0-stage → 0.2.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/README.md +167 -2
- package/dist/card.d.ts +60 -0
- package/dist/card.js +67 -0
- package/dist/card.js.map +1 -0
- package/dist/client.d.ts +77 -0
- package/dist/client.js +272 -0
- package/dist/client.js.map +1 -0
- package/dist/denial.d.ts +104 -0
- package/dist/denial.js +154 -0
- package/dist/denial.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/precheck.d.ts +12 -0
- package/dist/precheck.js +25 -0
- package/dist/precheck.js.map +1 -0
- package/dist/reconcile.d.ts +37 -0
- package/dist/reconcile.js +44 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/scheme.d.ts +93 -0
- package/dist/scheme.js +232 -0
- package/dist/scheme.js.map +1 -0
- package/dist/signer.d.ts +13 -0
- package/dist/signer.js +31 -0
- package/dist/signer.js.map +1 -0
- package/package.json +69 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/denial.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type xdr } from "@stellar/stellar-sdk";
|
|
2
|
+
export type DenialReason = "frozen" | "cancelled" | "expired" | "not_allowlisted" | "over_per_tx_cap" | "over_budget" | "wrong_token" | "insufficient_balance" | "bad_signature" | "wrong_context" | "unknown";
|
|
3
|
+
/**
|
|
4
|
+
* Where a payment was denied.
|
|
5
|
+
*
|
|
6
|
+
* - `precheck` — the local policy mirror, before anything is signed.
|
|
7
|
+
* - `simulate` — the card's `__check_auth`, in the enforcing simulation the
|
|
8
|
+
* client runs after signing and before handing the payload to a facilitator.
|
|
9
|
+
* - `verify` — the facilitator refused the payload.
|
|
10
|
+
* - `settle` — the settlement transaction failed on-chain.
|
|
11
|
+
*/
|
|
12
|
+
export type DenialStage = "precheck" | "simulate" | "verify" | "settle";
|
|
13
|
+
/** Card contract error codes that mean "policy denied". */
|
|
14
|
+
export declare const CARD_ERROR_CODES: Record<number, DenialReason>;
|
|
15
|
+
/**
|
|
16
|
+
* Every contract error the card can raise (`CardError`, codes 1..13), with a
|
|
17
|
+
* short user-facing sentence for each. This is the full table: unlike
|
|
18
|
+
* `CARD_ERROR_CODES` (1..8, payment denials only), it also covers the owner
|
|
19
|
+
* operations the web app surfaces (`set_policy`, `set_label`, allowlist
|
|
20
|
+
* management, freeze/cancel/withdraw) so their errors can be shown directly
|
|
21
|
+
* without a separate mapping.
|
|
22
|
+
*/
|
|
23
|
+
export declare const CARD_ERRORS: Record<number, string>;
|
|
24
|
+
/** Parses a Soroban `Error(Contract, #N)` from an error/diagnostic string. */
|
|
25
|
+
export declare function classifyContractError(text: string): {
|
|
26
|
+
code: number;
|
|
27
|
+
reason: DenialReason;
|
|
28
|
+
} | null;
|
|
29
|
+
/**
|
|
30
|
+
* Reads the card's own `__check_auth` verdict out of a transaction's diagnostic
|
|
31
|
+
* events.
|
|
32
|
+
*
|
|
33
|
+
* The card's address alone is not evidence: it appears in the `transfer`
|
|
34
|
+
* arguments of every diagnostic this transaction can produce, and the token's
|
|
35
|
+
* own error codes overlap the card's 1-8 range — a SAC balance error would be
|
|
36
|
+
* read as a policy decision. What identifies an auth failure is the host's
|
|
37
|
+
* event, which names the failing account and its error together:
|
|
38
|
+
*
|
|
39
|
+
* ["failed account authentication with error", <card>, Error(Contract, #N)]
|
|
40
|
+
*
|
|
41
|
+
* so the reason is taken from that event and nowhere else. Anything that does
|
|
42
|
+
* not match returns `null`, and the caller reports `unknown`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function cardDenialFromEvents(events: readonly xdr.DiagnosticEvent[], card: string): {
|
|
45
|
+
code: number;
|
|
46
|
+
reason: DenialReason;
|
|
47
|
+
} | null;
|
|
48
|
+
/** The merchant a denied payment was addressed to, as far as the client knows. */
|
|
49
|
+
export interface DeniedMerchant {
|
|
50
|
+
payTo: string;
|
|
51
|
+
url?: string;
|
|
52
|
+
amount?: string;
|
|
53
|
+
network?: string;
|
|
54
|
+
}
|
|
55
|
+
/** The hosted Mooring web app, used to build "allow this merchant" links. */
|
|
56
|
+
export declare const DEFAULT_APP_URL = "https://app.mooring.live";
|
|
57
|
+
/**
|
|
58
|
+
* `origin + pathname` of an absolute URL (drops query and fragment). Input
|
|
59
|
+
* that does not parse (a relative URL, say) is cut at its first `?` or `#`,
|
|
60
|
+
* so a query string can never pass through.
|
|
61
|
+
*/
|
|
62
|
+
export declare function stripQuery(url: string): string;
|
|
63
|
+
/** True for an absolute `http:` / `https:` URL. */
|
|
64
|
+
export declare function isAbsoluteHttpUrl(url: string): boolean;
|
|
65
|
+
/** Link to the web app's allow page for a card and a paid service URL (query and fragment are dropped). */
|
|
66
|
+
export declare function allowMerchantUrl(appBaseUrl: string, card: string, serviceUrl: string): string;
|
|
67
|
+
export declare class CardPolicyDenied extends Error {
|
|
68
|
+
readonly reason: DenialReason;
|
|
69
|
+
readonly stage: DenialStage;
|
|
70
|
+
readonly contractError?: number;
|
|
71
|
+
readonly detail?: string;
|
|
72
|
+
readonly merchant?: DeniedMerchant;
|
|
73
|
+
constructor(reason: DenialReason, stage: DenialStage, opts?: {
|
|
74
|
+
contractError?: number;
|
|
75
|
+
detail?: string;
|
|
76
|
+
merchant?: DeniedMerchant;
|
|
77
|
+
card?: string;
|
|
78
|
+
appUrl?: string;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Why a payment did not deliver the resource, when the card's policy is *not*
|
|
83
|
+
* the reason. `CardPolicyDenied` means exactly one thing — the card refused —
|
|
84
|
+
* so everything else lands here:
|
|
85
|
+
*
|
|
86
|
+
* - `rejected` — the facilitator (or the transport) refused the payment
|
|
87
|
+
* before anything was submitted: a malformed payload, a fee above the
|
|
88
|
+
* facilitator's ceiling, an expiration it will not accept, a 5xx. Nothing
|
|
89
|
+
* was spent.
|
|
90
|
+
* - `unconfirmed` — the settlement state is unknown or contradictory: the
|
|
91
|
+
* server reported a failure for a transaction the ledger accepted, or the
|
|
92
|
+
* transaction was never observed. The card may have been debited; reconcile
|
|
93
|
+
* `transaction` against the network before retrying.
|
|
94
|
+
*/
|
|
95
|
+
export declare class PaymentError extends Error {
|
|
96
|
+
readonly kind: "rejected" | "unconfirmed";
|
|
97
|
+
readonly transaction?: string;
|
|
98
|
+
readonly detail?: string;
|
|
99
|
+
constructor(opts: {
|
|
100
|
+
kind: "rejected" | "unconfirmed";
|
|
101
|
+
transaction?: string;
|
|
102
|
+
detail?: string;
|
|
103
|
+
});
|
|
104
|
+
}
|
package/dist/denial.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { humanizeEvents } from "@stellar/stellar-sdk";
|
|
2
|
+
/** Card contract error codes that mean "policy denied". */
|
|
3
|
+
export const CARD_ERROR_CODES = {
|
|
4
|
+
1: "bad_signature",
|
|
5
|
+
2: "wrong_context",
|
|
6
|
+
3: "frozen",
|
|
7
|
+
4: "cancelled",
|
|
8
|
+
5: "expired",
|
|
9
|
+
6: "not_allowlisted",
|
|
10
|
+
7: "over_per_tx_cap",
|
|
11
|
+
8: "over_budget",
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Every contract error the card can raise (`CardError`, codes 1..13), with a
|
|
15
|
+
* short user-facing sentence for each. This is the full table: unlike
|
|
16
|
+
* `CARD_ERROR_CODES` (1..8, payment denials only), it also covers the owner
|
|
17
|
+
* operations the web app surfaces (`set_policy`, `set_label`, allowlist
|
|
18
|
+
* management, freeze/cancel/withdraw) so their errors can be shown directly
|
|
19
|
+
* without a separate mapping.
|
|
20
|
+
*/
|
|
21
|
+
export const CARD_ERRORS = {
|
|
22
|
+
1: "The signature is not valid for this card.",
|
|
23
|
+
2: "This action is not the one payment the card's agent key is allowed to sign.",
|
|
24
|
+
3: "This card is frozen.",
|
|
25
|
+
4: "This card has been cancelled.",
|
|
26
|
+
5: "This card has expired.",
|
|
27
|
+
6: "This merchant is not on the card's allowlist.",
|
|
28
|
+
7: "This payment is over the card's per-transaction cap.",
|
|
29
|
+
8: "This would put the card over its budget for the current period.",
|
|
30
|
+
9: "The amount must be a positive number.",
|
|
31
|
+
10: "The card's merchant allowlist is full.",
|
|
32
|
+
11: "That policy is not valid (check the budget, cap and expiry values).",
|
|
33
|
+
12: "This action is not allowed in the card's current state.",
|
|
34
|
+
13: "That label is not valid (it must be 1 to 32 bytes).",
|
|
35
|
+
};
|
|
36
|
+
const CONTRACT_ERROR = /Error\(Contract, #(\d+)\)/;
|
|
37
|
+
/** Parses a Soroban `Error(Contract, #N)` from an error/diagnostic string. */
|
|
38
|
+
export function classifyContractError(text) {
|
|
39
|
+
const m = CONTRACT_ERROR.exec(text);
|
|
40
|
+
if (!m)
|
|
41
|
+
return null;
|
|
42
|
+
const code = Number(m[1]);
|
|
43
|
+
return { code, reason: CARD_ERROR_CODES[code] ?? "unknown" };
|
|
44
|
+
}
|
|
45
|
+
/** The host's phrase that attributes an authorization failure to an account. */
|
|
46
|
+
const AUTH_FAILURE = "failed account authentication with error";
|
|
47
|
+
/**
|
|
48
|
+
* Reads the card's own `__check_auth` verdict out of a transaction's diagnostic
|
|
49
|
+
* events.
|
|
50
|
+
*
|
|
51
|
+
* The card's address alone is not evidence: it appears in the `transfer`
|
|
52
|
+
* arguments of every diagnostic this transaction can produce, and the token's
|
|
53
|
+
* own error codes overlap the card's 1-8 range — a SAC balance error would be
|
|
54
|
+
* read as a policy decision. What identifies an auth failure is the host's
|
|
55
|
+
* event, which names the failing account and its error together:
|
|
56
|
+
*
|
|
57
|
+
* ["failed account authentication with error", <card>, Error(Contract, #N)]
|
|
58
|
+
*
|
|
59
|
+
* so the reason is taken from that event and nowhere else. Anything that does
|
|
60
|
+
* not match returns `null`, and the caller reports `unknown`.
|
|
61
|
+
*/
|
|
62
|
+
export function cardDenialFromEvents(events, card) {
|
|
63
|
+
for (const e of humanizeEvents([...events])) {
|
|
64
|
+
const data = e.data;
|
|
65
|
+
if (!Array.isArray(data) || data.length < 3)
|
|
66
|
+
continue;
|
|
67
|
+
if (data[0] !== AUTH_FAILURE || data[1] !== card)
|
|
68
|
+
continue;
|
|
69
|
+
const err = data[2];
|
|
70
|
+
if (err?.type !== "contract" || typeof err.code !== "number")
|
|
71
|
+
continue;
|
|
72
|
+
return { code: err.code, reason: CARD_ERROR_CODES[err.code] ?? "unknown" };
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/** The hosted Mooring web app, used to build "allow this merchant" links. */
|
|
77
|
+
export const DEFAULT_APP_URL = "https://app.mooring.live";
|
|
78
|
+
/**
|
|
79
|
+
* `origin + pathname` of an absolute URL (drops query and fragment). Input
|
|
80
|
+
* that does not parse (a relative URL, say) is cut at its first `?` or `#`,
|
|
81
|
+
* so a query string can never pass through.
|
|
82
|
+
*/
|
|
83
|
+
export function stripQuery(url) {
|
|
84
|
+
try {
|
|
85
|
+
const u = new URL(url);
|
|
86
|
+
return u.origin + u.pathname;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
const cut = url.search(/[?#]/);
|
|
90
|
+
return cut === -1 ? url : url.slice(0, cut);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** True for an absolute `http:` / `https:` URL. */
|
|
94
|
+
export function isAbsoluteHttpUrl(url) {
|
|
95
|
+
try {
|
|
96
|
+
const { protocol } = new URL(url);
|
|
97
|
+
return protocol === "http:" || protocol === "https:";
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Link to the web app's allow page for a card and a paid service URL (query and fragment are dropped). */
|
|
104
|
+
export function allowMerchantUrl(appBaseUrl, card, serviceUrl) {
|
|
105
|
+
const base = appBaseUrl.endsWith("/") ? appBaseUrl.slice(0, -1) : appBaseUrl;
|
|
106
|
+
return `${base}/allow?card=${card}&url=${encodeURIComponent(stripQuery(serviceUrl))}`;
|
|
107
|
+
}
|
|
108
|
+
export class CardPolicyDenied extends Error {
|
|
109
|
+
reason;
|
|
110
|
+
stage;
|
|
111
|
+
contractError;
|
|
112
|
+
detail;
|
|
113
|
+
merchant;
|
|
114
|
+
constructor(reason, stage, opts = {}) {
|
|
115
|
+
const appUrl = opts.appUrl ?? DEFAULT_APP_URL;
|
|
116
|
+
const link = reason === "not_allowlisted" && opts.merchant?.url && opts.card && appUrl
|
|
117
|
+
? ` — allow it: ${allowMerchantUrl(appUrl, opts.card, opts.merchant.url)}`
|
|
118
|
+
: "";
|
|
119
|
+
super(`card policy denied (${reason}) at ${stage}${opts.contractError ? ` [contract error #${opts.contractError}]` : ""}${opts.detail ? `: ${opts.detail}` : ""}${link}`);
|
|
120
|
+
this.name = "CardPolicyDenied";
|
|
121
|
+
this.reason = reason;
|
|
122
|
+
this.stage = stage;
|
|
123
|
+
this.contractError = opts.contractError;
|
|
124
|
+
this.detail = opts.detail;
|
|
125
|
+
this.merchant = opts.merchant;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Why a payment did not deliver the resource, when the card's policy is *not*
|
|
130
|
+
* the reason. `CardPolicyDenied` means exactly one thing — the card refused —
|
|
131
|
+
* so everything else lands here:
|
|
132
|
+
*
|
|
133
|
+
* - `rejected` — the facilitator (or the transport) refused the payment
|
|
134
|
+
* before anything was submitted: a malformed payload, a fee above the
|
|
135
|
+
* facilitator's ceiling, an expiration it will not accept, a 5xx. Nothing
|
|
136
|
+
* was spent.
|
|
137
|
+
* - `unconfirmed` — the settlement state is unknown or contradictory: the
|
|
138
|
+
* server reported a failure for a transaction the ledger accepted, or the
|
|
139
|
+
* transaction was never observed. The card may have been debited; reconcile
|
|
140
|
+
* `transaction` against the network before retrying.
|
|
141
|
+
*/
|
|
142
|
+
export class PaymentError extends Error {
|
|
143
|
+
kind;
|
|
144
|
+
transaction;
|
|
145
|
+
detail;
|
|
146
|
+
constructor(opts) {
|
|
147
|
+
super(`payment ${opts.kind}${opts.transaction ? ` (tx ${opts.transaction})` : ""}${opts.detail ? `: ${opts.detail}` : ""}`);
|
|
148
|
+
this.name = "PaymentError";
|
|
149
|
+
this.kind = opts.kind;
|
|
150
|
+
this.transaction = opts.transaction;
|
|
151
|
+
this.detail = opts.detail;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=denial.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"denial.js","sourceRoot":"","sources":["../src/denial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAY,MAAM,sBAAsB,CAAC;AAiBhE,2DAA2D;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAAiC;IAC5D,CAAC,EAAE,eAAe;IAClB,CAAC,EAAE,eAAe;IAClB,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,iBAAiB;IACpB,CAAC,EAAE,iBAAiB;IACpB,CAAC,EAAE,aAAa;CACjB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAA2B;IACjD,CAAC,EAAE,2CAA2C;IAC9C,CAAC,EAAE,6EAA6E;IAChF,CAAC,EAAE,sBAAsB;IACzB,CAAC,EAAE,+BAA+B;IAClC,CAAC,EAAE,wBAAwB;IAC3B,CAAC,EAAE,+CAA+C;IAClD,CAAC,EAAE,sDAAsD;IACzD,CAAC,EAAE,iEAAiE;IACpE,CAAC,EAAE,uCAAuC;IAC1C,EAAE,EAAE,wCAAwC;IAC5C,EAAE,EAAE,qEAAqE;IACzE,EAAE,EAAE,yDAAyD;IAC7D,EAAE,EAAE,qDAAqD;CAC1D,CAAC;AAEF,MAAM,cAAc,GAAG,2BAA2B,CAAC;AAEnD,8EAA8E;AAC9E,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;AAC/D,CAAC;AAED,gFAAgF;AAChF,MAAM,YAAY,GAAG,0CAA0C,CAAC;AAEhE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAsC,EACtC,IAAY;IAEZ,KAAK,MAAM,CAAC,IAAI,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACtD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,SAAS;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAiD,CAAC;QACpE,IAAI,GAAG,EAAE,IAAI,KAAK,UAAU,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;IAC7E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAKD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,IAAY,EAAE,UAAkB;IACnF,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7E,OAAO,GAAG,IAAI,eAAe,IAAI,QAAQ,kBAAkB,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,MAAM,CAAe;IACrB,KAAK,CAAc;IACnB,aAAa,CAAU;IACvB,MAAM,CAAU;IAChB,QAAQ,CAAkB;IAEnC,YACE,MAAoB,EACpB,KAAkB,EAClB,OAA+G,EAAE;QAEjH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC;QAC9C,MAAM,IAAI,GACR,MAAM,KAAK,iBAAiB,IAAI,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM;YACvE,CAAC,CAAC,gBAAgB,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YAC1E,CAAC,CAAC,EAAE,CAAC;QACT,KAAK,CAAC,uBAAuB,MAAM,QAAQ,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,qBAAqB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QAC1K,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChC,CAAC;CACF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAA6B;IACjC,WAAW,CAAU;IACrB,MAAM,CAAU;IAEzB,YAAY,IAAiF;QAC3F,KAAK,CACH,WAAW,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACrH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5B,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { signCardAuthEntries } from "./signer.js";
|
|
2
|
+
export { CARD_ERROR_CODES, CARD_ERRORS, CardPolicyDenied, DEFAULT_APP_URL, PaymentError, allowMerchantUrl, cardDenialFromEvents, classifyContractError, } from "./denial.js";
|
|
3
|
+
export type { DeniedMerchant, DenialReason, DenialStage } from "./denial.js";
|
|
4
|
+
export { reconcileSettlement } from "./reconcile.js";
|
|
5
|
+
export type { SettlementOutcome } from "./reconcile.js";
|
|
6
|
+
export { precheck } from "./precheck.js";
|
|
7
|
+
export type { PaymentTerms } from "./precheck.js";
|
|
8
|
+
export { readCardInfo, readMerchants } from "./card.js";
|
|
9
|
+
export type { CardInfo, CardPolicy, CardState } from "./card.js";
|
|
10
|
+
export { CardExactStellarScheme } from "./scheme.js";
|
|
11
|
+
export type { CardSchemeOptions, StellarNetwork } from "./scheme.js";
|
|
12
|
+
export { createMooringClient, createMooringFetch, getSettlement } from "./client.js";
|
|
13
|
+
export type { MooringClientOptions, Settlement } from "./client.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { signCardAuthEntries } from "./signer.js";
|
|
2
|
+
export { CARD_ERROR_CODES, CARD_ERRORS, CardPolicyDenied, DEFAULT_APP_URL, PaymentError, allowMerchantUrl, cardDenialFromEvents, classifyContractError, } from "./denial.js";
|
|
3
|
+
export { reconcileSettlement } from "./reconcile.js";
|
|
4
|
+
export { precheck } from "./precheck.js";
|
|
5
|
+
export { readCardInfo, readMerchants } from "./card.js";
|
|
6
|
+
export { CardExactStellarScheme } from "./scheme.js";
|
|
7
|
+
export { createMooringClient, createMooringFetch, getSettlement } from "./client.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CardInfo } from "./card.js";
|
|
2
|
+
import type { DenialReason } from "./denial.js";
|
|
3
|
+
export interface PaymentTerms {
|
|
4
|
+
payTo: string;
|
|
5
|
+
amount: string;
|
|
6
|
+
asset: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Local mirror of the card's on-chain policy, evaluated before signing so the agent
|
|
10
|
+
* never submits a payment the card will reject. Order matches the contract.
|
|
11
|
+
*/
|
|
12
|
+
export declare function precheck(info: CardInfo, merchants: string[], req: PaymentTerms, nowSeconds: number): DenialReason | null;
|
package/dist/precheck.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local mirror of the card's on-chain policy, evaluated before signing so the agent
|
|
3
|
+
* never submits a payment the card will reject. Order matches the contract.
|
|
4
|
+
*/
|
|
5
|
+
export function precheck(info, merchants, req, nowSeconds) {
|
|
6
|
+
const amount = BigInt(req.amount);
|
|
7
|
+
if (req.asset !== info.token)
|
|
8
|
+
return "wrong_token";
|
|
9
|
+
if (info.state === 1)
|
|
10
|
+
return "frozen";
|
|
11
|
+
if (info.state === 2)
|
|
12
|
+
return "cancelled";
|
|
13
|
+
if (BigInt(nowSeconds) >= info.policy.expiry)
|
|
14
|
+
return "expired";
|
|
15
|
+
if (!merchants.includes(req.payTo))
|
|
16
|
+
return "not_allowlisted";
|
|
17
|
+
if (amount > info.policy.max_per_tx)
|
|
18
|
+
return "over_per_tx_cap";
|
|
19
|
+
if (amount > info.remaining)
|
|
20
|
+
return "over_budget";
|
|
21
|
+
if (amount > info.balance)
|
|
22
|
+
return "insufficient_balance";
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=precheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precheck.js","sourceRoot":"","sources":["../src/precheck.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAc,EAAE,SAAmB,EAAE,GAAiB,EAAE,UAAkB;IACjG,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;QAAE,OAAO,aAAa,CAAC;IACnD,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACtC,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACzC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC/D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAC7D,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,iBAAiB,CAAC;IAC9D,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS;QAAE,OAAO,aAAa,CAAC;IAClD,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO;QAAE,OAAO,sBAAsB,CAAC;IACzD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type xdr } from "@stellar/stellar-sdk";
|
|
2
|
+
import type { StellarNetwork } from "./scheme.js";
|
|
3
|
+
/** What the ledger says about a settlement transaction. */
|
|
4
|
+
export type SettlementOutcome = {
|
|
5
|
+
status: "SUCCESS";
|
|
6
|
+
} | {
|
|
7
|
+
status: "FAILED";
|
|
8
|
+
events: xdr.DiagnosticEvent[];
|
|
9
|
+
} | {
|
|
10
|
+
status: "NOT_FOUND";
|
|
11
|
+
};
|
|
12
|
+
/** Reconciliation window: ~10 s, one RPC read per second. */
|
|
13
|
+
export declare const RECONCILE_ATTEMPTS = 10;
|
|
14
|
+
export declare const RECONCILE_DELAY_MS = 1000;
|
|
15
|
+
/**
|
|
16
|
+
* Asks the network what actually happened to a settlement transaction.
|
|
17
|
+
*
|
|
18
|
+
* The facilitator answers `settle_exact_stellar_transaction_failed` both for a
|
|
19
|
+
* transaction the ledger rejected *and* for one it simply stopped waiting for
|
|
20
|
+
* (its own poll gives up after `maxTimeoutSeconds`), so its "failed" cannot be
|
|
21
|
+
* read as "the payment did not happen" — inclusion can follow the answer. This
|
|
22
|
+
* asks the RPC directly and distinguishes the three real outcomes:
|
|
23
|
+
*
|
|
24
|
+
* - `SUCCESS` — the payment settled; the card was debited even though the
|
|
25
|
+
* server reported a failure and withheld the resource.
|
|
26
|
+
* - `FAILED` — the ledger rejected it; `events` carry the reason, including
|
|
27
|
+
* the card's own `__check_auth` verdict when that is what refused.
|
|
28
|
+
* - `NOT_FOUND` — still not visible when the window closed; the settlement
|
|
29
|
+
* state is unknown.
|
|
30
|
+
*
|
|
31
|
+
* An RPC error is treated as "not seen yet", not as an answer: a reconciliation
|
|
32
|
+
* we could not complete must never be reported as a failed payment.
|
|
33
|
+
*/
|
|
34
|
+
export declare function reconcileSettlement(rpcUrl: string, network: StellarNetwork, hash: string, opts?: {
|
|
35
|
+
attempts?: number;
|
|
36
|
+
delayMs?: number;
|
|
37
|
+
}): Promise<SettlementOutcome>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { rpc } from "@stellar/stellar-sdk";
|
|
2
|
+
/** Reconciliation window: ~10 s, one RPC read per second. */
|
|
3
|
+
export const RECONCILE_ATTEMPTS = 10;
|
|
4
|
+
export const RECONCILE_DELAY_MS = 1000;
|
|
5
|
+
/**
|
|
6
|
+
* Asks the network what actually happened to a settlement transaction.
|
|
7
|
+
*
|
|
8
|
+
* The facilitator answers `settle_exact_stellar_transaction_failed` both for a
|
|
9
|
+
* transaction the ledger rejected *and* for one it simply stopped waiting for
|
|
10
|
+
* (its own poll gives up after `maxTimeoutSeconds`), so its "failed" cannot be
|
|
11
|
+
* read as "the payment did not happen" — inclusion can follow the answer. This
|
|
12
|
+
* asks the RPC directly and distinguishes the three real outcomes:
|
|
13
|
+
*
|
|
14
|
+
* - `SUCCESS` — the payment settled; the card was debited even though the
|
|
15
|
+
* server reported a failure and withheld the resource.
|
|
16
|
+
* - `FAILED` — the ledger rejected it; `events` carry the reason, including
|
|
17
|
+
* the card's own `__check_auth` verdict when that is what refused.
|
|
18
|
+
* - `NOT_FOUND` — still not visible when the window closed; the settlement
|
|
19
|
+
* state is unknown.
|
|
20
|
+
*
|
|
21
|
+
* An RPC error is treated as "not seen yet", not as an answer: a reconciliation
|
|
22
|
+
* we could not complete must never be reported as a failed payment.
|
|
23
|
+
*/
|
|
24
|
+
export async function reconcileSettlement(rpcUrl, network, hash, opts = {}) {
|
|
25
|
+
const attempts = opts.attempts ?? RECONCILE_ATTEMPTS;
|
|
26
|
+
const delayMs = opts.delayMs ?? RECONCILE_DELAY_MS;
|
|
27
|
+
const server = new rpc.Server(rpcUrl, { allowHttp: network === "stellar:testnet" });
|
|
28
|
+
for (let i = 0; i < attempts; i++) {
|
|
29
|
+
try {
|
|
30
|
+
const tx = await server.getTransaction(hash);
|
|
31
|
+
if (tx.status === "SUCCESS")
|
|
32
|
+
return { status: "SUCCESS" };
|
|
33
|
+
if (tx.status === "FAILED")
|
|
34
|
+
return { status: "FAILED", events: tx.diagnosticEventsXdr ?? [] };
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* not visible yet, or the RPC hiccuped: keep waiting */
|
|
38
|
+
}
|
|
39
|
+
if (i < attempts - 1)
|
|
40
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
41
|
+
}
|
|
42
|
+
return { status: "NOT_FOUND" };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../src/reconcile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAY,MAAM,sBAAsB,CAAC;AASrD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc,EACd,OAAuB,EACvB,IAAY,EACZ,OAAgD,EAAE;IAElD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,kBAAkB,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,kBAAkB,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,KAAK,iBAAiB,EAAE,CAAC,CAAC;IAEpF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YAC1D,IAAI,EAAE,CAAC,MAAM,KAAK,QAAQ;gBAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,mBAAmB,IAAI,EAAE,EAAE,CAAC;QAChG,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;QAC1D,CAAC;QACD,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC;YAAE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjC,CAAC"}
|
package/dist/scheme.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Keypair, contract } from "@stellar/stellar-sdk";
|
|
2
|
+
import type { PaymentPayloadResult, PaymentRequirements, SchemeNetworkClient } from "@x402/core/types";
|
|
3
|
+
import { CardPolicyDenied, PaymentError } from "./denial.js";
|
|
4
|
+
export type StellarNetwork = "stellar:testnet" | "stellar:pubnet";
|
|
5
|
+
/**
|
|
6
|
+
* How far ahead the card's auth entry may be valid.
|
|
7
|
+
*
|
|
8
|
+
* The facilitator computes `maxLedger = currentLedger + ceil(maxTimeoutSeconds
|
|
9
|
+
* / estimatedLedgerSeconds)` and rejects an entry more than 2 ledgers beyond
|
|
10
|
+
* it (`invalid_exact_stellar_signature_expiration_too_far`). Its estimate is
|
|
11
|
+
* sampled from Horizon, so it can be slower than the 5 s the stock client
|
|
12
|
+
* assumes — on pubnet it usually is. Aiming low costs nothing: the expiry only
|
|
13
|
+
* has to outlive settlement, and a shorter one is never rejected.
|
|
14
|
+
*/
|
|
15
|
+
export declare function authExpirationLedgers(maxTimeoutSeconds: number): number;
|
|
16
|
+
export interface CardSchemeOptions {
|
|
17
|
+
/** Card contract address (C...). The card is the payer. */
|
|
18
|
+
card: string;
|
|
19
|
+
/** Agent keypair registered as the card's signer. */
|
|
20
|
+
agent: Keypair;
|
|
21
|
+
network: StellarNetwork;
|
|
22
|
+
/** Required on pubnet; optional on testnet. */
|
|
23
|
+
rpcUrl?: string;
|
|
24
|
+
/** Base URL of the Mooring app used in the allow link (default `DEFAULT_APP_URL`). */
|
|
25
|
+
appUrl?: string;
|
|
26
|
+
/** The (query-stripped) URL being paid for; lets a denial carry the allow link. */
|
|
27
|
+
requestUrl?: string;
|
|
28
|
+
/** Called when the card rejects the payment in the enforcing simulation. */
|
|
29
|
+
onDenial?: (denial: CardPolicyDenied) => void;
|
|
30
|
+
/** Called when the payment fails for a reason that is not the card's policy. */
|
|
31
|
+
onPaymentError?: (error: PaymentError) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* x402 "exact" scheme client whose payer is a Mooring card (a Soroban custom
|
|
35
|
+
* account). It produces exactly the same payload as `@x402/stellar`'s
|
|
36
|
+
* `ExactStellarScheme` — one `invokeHostFunction` calling
|
|
37
|
+
* `asset.transfer(card, payTo, amount)`, re-simulated after signing, returned
|
|
38
|
+
* as a base64 transaction envelope. Only the signing differs: the card's auth
|
|
39
|
+
* entries are signed by the agent key through `signCardAuthEntries`, so
|
|
40
|
+
* `__check_auth` enforces the budget, allowlist and expiry at settlement.
|
|
41
|
+
*/
|
|
42
|
+
export declare class CardExactStellarScheme implements SchemeNetworkClient {
|
|
43
|
+
readonly scheme = "exact";
|
|
44
|
+
readonly findDefaultAsset: import("@x402/core/types").FindDefaultAsset<import("@x402/core/types").DefaultAsset>;
|
|
45
|
+
private readonly card;
|
|
46
|
+
private readonly agent;
|
|
47
|
+
private readonly network;
|
|
48
|
+
private readonly rpcUrl;
|
|
49
|
+
private readonly passphrase;
|
|
50
|
+
private readonly appUrl?;
|
|
51
|
+
private readonly requestUrl?;
|
|
52
|
+
private readonly onDenial?;
|
|
53
|
+
private readonly onPaymentError?;
|
|
54
|
+
constructor(opts: CardSchemeOptions);
|
|
55
|
+
/** Throws unless the requirements are an `exact` payment this client can make. */
|
|
56
|
+
validateRequirements(req: PaymentRequirements): void;
|
|
57
|
+
createPaymentPayload(x402Version: number, req: PaymentRequirements): Promise<PaymentPayloadResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Turns a failed enforcing simulation into a typed denial when it was the
|
|
60
|
+
* card's `__check_auth` that said no.
|
|
61
|
+
*
|
|
62
|
+
* The card's address alone is not evidence: it appears in the `transfer`
|
|
63
|
+
* arguments of every diagnostic this transaction can produce, and the token's
|
|
64
|
+
* own error codes overlap the card's 1–8 range — a SAC balance error would be
|
|
65
|
+
* read as a policy decision. What identifies an auth failure is the host's
|
|
66
|
+
* phrase, which names the failing account and its error together:
|
|
67
|
+
*
|
|
68
|
+
* ["failed account authentication with error", <card>, Error(Contract, #N)]
|
|
69
|
+
*
|
|
70
|
+
* so the reason is taken from that fragment and nowhere else. Anything that
|
|
71
|
+
* does not match stays an ordinary error.
|
|
72
|
+
*/
|
|
73
|
+
private denialFromCard;
|
|
74
|
+
/**
|
|
75
|
+
* Refuses to build a payment whose card auth entry the deployed facilitator
|
|
76
|
+
* cannot decode.
|
|
77
|
+
*
|
|
78
|
+
* `buildTransfer` asks the RPC to record legacy v1 `ADDRESS` credentials
|
|
79
|
+
* (`useUpgradedAuth: false`) because OZ Channels rejects CAP-71 `ADDRESS_V2`
|
|
80
|
+
* as `invalid_exact_stellar_payload_malformed`. That flag is transitional —
|
|
81
|
+
* it becomes a no-op from protocol 28 — and an RPC or SDK that ignores it
|
|
82
|
+
* would otherwise produce a payload that is signed, sent and refused with a
|
|
83
|
+
* reason that says nothing about why. This checks what was actually
|
|
84
|
+
* recorded, and fails before the agent key signs anything.
|
|
85
|
+
*/
|
|
86
|
+
private assertLegacyCardCredentials;
|
|
87
|
+
/** Builds and simulates `asset.transfer(from, to, amount)` (SEP-41). */
|
|
88
|
+
protected buildTransfer(asset: string, from: string, to: string, amount: bigint): Promise<contract.AssembledTransaction<unknown>>;
|
|
89
|
+
/** Signs the card's auth entries with the agent key. */
|
|
90
|
+
protected sign(tx: contract.AssembledTransaction<unknown>, expirationLedger: number): Promise<void>;
|
|
91
|
+
/** Current ledger sequence, used as the auth-entry expiration base. */
|
|
92
|
+
protected latestLedger(): Promise<number>;
|
|
93
|
+
}
|