@ftptech/x402-canton-client 0.1.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/LICENSE +201 -0
- package/README.md +64 -0
- package/dist/cip56-signer.d.ts +82 -0
- package/dist/cip56-signer.d.ts.map +1 -0
- package/dist/cip56-signer.js +183 -0
- package/dist/cip56-signer.js.map +1 -0
- package/dist/fetch.d.ts +51 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +120 -0
- package/dist/fetch.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/keyfile-signer.d.ts +185 -0
- package/dist/keyfile-signer.d.ts.map +1 -0
- package/dist/keyfile-signer.js +281 -0
- package/dist/keyfile-signer.js.map +1 -0
- package/dist/scheme.d.ts +61 -0
- package/dist/scheme.d.ts.map +1 -0
- package/dist/scheme.js +164 -0
- package/dist/scheme.js.map +1 -0
- package/dist/signer.d.ts +126 -0
- package/dist/signer.d.ts.map +1 -0
- package/dist/signer.js +15 -0
- package/dist/signer.js.map +1 -0
- package/package.json +52 -0
package/dist/scheme.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExactCantonScheme — payer-side x402 scheme client.
|
|
3
|
+
*
|
|
4
|
+
* Composes a `CantonSigner` (which knows how to create a
|
|
5
|
+
* TransferCommand on the agent's participant) with the x402 v2 wire
|
|
6
|
+
* format to produce the PaymentPayload the facilitator expects.
|
|
7
|
+
*
|
|
8
|
+
* Usage pattern (next-tick wrapFetchWithCantonPayment will inline
|
|
9
|
+
* this):
|
|
10
|
+
*
|
|
11
|
+
* const scheme = new ExactCantonScheme(signer);
|
|
12
|
+
* const payload = await scheme.createPaymentPayload(
|
|
13
|
+
* requirements,
|
|
14
|
+
* { url: "https://api.example.com/data" }
|
|
15
|
+
* );
|
|
16
|
+
* // POST the request again with
|
|
17
|
+
* // PAYMENT-SIGNATURE: <base64-encoded JSON payload>
|
|
18
|
+
*/
|
|
19
|
+
import type { PaymentRequirements, X402ResourceInfo, CantonNetwork, CantonPaymentPayload } from "@ftptech/x402-canton-core";
|
|
20
|
+
import type { CantonSigner } from "./signer.js";
|
|
21
|
+
export interface CantonPaymentEnvelope {
|
|
22
|
+
x402Version: 2;
|
|
23
|
+
scheme: "exact-canton";
|
|
24
|
+
network: CantonNetwork;
|
|
25
|
+
resource: X402ResourceInfo;
|
|
26
|
+
accepted: PaymentRequirements;
|
|
27
|
+
payload: CantonPaymentPayload;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when the resource advertises a transferMethod this signer cannot
|
|
31
|
+
* service — e.g. a CIP-56-only wallet (the relay-backed agent wallet) facing a
|
|
32
|
+
* resource that only accepts `external-party-amulet-rules` (the v1 Splice
|
|
33
|
+
* TransferCommand path), or vice versa. Named + carrying both methods so the
|
|
34
|
+
* caller can branch (e.g. surface "fund a different wallet" vs a cryptic
|
|
35
|
+
* "signer does not implement ..."), instead of leaking a bare Error.
|
|
36
|
+
*/
|
|
37
|
+
export declare class SchemeMethodMismatchError extends Error {
|
|
38
|
+
/** What the resource's 402 demanded. */
|
|
39
|
+
readonly required: string;
|
|
40
|
+
/** What this signer actually supports. */
|
|
41
|
+
readonly supported: string;
|
|
42
|
+
constructor(
|
|
43
|
+
/** What the resource's 402 demanded. */
|
|
44
|
+
required: string,
|
|
45
|
+
/** What this signer actually supports. */
|
|
46
|
+
supported: string);
|
|
47
|
+
}
|
|
48
|
+
export declare class ExactCantonScheme {
|
|
49
|
+
private readonly signer;
|
|
50
|
+
constructor(signer: CantonSigner);
|
|
51
|
+
/**
|
|
52
|
+
* Build the full PaymentPayload to send back in PAYMENT-SIGNATURE.
|
|
53
|
+
*
|
|
54
|
+
* Generates a fresh paymentId, stamps x402 metadata onto the
|
|
55
|
+
* on-ledger Transfer.meta, delegates to signer.signCip56Transfer to
|
|
56
|
+
* land the TransferFactory_Transfer, and wraps the result in the v2
|
|
57
|
+
* envelope. Throws if the signer can't service the cip56 path.
|
|
58
|
+
*/
|
|
59
|
+
createPaymentPayload(requirements: PaymentRequirements, resource: X402ResourceInfo): Promise<CantonPaymentEnvelope>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=scheme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheme.d.ts","sourceRoot":"","sources":["../src/scheme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,CAAC,CAAC;IACf,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAEhD,wCAAwC;aACxB,QAAQ,EAAE,MAAM;IAChC,0CAA0C;aAC1B,SAAS,EAAE,MAAM;;IAHjC,wCAAwC;IACxB,QAAQ,EAAE,MAAM;IAChC,0CAA0C;IAC1B,SAAS,EAAE,MAAM;CAiBpC;AAED,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAEjD;;;;;;;OAOG;IACG,oBAAoB,CACxB,YAAY,EAAE,mBAAmB,EACjC,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,qBAAqB,CAAC;CAkHlC"}
|
package/dist/scheme.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExactCantonScheme — payer-side x402 scheme client.
|
|
3
|
+
*
|
|
4
|
+
* Composes a `CantonSigner` (which knows how to create a
|
|
5
|
+
* TransferCommand on the agent's participant) with the x402 v2 wire
|
|
6
|
+
* format to produce the PaymentPayload the facilitator expects.
|
|
7
|
+
*
|
|
8
|
+
* Usage pattern (next-tick wrapFetchWithCantonPayment will inline
|
|
9
|
+
* this):
|
|
10
|
+
*
|
|
11
|
+
* const scheme = new ExactCantonScheme(signer);
|
|
12
|
+
* const payload = await scheme.createPaymentPayload(
|
|
13
|
+
* requirements,
|
|
14
|
+
* { url: "https://api.example.com/data" }
|
|
15
|
+
* );
|
|
16
|
+
* // POST the request again with
|
|
17
|
+
* // PAYMENT-SIGNATURE: <base64-encoded JSON payload>
|
|
18
|
+
*/
|
|
19
|
+
import { randomUUID } from "node:crypto";
|
|
20
|
+
/**
|
|
21
|
+
* Thrown when the resource advertises a transferMethod this signer cannot
|
|
22
|
+
* service — e.g. a CIP-56-only wallet (the relay-backed agent wallet) facing a
|
|
23
|
+
* resource that only accepts `external-party-amulet-rules` (the v1 Splice
|
|
24
|
+
* TransferCommand path), or vice versa. Named + carrying both methods so the
|
|
25
|
+
* caller can branch (e.g. surface "fund a different wallet" vs a cryptic
|
|
26
|
+
* "signer does not implement ..."), instead of leaking a bare Error.
|
|
27
|
+
*/
|
|
28
|
+
export class SchemeMethodMismatchError extends Error {
|
|
29
|
+
required;
|
|
30
|
+
supported;
|
|
31
|
+
constructor(
|
|
32
|
+
/** What the resource's 402 demanded. */
|
|
33
|
+
required,
|
|
34
|
+
/** What this signer actually supports. */
|
|
35
|
+
supported) {
|
|
36
|
+
const hint = supported === "cip56-transfer-factory"
|
|
37
|
+
? " The agent-wallet relay signer is CIP-56-only " +
|
|
38
|
+
"(cip56-transfer-factory) and cannot create a v1 " +
|
|
39
|
+
"external-party-amulet-rules TransferCommand."
|
|
40
|
+
: supported === "(none)"
|
|
41
|
+
? " This signer implements neither signCip56Transfer nor " +
|
|
42
|
+
"signTransferCommand."
|
|
43
|
+
: "";
|
|
44
|
+
super(`this wallet supports ${supported} only; the resource requires ` +
|
|
45
|
+
`${required}.${hint}`);
|
|
46
|
+
this.required = required;
|
|
47
|
+
this.supported = supported;
|
|
48
|
+
this.name = "SchemeMethodMismatchError";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export class ExactCantonScheme {
|
|
52
|
+
signer;
|
|
53
|
+
constructor(signer) {
|
|
54
|
+
this.signer = signer;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build the full PaymentPayload to send back in PAYMENT-SIGNATURE.
|
|
58
|
+
*
|
|
59
|
+
* Generates a fresh paymentId, stamps x402 metadata onto the
|
|
60
|
+
* on-ledger Transfer.meta, delegates to signer.signCip56Transfer to
|
|
61
|
+
* land the TransferFactory_Transfer, and wraps the result in the v2
|
|
62
|
+
* envelope. Throws if the signer can't service the cip56 path.
|
|
63
|
+
*/
|
|
64
|
+
async createPaymentPayload(requirements, resource) {
|
|
65
|
+
const extra = requirements.extra;
|
|
66
|
+
const paymentId = randomUUID();
|
|
67
|
+
if (extra.transferMethod === "external-party-amulet-rules") {
|
|
68
|
+
if (!this.signer.signTransferCommand) {
|
|
69
|
+
// The signer advertised no v1 capability — most commonly the
|
|
70
|
+
// CIP-56-only agent-wallet relay signer. Surface a named, branchable
|
|
71
|
+
// error instead of a cryptic "does not implement ..." (plan §4.3).
|
|
72
|
+
throw new SchemeMethodMismatchError("external-party-amulet-rules", this.signer.signCip56Transfer
|
|
73
|
+
? "cip56-transfer-factory"
|
|
74
|
+
: "(none)");
|
|
75
|
+
}
|
|
76
|
+
const description = JSON.stringify({
|
|
77
|
+
paymentId,
|
|
78
|
+
resourceUrl: resource.url,
|
|
79
|
+
...(extra.merchantContractCid !== undefined
|
|
80
|
+
? { merchantContractCid: extra.merchantContractCid }
|
|
81
|
+
: {}),
|
|
82
|
+
x402Version: 2,
|
|
83
|
+
});
|
|
84
|
+
const signed = await this.signer.signTransferCommand({
|
|
85
|
+
receiver: requirements.payTo,
|
|
86
|
+
delegate: extra.facilitatorParty,
|
|
87
|
+
amount: requirements.amount,
|
|
88
|
+
synchronizerId: extra.synchronizerId,
|
|
89
|
+
description,
|
|
90
|
+
expiresAtMs: Date.now() + requirements.maxTimeoutSeconds * 1000,
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
x402Version: 2,
|
|
94
|
+
scheme: "exact-canton",
|
|
95
|
+
network: requirements.network,
|
|
96
|
+
resource,
|
|
97
|
+
accepted: requirements,
|
|
98
|
+
payload: {
|
|
99
|
+
transferMethod: "external-party-amulet-rules",
|
|
100
|
+
transferCommandCid: signed.transferCommandCid,
|
|
101
|
+
payerParty: signed.payerParty,
|
|
102
|
+
nonce: signed.nonce,
|
|
103
|
+
...(signed.createUpdateId !== undefined
|
|
104
|
+
? { createUpdateId: signed.createUpdateId }
|
|
105
|
+
: {}),
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (extra.transferMethod === "cip56-transfer-factory") {
|
|
110
|
+
if (!this.signer.signCip56Transfer) {
|
|
111
|
+
throw new SchemeMethodMismatchError("cip56-transfer-factory", this.signer.signTransferCommand
|
|
112
|
+
? "external-party-amulet-rules"
|
|
113
|
+
: "(none)");
|
|
114
|
+
}
|
|
115
|
+
// Stash x402 metadata on the on-ledger Transfer.meta so the
|
|
116
|
+
// facilitator's /verify can correlate even though there's no
|
|
117
|
+
// dedicated `description` field on TransferFactory_Transfer.
|
|
118
|
+
// `Map Text Text` encodes as a JSON object in Canton 3.4's
|
|
119
|
+
// JSON Ledger API v2.
|
|
120
|
+
// x402.facilitatorParty MUST be included in Transfer.meta so
|
|
121
|
+
// that CIP-56 factory/registry implementations can add the
|
|
122
|
+
// facilitator as an observer on the resulting TransferInstruction.
|
|
123
|
+
// Without this, the facilitator cannot call getTransactionById
|
|
124
|
+
// for the completed proof path (Canton only returns events the
|
|
125
|
+
// requesting party is a stakeholder in). See scheme spec
|
|
126
|
+
// §Facilitator Visibility for the full requirement.
|
|
127
|
+
const transferMeta = {
|
|
128
|
+
"x402.paymentId": paymentId,
|
|
129
|
+
"x402.resourceUrl": resource.url,
|
|
130
|
+
"x402.version": "2",
|
|
131
|
+
"x402.facilitatorParty": extra.facilitatorParty,
|
|
132
|
+
};
|
|
133
|
+
const signed = await this.signer.signCip56Transfer({
|
|
134
|
+
receiver: requirements.payTo,
|
|
135
|
+
transferFactoryCid: extra.transferFactoryCid,
|
|
136
|
+
transferFactoryTemplateId: extra.transferFactoryTemplateId,
|
|
137
|
+
factoryAdmin: extra.instrumentId.admin,
|
|
138
|
+
instrumentId: extra.instrumentId,
|
|
139
|
+
amount: requirements.amount,
|
|
140
|
+
synchronizerId: extra.synchronizerId,
|
|
141
|
+
facilitatorParty: extra.facilitatorParty,
|
|
142
|
+
transferMeta,
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
x402Version: 2,
|
|
146
|
+
scheme: "exact-canton",
|
|
147
|
+
network: requirements.network,
|
|
148
|
+
resource,
|
|
149
|
+
accepted: requirements,
|
|
150
|
+
payload: {
|
|
151
|
+
transferMethod: "cip56-transfer-factory",
|
|
152
|
+
payerParty: signed.payerParty,
|
|
153
|
+
...(signed.transferInstructionCid !== null
|
|
154
|
+
? { transferInstructionCid: signed.transferInstructionCid }
|
|
155
|
+
: { updateId: signed.updateId }),
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Exhaustiveness — cip56-transfer-factory is the only variant.
|
|
160
|
+
const exhaustive = extra;
|
|
161
|
+
throw new Error(`unsupported transferMethod: ${exhaustive.transferMethod}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=scheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheme.js","sourceRoot":"","sources":["../src/scheme.ts"],"names":[],"mappings":"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"}
|
package/dist/signer.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CantonSigner abstraction for the payer (agent) side.
|
|
3
|
+
*
|
|
4
|
+
* The signer lands the on-ledger artifact the facilitator later
|
|
5
|
+
* verifies, via `signCip56Transfer` — any CIP-56 token (incl. Canton
|
|
6
|
+
* Coin) through Splice's `TransferFactory_Transfer`. Settlement happens
|
|
7
|
+
* directly between sender and receiver; the facilitator's role is just
|
|
8
|
+
* verification (for a merchant with a TransferPreapproval the transfer
|
|
9
|
+
* completes atomically).
|
|
10
|
+
*
|
|
11
|
+
* Implementation: `Cip56KeyfileSigner` — production, Ed25519 PEM key,
|
|
12
|
+
* interactive-submission/prepare+execute. Test stubs use vi.fn().
|
|
13
|
+
*/
|
|
14
|
+
export interface SignTransferCommandInput {
|
|
15
|
+
/** Merchant party id. Same as PaymentRequirements.payTo. */
|
|
16
|
+
receiver: string;
|
|
17
|
+
/** Facilitator party id. Same as extra.facilitatorParty. */
|
|
18
|
+
delegate: string;
|
|
19
|
+
/** Atomic units of the asset (e.g. canton-coin). JSON string. */
|
|
20
|
+
amount: string;
|
|
21
|
+
/** Global Synchronizer id. Same as extra.synchronizerId. */
|
|
22
|
+
synchronizerId: string;
|
|
23
|
+
/** JSON-encoded {paymentId, resourceUrl, merchantContractCid?, x402Version}. */
|
|
24
|
+
description: string;
|
|
25
|
+
/** Optional override for the TransferCommand expiry. Defaults to
|
|
26
|
+
* now + 60s per the maxTimeoutSeconds convention. */
|
|
27
|
+
expiresAtMs?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface SignedTransferCommand {
|
|
30
|
+
/** ContractId of the TransferCommand just created on-ledger. */
|
|
31
|
+
transferCommandCid: string;
|
|
32
|
+
/** The agent's own party id (the TransferCommand.sender). */
|
|
33
|
+
payerParty: string;
|
|
34
|
+
/** Monotonic nonce assigned to this TransferCommand. */
|
|
35
|
+
nonce: number;
|
|
36
|
+
/** updateId of the TransferCommand_Create transaction. Set when the agent
|
|
37
|
+
* uses the relay path (submit/execute returns it); absent for direct
|
|
38
|
+
* KeyfileSigner flows where the create updateId is not surfaced. */
|
|
39
|
+
createUpdateId?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface SignCip56TransferInput {
|
|
42
|
+
/** Merchant party id. Same as PaymentRequirements.payTo. */
|
|
43
|
+
receiver: string;
|
|
44
|
+
/** CIP-56 TransferFactory cid the merchant advertised in
|
|
45
|
+
* `extra.transferFactoryCid`. */
|
|
46
|
+
transferFactoryCid: string;
|
|
47
|
+
/** Hash-prefixed template id of the factory contract. The
|
|
48
|
+
* signer can read this off Scan or pass through what the
|
|
49
|
+
* merchant published. */
|
|
50
|
+
transferFactoryTemplateId: string;
|
|
51
|
+
/** The factory's admin party — clients should source from a
|
|
52
|
+
* trusted location (Scan or the merchant's own published
|
|
53
|
+
* metadata). Implementations check `expectedAdmin` matches the
|
|
54
|
+
* factory's own admin field as a bait-defense. */
|
|
55
|
+
factoryAdmin: string;
|
|
56
|
+
/** `{admin, id}` of the instrument the merchant advertised in
|
|
57
|
+
* `extra.instrumentId`. */
|
|
58
|
+
instrumentId: {
|
|
59
|
+
admin: string;
|
|
60
|
+
id: string;
|
|
61
|
+
};
|
|
62
|
+
/** Atomic units of the instrument. JSON string for precision. */
|
|
63
|
+
amount: string;
|
|
64
|
+
/** Global Synchronizer id. */
|
|
65
|
+
synchronizerId: string;
|
|
66
|
+
/** Optional override for the Transfer.executeBefore. Defaults
|
|
67
|
+
* to now + 60s. */
|
|
68
|
+
executeBeforeMs?: number;
|
|
69
|
+
/** Token-specific extra context to pass into the factory choice's
|
|
70
|
+
* `extraArgs`. For most CIP-56 tokens this is `{values: {}}` for
|
|
71
|
+
* both `context` and `meta`; some implementations want
|
|
72
|
+
* merchant-supplied factoryContext metadata. Canton 3.4 encodes
|
|
73
|
+
* `Map Text Text` as a JSON object (not an array of pairs). */
|
|
74
|
+
extraArgs?: {
|
|
75
|
+
context: {
|
|
76
|
+
values: Record<string, string>;
|
|
77
|
+
};
|
|
78
|
+
meta: {
|
|
79
|
+
values: Record<string, string>;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
/** Facilitator party id from PaymentRequirements.extra.facilitatorParty.
|
|
83
|
+
* MUST be included in Transfer.meta.values["x402.facilitatorParty"]
|
|
84
|
+
* so that CIP-56 factories can add the facilitator as an observer
|
|
85
|
+
* on the resulting TransferInstruction. Without observer status the
|
|
86
|
+
* facilitator cannot verify or settle the payment. */
|
|
87
|
+
facilitatorParty: string;
|
|
88
|
+
/** Free-form metadata appended to the on-ledger Transfer.meta.
|
|
89
|
+
* Will include x402 paymentId, resourceUrl, version, and
|
|
90
|
+
* facilitatorParty (auto-added by ExactCantonScheme.sign). */
|
|
91
|
+
transferMeta?: Record<string, string>;
|
|
92
|
+
}
|
|
93
|
+
export interface SignedCip56Transfer {
|
|
94
|
+
payerParty: string;
|
|
95
|
+
/** Canton ledger updateId of the TransferFactory_Transfer
|
|
96
|
+
* submission. Always set; the client uses this as the
|
|
97
|
+
* Completed-case proof in the PaymentPayload. */
|
|
98
|
+
updateId: string;
|
|
99
|
+
/** ContractId of the TransferInstruction the registry created,
|
|
100
|
+
* IF the result was TransferInstructionResult_Pending. Null for
|
|
101
|
+
* Completed results. */
|
|
102
|
+
transferInstructionCid: string | null;
|
|
103
|
+
}
|
|
104
|
+
export interface CantonSigner {
|
|
105
|
+
/** Party this signer signs as. Same value the facilitator sees
|
|
106
|
+
* in `payload.payerParty`. */
|
|
107
|
+
readonly party: string;
|
|
108
|
+
/**
|
|
109
|
+
* Land a Splice TransferCommand on the agent's participant for the
|
|
110
|
+
* Canton-Coin v1 path. Implementations call
|
|
111
|
+
* /v2/interactive-submission/prepare -> sign the prepared-tx hash with
|
|
112
|
+
* the agent's key -> /execute. Optional: signers that only support
|
|
113
|
+
* CIP-56 may omit this method.
|
|
114
|
+
*/
|
|
115
|
+
signTransferCommand?(input: SignTransferCommandInput): Promise<SignedTransferCommand>;
|
|
116
|
+
/**
|
|
117
|
+
* Exercise TransferFactory_Transfer on the agent's participant
|
|
118
|
+
* for the CIP-56 path. Implementations submit the exercise,
|
|
119
|
+
* extract the TransferInstructionResult from the resulting
|
|
120
|
+
* transaction events, and return the updateId plus (if
|
|
121
|
+
* applicable) the TransferInstruction cid. Optional: signers
|
|
122
|
+
* that only support TransferCommand may omit this method.
|
|
123
|
+
*/
|
|
124
|
+
signCip56Transfer?(input: SignCip56TransferInput): Promise<SignedCip56Transfer>;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=signer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer.d.ts","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAC;IACpB;0DACsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd;;yEAEqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB;sCACkC;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;8BAE0B;IAC1B,yBAAyB,EAAE,MAAM,CAAC;IAClC;;;uDAGmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB;gCAC4B;IAC5B,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB;wBACoB;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;oEAIgE;IAChE,SAAS,CAAC,EAAE;QACV,OAAO,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SAAE,CAAC;QAC5C,IAAI,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SAAE,CAAC;KAC1C,CAAC;IACF;;;;2DAIuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB;;mEAE+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB;;sDAEkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB;;6BAEyB;IACzB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B;mCAC+B;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB;;;;;;OAMG;IACH,mBAAmB,CAAC,CAClB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAElC;;;;;;;OAOG;IACH,iBAAiB,CAAC,CAChB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACjC"}
|
package/dist/signer.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CantonSigner abstraction for the payer (agent) side.
|
|
3
|
+
*
|
|
4
|
+
* The signer lands the on-ledger artifact the facilitator later
|
|
5
|
+
* verifies, via `signCip56Transfer` — any CIP-56 token (incl. Canton
|
|
6
|
+
* Coin) through Splice's `TransferFactory_Transfer`. Settlement happens
|
|
7
|
+
* directly between sender and receiver; the facilitator's role is just
|
|
8
|
+
* verification (for a merchant with a TransferPreapproval the transfer
|
|
9
|
+
* completes atomically).
|
|
10
|
+
*
|
|
11
|
+
* Implementation: `Cip56KeyfileSigner` — production, Ed25519 PEM key,
|
|
12
|
+
* interactive-submission/prepare+execute. Test stubs use vi.fn().
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=signer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer.js","sourceRoot":"","sources":["../src/signer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ftptech/x402-canton-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Canton x402 client SDK — payer side. ExactCantonScheme + signer abstractions for autonomous agents.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "FTP team",
|
|
7
|
+
"homepage": "https://github.com/sunstrike228/canton-x402/tree/main/packages/client#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/sunstrike228/canton-x402.git",
|
|
11
|
+
"directory": "packages/client"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/sunstrike228/canton-x402/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"x402",
|
|
18
|
+
"canton",
|
|
19
|
+
"canton-network",
|
|
20
|
+
"client",
|
|
21
|
+
"payment",
|
|
22
|
+
"fetch",
|
|
23
|
+
"agent"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@ftptech/x402-canton-core": "^0.1.0",
|
|
41
|
+
"@ftptech/x402-canton-ledger": "^0.1.0"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.json",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"lint": "eslint src --max-warnings 0"
|
|
51
|
+
}
|
|
52
|
+
}
|