@stellar-agent-services/provider-kit 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +508 -2
- package/dist/approve/assets/index-BazIJAI2.css +1 -0
- package/dist/approve/assets/index-CL28cSJy.js +420 -0
- package/dist/approve/favicon.svg +1 -0
- package/dist/approve/index.html +18 -0
- package/dist/cli/approval-view.d.ts +80 -0
- package/dist/cli/approval-view.d.ts.map +1 -0
- package/dist/cli/approval-view.js +5 -0
- package/dist/cli/approval-view.js.map +1 -0
- package/dist/cli/approval.d.ts +132 -0
- package/dist/cli/approval.d.ts.map +1 -0
- package/dist/cli/approval.js +542 -0
- package/dist/cli/approval.js.map +1 -0
- package/dist/cli/check.d.ts +3 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +137 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/dev-account.d.ts +28 -0
- package/dist/cli/dev-account.d.ts.map +1 -0
- package/dist/cli/dev-account.js +62 -0
- package/dist/cli/dev-account.js.map +1 -0
- package/dist/cli/dev.d.ts +27 -0
- package/dist/cli/dev.d.ts.map +1 -0
- package/dist/cli/dev.js +226 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/discovery.d.ts +20 -0
- package/dist/cli/discovery.d.ts.map +1 -0
- package/dist/cli/discovery.js +202 -0
- package/dist/cli/discovery.js.map +1 -0
- package/dist/cli/env-file.d.ts +16 -0
- package/dist/cli/env-file.d.ts.map +1 -0
- package/dist/cli/env-file.js +77 -0
- package/dist/cli/env-file.js.map +1 -0
- package/dist/cli/fly.d.ts +28 -0
- package/dist/cli/fly.d.ts.map +1 -0
- package/dist/cli/fly.js +92 -0
- package/dist/cli/fly.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +11 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +170 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/launch.d.ts +21 -0
- package/dist/cli/launch.d.ts.map +1 -0
- package/dist/cli/launch.js +627 -0
- package/dist/cli/launch.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +158 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/owner-chain.d.ts +88 -0
- package/dist/cli/owner-chain.d.ts.map +1 -0
- package/dist/cli/owner-chain.js +284 -0
- package/dist/cli/owner-chain.js.map +1 -0
- package/dist/cli/owner-steps.d.ts +33 -0
- package/dist/cli/owner-steps.d.ts.map +1 -0
- package/dist/cli/owner-steps.js +121 -0
- package/dist/cli/owner-steps.js.map +1 -0
- package/dist/cli/processes.d.ts +47 -0
- package/dist/cli/processes.d.ts.map +1 -0
- package/dist/cli/processes.js +129 -0
- package/dist/cli/processes.js.map +1 -0
- package/dist/cli/reconcile.d.ts +3 -0
- package/dist/cli/reconcile.d.ts.map +1 -0
- package/dist/cli/reconcile.js +76 -0
- package/dist/cli/reconcile.js.map +1 -0
- package/dist/cli/register.d.ts +9 -0
- package/dist/cli/register.d.ts.map +1 -0
- package/dist/cli/register.js +209 -0
- package/dist/cli/register.js.map +1 -0
- package/dist/cli/request-validation.d.ts +5 -0
- package/dist/cli/request-validation.d.ts.map +1 -0
- package/dist/cli/request-validation.js +144 -0
- package/dist/cli/request-validation.js.map +1 -0
- package/dist/cli/serve.d.ts +25 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +73 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/shared.d.ts +142 -0
- package/dist/cli/shared.d.ts.map +1 -0
- package/dist/cli/shared.js +110 -0
- package/dist/cli/shared.js.map +1 -0
- package/dist/cli/status.d.ts +32 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +248 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/target.d.ts +14 -0
- package/dist/cli/target.d.ts.map +1 -0
- package/dist/cli/target.js +43 -0
- package/dist/cli/target.js.map +1 -0
- package/dist/cli/trustline.d.ts +3 -0
- package/dist/cli/trustline.d.ts.map +1 -0
- package/dist/cli/trustline.js +114 -0
- package/dist/cli/trustline.js.map +1 -0
- package/dist/cli/try.d.ts +54 -0
- package/dist/cli/try.d.ts.map +1 -0
- package/dist/cli/try.js +450 -0
- package/dist/cli/try.js.map +1 -0
- package/dist/cli/tunnel.d.ts +13 -0
- package/dist/cli/tunnel.d.ts.map +1 -0
- package/dist/cli/tunnel.js +43 -0
- package/dist/cli/tunnel.js.map +1 -0
- package/dist/cli/validators.d.ts +6 -0
- package/dist/cli/validators.d.ts.map +1 -0
- package/dist/cli/validators.js +14 -0
- package/dist/cli/validators.js.map +1 -0
- package/dist/define-service.d.ts +71 -0
- package/dist/define-service.d.ts.map +1 -0
- package/dist/define-service.js +86 -0
- package/dist/define-service.js.map +1 -0
- package/dist/gateway/config.d.ts +88 -0
- package/dist/gateway/config.d.ts.map +1 -0
- package/dist/gateway/config.js +201 -0
- package/dist/gateway/config.js.map +1 -0
- package/dist/gateway/openapi.d.ts +69 -0
- package/dist/gateway/openapi.d.ts.map +1 -0
- package/dist/gateway/openapi.js +677 -0
- package/dist/gateway/openapi.js.map +1 -0
- package/dist/gateway/upstream.d.ts +15 -0
- package/dist/gateway/upstream.d.ts.map +1 -0
- package/dist/gateway/upstream.js +95 -0
- package/dist/gateway/upstream.js.map +1 -0
- package/dist/http/bounded.d.ts +3 -0
- package/dist/http/bounded.d.ts.map +1 -0
- package/dist/http/bounded.js +23 -0
- package/dist/http/bounded.js.map +1 -0
- package/dist/http/node-server.d.ts +15 -0
- package/dist/http/node-server.d.ts.map +1 -0
- package/dist/http/node-server.js +120 -0
- package/dist/http/node-server.js.map +1 -0
- package/dist/http/rate-limit.d.ts +11 -0
- package/dist/http/rate-limit.d.ts.map +1 -0
- package/dist/http/rate-limit.js +35 -0
- package/dist/http/rate-limit.js.map +1 -0
- package/dist/http/router.d.ts +29 -0
- package/dist/http/router.d.ts.map +1 -0
- package/dist/http/router.js +329 -0
- package/dist/http/router.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/memory-store.d.ts +3 -0
- package/dist/jobs/memory-store.d.ts.map +1 -0
- package/dist/jobs/memory-store.js +121 -0
- package/dist/jobs/memory-store.js.map +1 -0
- package/dist/jobs/reconcile.d.ts +22 -0
- package/dist/jobs/reconcile.d.ts.map +1 -0
- package/dist/jobs/reconcile.js +82 -0
- package/dist/jobs/reconcile.js.map +1 -0
- package/dist/jobs/recovery.d.ts +19 -0
- package/dist/jobs/recovery.d.ts.map +1 -0
- package/dist/jobs/recovery.js +65 -0
- package/dist/jobs/recovery.js.map +1 -0
- package/dist/jobs/runner.d.ts +38 -0
- package/dist/jobs/runner.d.ts.map +1 -0
- package/dist/jobs/runner.js +194 -0
- package/dist/jobs/runner.js.map +1 -0
- package/dist/jobs/scheduler.d.ts +66 -0
- package/dist/jobs/scheduler.d.ts.map +1 -0
- package/dist/jobs/scheduler.js +197 -0
- package/dist/jobs/scheduler.js.map +1 -0
- package/dist/jobs/sqlite-store.d.ts +8 -0
- package/dist/jobs/sqlite-store.d.ts.map +1 -0
- package/dist/jobs/sqlite-store.js +231 -0
- package/dist/jobs/sqlite-store.js.map +1 -0
- package/dist/jobs/store.d.ts +118 -0
- package/dist/jobs/store.d.ts.map +1 -0
- package/dist/jobs/store.js +36 -0
- package/dist/jobs/store.js.map +1 -0
- package/dist/manifest.d.ts +11 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +99 -0
- package/dist/manifest.js.map +1 -0
- package/dist/payments/chain.d.ts +23 -0
- package/dist/payments/chain.d.ts.map +1 -0
- package/dist/payments/chain.js +108 -0
- package/dist/payments/chain.js.map +1 -0
- package/dist/payments/facilitator.d.ts +44 -0
- package/dist/payments/facilitator.d.ts.map +1 -0
- package/dist/payments/facilitator.js +125 -0
- package/dist/payments/facilitator.js.map +1 -0
- package/dist/payments/onchain.d.ts +36 -0
- package/dist/payments/onchain.d.ts.map +1 -0
- package/dist/payments/onchain.js +191 -0
- package/dist/payments/onchain.js.map +1 -0
- package/dist/payments/payload-checks.d.ts +22 -0
- package/dist/payments/payload-checks.d.ts.map +1 -0
- package/dist/payments/payload-checks.js +113 -0
- package/dist/payments/payload-checks.js.map +1 -0
- package/dist/payments/settlement.d.ts +22 -0
- package/dist/payments/settlement.d.ts.map +1 -0
- package/dist/payments/settlement.js +65 -0
- package/dist/payments/settlement.js.map +1 -0
- package/dist/payments/x402-server.d.ts +8 -0
- package/dist/payments/x402-server.d.ts.map +1 -0
- package/dist/payments/x402-server.js +74 -0
- package/dist/payments/x402-server.js.map +1 -0
- package/dist/provider.d.ts +63 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +177 -0
- package/dist/provider.js.map +1 -0
- package/dist/registration.d.ts +86 -0
- package/dist/registration.d.ts.map +1 -0
- package/dist/registration.js +162 -0
- package/dist/registration.js.map +1 -0
- package/dist/testing.d.ts +13 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +48 -0
- package/dist/testing.js.map +1 -0
- package/dist/validation-request.d.ts +36 -0
- package/dist/validation-request.d.ts.map +1 -0
- package/dist/validation-request.js +101 -0
- package/dist/validation-request.js.map +1 -0
- package/package.json +55 -4
- package/schemas/gateway-config.schema.json +140 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ProviderManifest, type RuleViolation } from "@stellar-agent-services/protocol";
|
|
2
|
+
import type { Service } from "./define-service.js";
|
|
3
|
+
import type { ProviderConfig } from "./provider.js";
|
|
4
|
+
export declare const DEFAULT_MAX_TIMEOUT_SECONDS = 60;
|
|
5
|
+
export declare function buildManifest(config: ProviderConfig, services: readonly Service[]): ProviderManifest;
|
|
6
|
+
/**
|
|
7
|
+
* Every violation a client or verifier would find in this manifest, served from `manifestUrl`
|
|
8
|
+
* (§2.4). With `dev`, a loopback http:// provider is checked as if it were served over HTTPS [M6].
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkManifest(manifest: ProviderManifest, manifestUrl: string, dev?: boolean): RuleViolation[];
|
|
11
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAOA,OAAO,EAML,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAEnB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAE9C,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,gBAAgB,CAwBpG;AAyBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,aAAa,EAAE,CAqB3G"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Builds the Provider Standard v1 manifest from the provider config, and checks it at startup.
|
|
2
|
+
//
|
|
3
|
+
// The payment option and every URL come from the same config, so the 402 challenge and the manifest
|
|
4
|
+
// can never disagree. createProvider() refuses to start with a manifest that fails the manifest JSON
|
|
5
|
+
// Schema [M9] or checkManifestRules() (§2.4): what a client or verifier would reject is caught before
|
|
6
|
+
// anyone can pay. The router serves it with Cache-Control max-age=300 [M4].
|
|
7
|
+
import { checkManifestRules, PROVIDER_STANDARD, USDC_ASSET, } from "@stellar-agent-services/protocol";
|
|
8
|
+
import schema from "@stellar-agent-services/protocol/manifest.schema.json" with { type: "json" };
|
|
9
|
+
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
10
|
+
import { laneFor } from "./jobs/scheduler.js";
|
|
11
|
+
export const DEFAULT_MAX_TIMEOUT_SECONDS = 60;
|
|
12
|
+
export function buildManifest(config, services) {
|
|
13
|
+
const maxTimeoutSeconds = config.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
|
|
14
|
+
const manifest = {
|
|
15
|
+
standard: PROVIDER_STANDARD,
|
|
16
|
+
provider: config.provider,
|
|
17
|
+
baseUrl: config.baseUrl.replace(/\/+$/, ""),
|
|
18
|
+
payment: {
|
|
19
|
+
protocol: "x402",
|
|
20
|
+
x402Version: 2,
|
|
21
|
+
accepts: [
|
|
22
|
+
{
|
|
23
|
+
scheme: "exact",
|
|
24
|
+
network: config.network,
|
|
25
|
+
asset: USDC_ASSET[config.network],
|
|
26
|
+
payTo: config.payTo,
|
|
27
|
+
maxTimeoutSeconds,
|
|
28
|
+
extra: { areFeesSponsored: true },
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
services: services.map((service) => describe(service, maxTimeoutSeconds)),
|
|
33
|
+
};
|
|
34
|
+
if (config.retentionSeconds !== undefined)
|
|
35
|
+
manifest.jobs = { retentionSeconds: config.retentionSeconds };
|
|
36
|
+
return manifest;
|
|
37
|
+
}
|
|
38
|
+
function describe(service, maxTimeoutSeconds) {
|
|
39
|
+
const descriptor = {
|
|
40
|
+
name: service.name,
|
|
41
|
+
description: service.description,
|
|
42
|
+
price: { amount: service.amount },
|
|
43
|
+
charge: service.charge,
|
|
44
|
+
inputSchema: service.inputSchema,
|
|
45
|
+
outputSchema: service.outputSchema,
|
|
46
|
+
};
|
|
47
|
+
if (service.title !== undefined)
|
|
48
|
+
descriptor.title = service.title;
|
|
49
|
+
if (service.expectedDurationSeconds !== undefined)
|
|
50
|
+
descriptor.expectedDurationSeconds = service.expectedDurationSeconds;
|
|
51
|
+
if (service.examples !== undefined)
|
|
52
|
+
descriptor.examples = service.examples;
|
|
53
|
+
if (service.tags !== undefined)
|
|
54
|
+
descriptor.tags = service.tags;
|
|
55
|
+
if (service.maxInputBytes !== undefined)
|
|
56
|
+
descriptor.maxInputBytes = service.maxInputBytes;
|
|
57
|
+
// What the lane enforces, so the hint matches the 503s [Q2].
|
|
58
|
+
const lane = laneFor(service, maxTimeoutSeconds);
|
|
59
|
+
descriptor.capacity = { concurrency: lane.concurrency, maxQueueWaitSeconds: lane.maxQueued === 0 ? 0 : lane.maxWaitSeconds };
|
|
60
|
+
return descriptor;
|
|
61
|
+
}
|
|
62
|
+
const validateSchema = new Ajv2020({ strict: false, allErrors: true, validateFormats: false }).compile(schema);
|
|
63
|
+
const examples = new Ajv2020({ strict: false, validateFormats: false });
|
|
64
|
+
/**
|
|
65
|
+
* Every violation a client or verifier would find in this manifest, served from `manifestUrl`
|
|
66
|
+
* (§2.4). With `dev`, a loopback http:// provider is checked as if it were served over HTTPS [M6].
|
|
67
|
+
*/
|
|
68
|
+
export function checkManifest(manifest, manifestUrl, dev = false) {
|
|
69
|
+
const local = dev && isLoopback(manifestUrl);
|
|
70
|
+
const https = (url) => (local && url !== undefined && isLoopback(url) ? url.replace(/^http:/, "https:") : url);
|
|
71
|
+
const checked = structuredClone(manifest);
|
|
72
|
+
checked.baseUrl = https(checked.baseUrl);
|
|
73
|
+
for (const field of ["homepage", "termsUrl"]) {
|
|
74
|
+
const url = https(checked.provider[field]);
|
|
75
|
+
if (url !== undefined)
|
|
76
|
+
checked.provider[field] = url;
|
|
77
|
+
}
|
|
78
|
+
const violations = [];
|
|
79
|
+
if (!validateSchema(checked)) {
|
|
80
|
+
for (const error of validateSchema.errors ?? []) {
|
|
81
|
+
violations.push({ rule: "M9", pointer: error.instancePath, message: error.message ?? "does not match the manifest JSON Schema" });
|
|
82
|
+
}
|
|
83
|
+
return violations;
|
|
84
|
+
}
|
|
85
|
+
return checkManifestRules(checked, {
|
|
86
|
+
manifestUrl: https(manifestUrl),
|
|
87
|
+
validateExample: (exampleSchema, value) => examples.validate(exampleSchema, value),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function isLoopback(url) {
|
|
91
|
+
try {
|
|
92
|
+
const { protocol, hostname } = new URL(url);
|
|
93
|
+
return protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(hostname);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type StellarNetwork } from "@stellar-agent-services/protocol";
|
|
2
|
+
import { rpc } from "@stellar/stellar-sdk";
|
|
3
|
+
/** The RPC calls the kit makes: an rpc.Server, or a fake chain in tests. */
|
|
4
|
+
export type ChainReader = Pick<rpc.Server, "getLatestLedger" | "getLedgers" | "getHealth" | "getEvents" | "getTransaction">;
|
|
5
|
+
/**
|
|
6
|
+
* A Soroban RPC client for `network`: `url`, or the public default. Undefined when there is none, as on
|
|
7
|
+
* pubnet, where SDF runs no public RPC.
|
|
8
|
+
*/
|
|
9
|
+
export declare function rpcChain(network: StellarNetwork, url?: string, options?: {
|
|
10
|
+
dev?: boolean;
|
|
11
|
+
}): ChainReader | undefined;
|
|
12
|
+
export interface LedgerClock {
|
|
13
|
+
/** The latest closed ledger. */
|
|
14
|
+
latest(): Promise<number>;
|
|
15
|
+
/** When `ledger` closes, or closed: an estimate, in epoch ms. */
|
|
16
|
+
closesAt(ledger: number): Promise<number>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A clock on `chain`'s ledgers. Readings are cached for a few seconds, and a failed reading rejects
|
|
20
|
+
* until the next one is due: callers fall back to wall-clock deadlines meanwhile.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ledgerClock(chain: Pick<ChainReader, "getLatestLedger" | "getLedgers">): LedgerClock;
|
|
23
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/payments/chain.ts"],"names":[],"mappings":"AAaA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACxF,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAE3C,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,gBAAgB,CAAC,CAAC;AAK5H;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,WAAW,GAAG,SAAS,CASxH;AAED,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAqBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,iBAAiB,GAAG,YAAY,CAAC,GAAG,WAAW,CAsDnG"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Reading the chain: the Soroban RPC calls the kit makes, and a ledger clock.
|
|
2
|
+
//
|
|
3
|
+
// The provider still holds no key and sends nothing; it only reads. Two things need the chain:
|
|
4
|
+
// - Reconciliation (payments/onchain.ts, jobs/reconcile.ts): a payment_uncertain job is decided from
|
|
5
|
+
// the transactions that did, or did not, use its payment [J13].
|
|
6
|
+
// - The ledger clock. A signed payment is valid up to a ledger, not a time [S2]. The clock turns a
|
|
7
|
+
// ledger into an estimated time, from the latest ledger's close time and the recent average ledger
|
|
8
|
+
// duration, so an on-success job's deadline follows its payment however late the client sent it
|
|
9
|
+
// [Q8], and a sweep can tell for sure that a payment expired.
|
|
10
|
+
//
|
|
11
|
+
// Reads go through Soroban RPC, the same server the facilitator and the payment client use. The URL is
|
|
12
|
+
// HTTPS (http://localhost only in development), like the facilitator's.
|
|
13
|
+
import { SOROBAN_RPC_URL } from "@stellar-agent-services/protocol";
|
|
14
|
+
import { rpc } from "@stellar/stellar-sdk";
|
|
15
|
+
/** An RPC call that takes longer fails, and reconciliation tries again on its next round. */
|
|
16
|
+
const RPC_TIMEOUT_MS = 15_000;
|
|
17
|
+
/**
|
|
18
|
+
* A Soroban RPC client for `network`: `url`, or the public default. Undefined when there is none, as on
|
|
19
|
+
* pubnet, where SDF runs no public RPC.
|
|
20
|
+
*/
|
|
21
|
+
export function rpcChain(network, url, options = {}) {
|
|
22
|
+
const target = url ?? SOROBAN_RPC_URL[network];
|
|
23
|
+
if (target === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
const base = new URL(target);
|
|
26
|
+
const loopback = base.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(base.hostname);
|
|
27
|
+
if (base.protocol !== "https:" && !(options.dev && loopback)) {
|
|
28
|
+
throw new TypeError("the Soroban RPC URL must be https:// (http://localhost is allowed with dev: true)");
|
|
29
|
+
}
|
|
30
|
+
return new rpc.Server(target, { timeout: RPC_TIMEOUT_MS, allowHttp: loopback });
|
|
31
|
+
}
|
|
32
|
+
/** Ledgers the average duration is measured over: about eight minutes. */
|
|
33
|
+
const SAMPLE_LEDGERS = 100;
|
|
34
|
+
/** Used when no sample can be read, or a sample looks wrong. Stellar closes a ledger about every 5 s. */
|
|
35
|
+
const DEFAULT_LEDGER_MS = 5000;
|
|
36
|
+
/** How long a reading is used before the chain is read again. */
|
|
37
|
+
const CLOCK_CACHE_MS = 5000;
|
|
38
|
+
/**
|
|
39
|
+
* How long a reading may take. Jobs and paid requests wait for the clock, so a slow RPC makes them
|
|
40
|
+
* fall back to their claim-time deadlines instead of waiting for it.
|
|
41
|
+
*/
|
|
42
|
+
const CLOCK_TIMEOUT_MS = 3000;
|
|
43
|
+
/**
|
|
44
|
+
* A clock on `chain`'s ledgers. Readings are cached for a few seconds, and a failed reading rejects
|
|
45
|
+
* until the next one is due: callers fall back to wall-clock deadlines meanwhile.
|
|
46
|
+
*/
|
|
47
|
+
export function ledgerClock(chain) {
|
|
48
|
+
let reading;
|
|
49
|
+
let readAt = 0;
|
|
50
|
+
let failing = false;
|
|
51
|
+
const read = async () => {
|
|
52
|
+
const latest = await chain.getLatestLedger();
|
|
53
|
+
let sequence = latest.sequence;
|
|
54
|
+
let closedAt = Number(latest.closeTime) * 1000;
|
|
55
|
+
let ledgerMs = DEFAULT_LEDGER_MS;
|
|
56
|
+
try {
|
|
57
|
+
const sample = await chain.getLedgers({ startLedger: Math.max(1, sequence - SAMPLE_LEDGERS), pagination: { limit: 1 } });
|
|
58
|
+
const first = sample.ledgers[0];
|
|
59
|
+
if (first !== undefined && sample.latestLedger > first.sequence) {
|
|
60
|
+
const measured = ((sample.latestLedgerCloseTime - Number(first.ledgerCloseTime)) * 1000) / (sample.latestLedger - first.sequence);
|
|
61
|
+
if (measured >= 1000 && measured <= 60_000)
|
|
62
|
+
ledgerMs = measured;
|
|
63
|
+
}
|
|
64
|
+
sequence = sample.latestLedger;
|
|
65
|
+
closedAt = sample.latestLedgerCloseTime * 1000;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// The latest ledger alone is enough, with the default duration.
|
|
69
|
+
}
|
|
70
|
+
// An RPC that does not report close times: the latest ledger closed within the last few seconds.
|
|
71
|
+
if (!Number.isFinite(closedAt) || closedAt <= 0)
|
|
72
|
+
closedAt = Date.now();
|
|
73
|
+
return { sequence, closedAt, ledgerMs };
|
|
74
|
+
};
|
|
75
|
+
const current = () => {
|
|
76
|
+
if (reading === undefined || Date.now() - readAt >= CLOCK_CACHE_MS) {
|
|
77
|
+
readAt = Date.now();
|
|
78
|
+
reading = withTimeout(read(), CLOCK_TIMEOUT_MS).then((value) => {
|
|
79
|
+
failing = false;
|
|
80
|
+
return value;
|
|
81
|
+
}, (error) => {
|
|
82
|
+
if (!failing)
|
|
83
|
+
console.warn(`[provider-kit] the ledger clock can't read the chain; deadlines fall back to claim times: ${error.message}`);
|
|
84
|
+
failing = true;
|
|
85
|
+
throw error;
|
|
86
|
+
});
|
|
87
|
+
// Callers catch it; this keeps an unobserved rejection from crashing the process.
|
|
88
|
+
reading.catch(() => undefined);
|
|
89
|
+
}
|
|
90
|
+
return reading;
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
latest: async () => (await current()).sequence,
|
|
94
|
+
async closesAt(ledger) {
|
|
95
|
+
const { sequence, closedAt, ledgerMs } = await current();
|
|
96
|
+
return closedAt + (ledger - sequence) * ledgerMs;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function withTimeout(promise, ms) {
|
|
101
|
+
let timer;
|
|
102
|
+
const timeout = new Promise((_, reject) => {
|
|
103
|
+
timer = setTimeout(() => reject(new Error(`no answer in ${ms} ms`)), ms);
|
|
104
|
+
timer.unref();
|
|
105
|
+
});
|
|
106
|
+
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/payments/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { StellarNetwork } from "@stellar-agent-services/protocol";
|
|
2
|
+
import type { PaymentPayload, PaymentRequirements, SettleResponse } from "@x402/core/types";
|
|
3
|
+
export interface VerifyResult {
|
|
4
|
+
isValid: boolean;
|
|
5
|
+
invalidReason?: string;
|
|
6
|
+
payer?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SupportedKind {
|
|
9
|
+
x402Version: number;
|
|
10
|
+
scheme: string;
|
|
11
|
+
network: string;
|
|
12
|
+
extra?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** The facilitator calls the provider makes. httpFacilitator() implements it; tests pass a fake. */
|
|
15
|
+
export interface Facilitator {
|
|
16
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResult>;
|
|
17
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
|
|
18
|
+
/** GET /supported. A fake may leave it out; the startup check is then skipped. */
|
|
19
|
+
supported?(): Promise<{
|
|
20
|
+
kinds: SupportedKind[];
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export interface FacilitatorOptions {
|
|
24
|
+
/** Allows an http://localhost facilitator, for local development. */
|
|
25
|
+
dev?: boolean;
|
|
26
|
+
/** Default 20. */
|
|
27
|
+
verifyTimeoutSeconds?: number;
|
|
28
|
+
/** Default: the payment's maxTimeoutSeconds + 30, since settle waits for the transaction's ledger. */
|
|
29
|
+
settleTimeoutSeconds?: number;
|
|
30
|
+
/** Sent with every call, for facilitators that want an API key. Never a Stellar secret. */
|
|
31
|
+
headers?: Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
export declare class FacilitatorError extends Error {
|
|
34
|
+
name: string;
|
|
35
|
+
}
|
|
36
|
+
/** How long a settle call may take before the kit treats it as uncertain. */
|
|
37
|
+
export declare function settleTimeoutSeconds(maxTimeoutSeconds: number, options?: FacilitatorOptions): number;
|
|
38
|
+
export declare function httpFacilitator(url: string, options?: FacilitatorOptions): Facilitator;
|
|
39
|
+
/**
|
|
40
|
+
* Startup check: the facilitator settles x402 v2 `exact` payments on the network, with fees
|
|
41
|
+
* sponsored as the manifest promises. Throws with the reason otherwise.
|
|
42
|
+
*/
|
|
43
|
+
export declare function checkFacilitator(facilitator: Facilitator, network: StellarNetwork): Promise<void>;
|
|
44
|
+
//# sourceMappingURL=facilitator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../src/payments/facilitator.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG5F,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,oGAAoG;AACpG,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1F,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5F,kFAAkF;IAClF,SAAS,CAAC,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,aAAa,EAAE,CAAA;KAAE,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,kBAAkB;IAClB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sGAAsG;IACtG,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IAChC,IAAI,SAAsB;CACpC;AAOD,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,iBAAiB,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAExG;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAgF1F;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvG"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// The x402 facilitator: verifies and settles payments for the provider, which holds no secret key.
|
|
2
|
+
//
|
|
3
|
+
// httpFacilitator() is the kit's own client rather than @x402/core's HTTPFacilitatorClient, so that:
|
|
4
|
+
// - the URL is HTTPS (http://localhost only in development) and redirects are refused, so a payment
|
|
5
|
+
// is never sent anywhere the operator did not configure;
|
|
6
|
+
// - every call has a deadline. settle's waits for the transaction's ledger, so its default deadline is
|
|
7
|
+
// the payment's maxTimeoutSeconds plus a margin. A settle call that runs out of time is "uncertain",
|
|
8
|
+
// never "failed" (settlement.ts);
|
|
9
|
+
// - only the fields a facilitator needs are sent, and its answers are size-bounded and shape-checked.
|
|
10
|
+
// Testnet: https://x402.org/facilitator supports stellar:testnet + exact with sponsored fees.
|
|
11
|
+
import { readBounded } from "../http/bounded.js";
|
|
12
|
+
export class FacilitatorError extends Error {
|
|
13
|
+
name = "FacilitatorError";
|
|
14
|
+
}
|
|
15
|
+
const DEFAULT_VERIFY_TIMEOUT_SECONDS = 20;
|
|
16
|
+
const SETTLE_TIMEOUT_MARGIN_SECONDS = 30;
|
|
17
|
+
const SUPPORTED_TIMEOUT_SECONDS = 15;
|
|
18
|
+
const MAX_RESPONSE_BYTES = 64 * 1024;
|
|
19
|
+
/** How long a settle call may take before the kit treats it as uncertain. */
|
|
20
|
+
export function settleTimeoutSeconds(maxTimeoutSeconds, options = {}) {
|
|
21
|
+
return options.settleTimeoutSeconds ?? maxTimeoutSeconds + SETTLE_TIMEOUT_MARGIN_SECONDS;
|
|
22
|
+
}
|
|
23
|
+
export function httpFacilitator(url, options = {}) {
|
|
24
|
+
const base = new URL(url);
|
|
25
|
+
const loopback = base.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(base.hostname);
|
|
26
|
+
if (base.protocol !== "https:" && !(options.dev && loopback)) {
|
|
27
|
+
throw new TypeError("the facilitator URL must be https:// (http://localhost is allowed with dev: true)");
|
|
28
|
+
}
|
|
29
|
+
if (base.username !== "" || base.password !== "" || base.search !== "" || base.hash !== "") {
|
|
30
|
+
throw new TypeError("the facilitator URL must not have user info, a query or a fragment");
|
|
31
|
+
}
|
|
32
|
+
const root = base.toString().replace(/\/+$/, "");
|
|
33
|
+
const call = async (path, init) => {
|
|
34
|
+
const response = await fetch(`${root}/${path}`, {
|
|
35
|
+
method: init.method,
|
|
36
|
+
headers: { Accept: "application/json", ...(init.body === undefined ? {} : { "Content-Type": "application/json" }), ...options.headers },
|
|
37
|
+
...(init.body === undefined ? {} : { body: JSON.stringify(init.body) }),
|
|
38
|
+
redirect: "error",
|
|
39
|
+
signal: AbortSignal.timeout(init.timeoutSeconds * 1000),
|
|
40
|
+
});
|
|
41
|
+
const bytes = await readBounded(response.body, MAX_RESPONSE_BYTES);
|
|
42
|
+
if (bytes === undefined)
|
|
43
|
+
throw new FacilitatorError(`${path} answered with more than ${MAX_RESPONSE_BYTES} bytes`);
|
|
44
|
+
const text = new TextDecoder().decode(bytes);
|
|
45
|
+
let body;
|
|
46
|
+
try {
|
|
47
|
+
body = JSON.parse(text);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
throw new FacilitatorError(`${path} answered ${response.status} without JSON`);
|
|
51
|
+
}
|
|
52
|
+
return { status: response.status, body: isObject(body) ? body : {} };
|
|
53
|
+
};
|
|
54
|
+
// Only what the scheme needs: no resource description, no extensions.
|
|
55
|
+
const request = (payload, requirements) => ({
|
|
56
|
+
x402Version: 2,
|
|
57
|
+
paymentPayload: { x402Version: payload.x402Version, accepted: payload.accepted, payload: payload.payload },
|
|
58
|
+
paymentRequirements: requirements,
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
async verify(payload, requirements) {
|
|
62
|
+
const { status, body } = await call("verify", {
|
|
63
|
+
method: "POST",
|
|
64
|
+
body: request(payload, requirements),
|
|
65
|
+
timeoutSeconds: options.verifyTimeoutSeconds ?? DEFAULT_VERIFY_TIMEOUT_SECONDS,
|
|
66
|
+
});
|
|
67
|
+
// A facilitator may answer an invalid payment with 400 and a verify body.
|
|
68
|
+
if (typeof body["isValid"] !== "boolean")
|
|
69
|
+
throw new FacilitatorError(`verify answered ${status}`);
|
|
70
|
+
const result = { isValid: body["isValid"] };
|
|
71
|
+
if (typeof body["invalidReason"] === "string")
|
|
72
|
+
result.invalidReason = body["invalidReason"];
|
|
73
|
+
if (typeof body["payer"] === "string")
|
|
74
|
+
result.payer = body["payer"];
|
|
75
|
+
return result;
|
|
76
|
+
},
|
|
77
|
+
async settle(payload, requirements) {
|
|
78
|
+
const { status, body } = await call("settle", {
|
|
79
|
+
method: "POST",
|
|
80
|
+
body: request(payload, requirements),
|
|
81
|
+
timeoutSeconds: settleTimeoutSeconds(requirements.maxTimeoutSeconds, options),
|
|
82
|
+
});
|
|
83
|
+
if (typeof body["success"] !== "boolean")
|
|
84
|
+
throw new FacilitatorError(`settle answered ${status}`);
|
|
85
|
+
const response = {
|
|
86
|
+
success: body["success"],
|
|
87
|
+
transaction: typeof body["transaction"] === "string" ? body["transaction"] : "",
|
|
88
|
+
network: (typeof body["network"] === "string" ? body["network"] : ""),
|
|
89
|
+
};
|
|
90
|
+
if (typeof body["payer"] === "string")
|
|
91
|
+
response.payer = body["payer"];
|
|
92
|
+
if (typeof body["errorReason"] === "string")
|
|
93
|
+
response.errorReason = body["errorReason"];
|
|
94
|
+
return response;
|
|
95
|
+
},
|
|
96
|
+
async supported() {
|
|
97
|
+
const { status, body } = await call("supported", { method: "GET", timeoutSeconds: SUPPORTED_TIMEOUT_SECONDS });
|
|
98
|
+
// The first call a provider makes, so a missing or wrong API key shows here, before any payment.
|
|
99
|
+
if (status === 401 || status === 403) {
|
|
100
|
+
throw new FacilitatorError(`supported answered ${status}: the facilitator wants an API key, such as an Authorization header (facilitatorHeaders in a gateway config), or refused the one sent`);
|
|
101
|
+
}
|
|
102
|
+
if (status !== 200 || !Array.isArray(body["kinds"]))
|
|
103
|
+
throw new FacilitatorError(`supported answered ${status}`);
|
|
104
|
+
return { kinds: body["kinds"].filter(isObject) };
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Startup check: the facilitator settles x402 v2 `exact` payments on the network, with fees
|
|
110
|
+
* sponsored as the manifest promises. Throws with the reason otherwise.
|
|
111
|
+
*/
|
|
112
|
+
export async function checkFacilitator(facilitator, network) {
|
|
113
|
+
if (facilitator.supported === undefined)
|
|
114
|
+
return;
|
|
115
|
+
const { kinds } = await facilitator.supported();
|
|
116
|
+
const kind = kinds.find((candidate) => candidate.x402Version === 2 && candidate.scheme === "exact" && candidate.network === network);
|
|
117
|
+
if (kind === undefined)
|
|
118
|
+
throw new FacilitatorError(`the facilitator does not support x402 v2 "exact" payments on ${network}`);
|
|
119
|
+
if (kind.extra?.["areFeesSponsored"] !== true)
|
|
120
|
+
throw new FacilitatorError(`the facilitator does not sponsor fees on ${network}`);
|
|
121
|
+
}
|
|
122
|
+
function isObject(value) {
|
|
123
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=facilitator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator.js","sourceRoot":"","sources":["../../src/payments/facilitator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PaymentReceipt, StellarNetwork } from "@stellar-agent-services/protocol";
|
|
2
|
+
import { rpc } from "@stellar/stellar-sdk";
|
|
3
|
+
import type { PaymentClaim } from "../jobs/store.js";
|
|
4
|
+
import type { ChainReader } from "./chain.js";
|
|
5
|
+
export type PaymentLookup = {
|
|
6
|
+
outcome: "settled";
|
|
7
|
+
receipt: PaymentReceipt;
|
|
8
|
+
} | {
|
|
9
|
+
outcome: "not_settled";
|
|
10
|
+
reason: string;
|
|
11
|
+
} | {
|
|
12
|
+
outcome: "undecided";
|
|
13
|
+
reason: string;
|
|
14
|
+
};
|
|
15
|
+
export interface PaymentSearch {
|
|
16
|
+
chain: ChainReader;
|
|
17
|
+
network: StellarNetwork;
|
|
18
|
+
/** The asset contract the payment is in: the manifest's USDC SAC. */
|
|
19
|
+
asset: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* How far before its expiration ledger a payment can land. The provider (http/router.ts) and the
|
|
23
|
+
* facilitator both refuse a signature that expires more than maxTimeoutSeconds (at most 300, §4.1) of
|
|
24
|
+
* ledgers after the payment is verified, counting a ledger as at least one second (they take about
|
|
25
|
+
* five), and a payment lands after its verification. So this window holds every ledger it could have
|
|
26
|
+
* landed in, with room to spare.
|
|
27
|
+
*/
|
|
28
|
+
export declare const SEARCH_WINDOW_LEDGERS = 320;
|
|
29
|
+
/** Ledgers beyond the latest that a signature may expire in, on top of maxTimeoutSeconds. */
|
|
30
|
+
export declare const EXPIRATION_TOLERANCE_LEDGERS = 10;
|
|
31
|
+
/**
|
|
32
|
+
* Looks for the payment `claim` describes. `known` is a transaction the facilitator named. `health` is
|
|
33
|
+
* a recent getHealth() answer, to share one across many lookups; it is read when not given.
|
|
34
|
+
*/
|
|
35
|
+
export declare function findPayment(claim: PaymentClaim, known: string | undefined, search: PaymentSearch, health?: rpc.Api.GetHealthResponse): Promise<PaymentLookup>;
|
|
36
|
+
//# sourceMappingURL=onchain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onchain.d.ts","sourceRoot":"","sources":["../../src/payments/onchain.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvF,OAAO,EAAW,GAAG,EAA8B,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,MAAM,aAAa,GACrB;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,6FAA6F;AAC7F,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAK/C;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,aAAa,EACrB,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,iBAAiB,GACjC,OAAO,CAAC,aAAa,CAAC,CAqDxB"}
|