@integraledger/lcp-binding-stellar 0.9.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;8GAG8G;AAC9G,eAAO,MAAM,UAAU,EAAG,kBAA2B,CAAC;AAEtD,8DAA8D;AAC9D,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,mGAAmG;AACnG,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAElD;;;wFAGwF;AACxF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,kEAAkE;IAClE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,yGAAyG;AACzG,eAAO,MAAM,kBAAkB,sCAAsC,CAAC;AACtE;;gCAEgC;AAChC,eAAO,MAAM,iBAAiB,mDACoB,CAAC;AAkBnD;gCACgC;AAChC,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,cAAc,GACtB,oBAAoB,CAEtB;AAED,uEAAuE;AACvE,eAAO,MAAM,aAAa,IAAI,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Stellar network constants for the LCP CAP-67 muxed-address binding. The binding rides
3
+ * `mux_id = atrHash[:8]` inside a CAP-67 muxed M-address that the seller advertises as `payTo`; the buyer
4
+ * signs a Soroban SAC `transfer(from, to, amount)` whose `to` is that M-address, so the buyer's signature
5
+ * commits the 8-byte prefix atomically with the transfer (canonical LCP §8.3.1 Native Field per the LCP
6
+ * per-chain binding table — the CAP-67 muxed id, not an overlay contract).
7
+ *
8
+ * ★ ONLY 8 bytes ride on-chain. A CAP-67 muxed id is exactly 8 bytes, so the FULL 32-byte atrHash does not
9
+ * fit — the on-chain artifact confirms `atrHash[:8]`, it does not recover the whole hash (that comes from
10
+ * off-chain `extensions.legalContext.info`). See `mux.ts` and the manifest for how the surface stays honest.
11
+ */
12
+ /** The single canonical mux-id derivation scheme LCP-on-Stellar commits to: `mux_id = atrHash[:8]`. The
13
+ * prefix is deliberately public (project_stellar_mux_prefix8_audit) — any observer holding the atrHash can
14
+ * confirm the on-chain mux id matches, which IS the audit-trail property the protocol wants. No HMAC /
15
+ * per-seller-key variant is wired (that would trade auditability for unlinkability, which is not wanted). */
16
+ export const MUX_SCHEME = "atrHash-prefix-8";
17
+ /** The mux id is the first 8 bytes of the 32-byte atrHash. */
18
+ export const MUX_ID_BYTES = 8;
19
+ /** Stellar network passphrases (from the SDK's `Networks`; inlined here so constants stays SDK-free). */
20
+ export const TESTNET_PASSPHRASE = "Test SDF Network ; September 2015";
21
+ /** The pubnet passphrase. Note the spacing — ` ; ` with spaces either side is part of the string, and the
22
+ * passphrase is hashed into every signature, so a single wrong character produces a transaction that
23
+ * verifies against nothing. */
24
+ export const PUBNET_PASSPHRASE = "Public Global Stellar Network ; September 2015";
25
+ const TESTNET = {
26
+ network: "testnet",
27
+ networkPassphrase: TESTNET_PASSPHRASE,
28
+ horizonUrl: "https://horizon-testnet.stellar.org",
29
+ sorobanRpcUrl: "https://soroban-testnet.stellar.org",
30
+ usdcSacContractId: "CAQCFVLOBK5GIULPNZRGATJJMIZL5BSP7X5YJVMGCPTUEPFM4AVSRCJU",
31
+ };
32
+ const PUBNET = {
33
+ network: "pubnet",
34
+ networkPassphrase: PUBNET_PASSPHRASE,
35
+ horizonUrl: "https://horizon.stellar.org",
36
+ sorobanRpcUrl: "https://mainnet.sorobanrpc.com",
37
+ usdcSacContractId: "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
38
+ };
39
+ /** The constants for one network. Both are usable — the CAP-67 muxed id is a ledger primitive, so nothing
40
+ * has to be deployed first. */
41
+ export function getStellarConfig(network) {
42
+ return network === "testnet" ? TESTNET : PUBNET;
43
+ }
44
+ /** USDC on Stellar has 7 decimals — 1 USDC = 10_000_000 base units. */
45
+ export const USDC_DECIMALS = 7;
46
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;8GAG8G;AAC9G,MAAM,CAAC,MAAM,UAAU,GAAG,kBAA2B,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAqB9B,yGAAyG;AACzG,MAAM,CAAC,MAAM,kBAAkB,GAAG,mCAAmC,CAAC;AACtE;;gCAEgC;AAChC,MAAM,CAAC,MAAM,iBAAiB,GAC5B,gDAAgD,CAAC;AAEnD,MAAM,OAAO,GAAyB;IACpC,OAAO,EAAE,SAAS;IAClB,iBAAiB,EAAE,kBAAkB;IACrC,UAAU,EAAE,qCAAqC;IACjD,aAAa,EAAE,qCAAqC;IACpD,iBAAiB,EAAE,0DAA0D;CAC9E,CAAC;AAEF,MAAM,MAAM,GAAyB;IACnC,OAAO,EAAE,QAAQ;IACjB,iBAAiB,EAAE,iBAAiB;IACpC,UAAU,EAAE,6BAA6B;IACzC,aAAa,EAAE,gCAAgC;IAC/C,iBAAiB,EAAE,0DAA0D;CAC9E,CAAC;AAEF;gCACgC;AAChC,MAAM,UAAU,gBAAgB,CAC9B,OAAuB;IAEvB,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAClD,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { buildMuxedDestination, createStellarAdapter, isSettledSuccessfully, STELLAR_PREFIX_NOTE, type StellarAdapter, type StellarMuxConfirmation, type StellarMuxPrefixRecovery, type StellarReader, type StellarSettlementRef, type StellarSettlementView, } from "./adapter.js";
2
+ export { getStellarConfig, MUX_ID_BYTES, MUX_SCHEME, PUBNET_PASSPHRASE, type StellarNetwork, type StellarNetworkConfig, TESTNET_PASSPHRASE, USDC_DECIMALS, } from "./constants.js";
3
+ export { STELLAR_MANIFEST } from "./manifest.js";
4
+ export { type DecodedMuxedAddress, decodeMuxedAddress, deriveMuxId, encodeMuxedAddress, recoverMuxIdPrefix8, verifyMuxedBinding, } from "./mux.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EACL,KAAK,mBAAmB,EACxB,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { buildMuxedDestination, createStellarAdapter, isSettledSuccessfully, STELLAR_PREFIX_NOTE, } from "./adapter.js";
2
+ export { getStellarConfig, MUX_ID_BYTES, MUX_SCHEME, PUBNET_PASSPHRASE, TESTNET_PASSPHRASE, USDC_DECIMALS, } from "./constants.js";
3
+ export { STELLAR_MANIFEST } from "./manifest.js";
4
+ export { decodeMuxedAddress, deriveMuxId, encodeMuxedAddress, recoverMuxIdPrefix8, verifyMuxedBinding, } from "./mux.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GAOpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,iBAAiB,EAGjB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAEL,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,UAAU,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { BindingManifest } from "@integraledger/lcp-binding-core";
2
+ /**
3
+ * The Stellar CAP-67 muxed-address binding manifest.
4
+ *
5
+ * **pattern = "native-field"** — the binding rides `mux_id` inside a CAP-67 muxed M-address (an existing
6
+ * Stellar account primitive), not an overlay contract (canonical LCP §8.3.1 per the LCP per-chain table). The
7
+ * buyer signs the Soroban SAC `transfer` whose `to` is that M-address, so the weld is **signature-grade** —
8
+ * the payer's signature commits the mux id atomically with the transfer.
9
+ *
10
+ * **★ recovery.zeroPartyRecoverable = false AND recovery.forwardIndexable = false — deliberately honest.**
11
+ * A CAP-67 muxed id is exactly **8 bytes**, so only `atrHash[:8]` rides on-chain; the FULL 32-byte atrHash
12
+ * does NOT fit. From a settlement alone you can recover only the 8-byte prefix, which is not the atrHash —
13
+ * so the binding CONFIRMS a known atrHash's prefix-8 against the on-chain mux id (`verifyMuxedBinding`), it
14
+ * does NOT reconstruct the full hash from the chain (that comes from off-chain `extensions.legalContext.info`). Hence
15
+ * `zeroPartyRecoverable: false` (a party with only the settlement cannot derive the atrHash) and
16
+ * `forwardIndexable: false` (no native index over mux prefixes; `enumerate` is a best-effort account scan,
17
+ * `indexing: "account-scan:mux-prefix8"`). The prefix-8 truncation is stated in `finality.note` too.
18
+ *
19
+ * **NO `protocol`, and here is precisely what it is neutral OF.** This binding welds into the destination
20
+ * of a CLASSIC Stellar payment. x402's `exact` scheme for Stellar (read 2026-08-08) is a different flow
21
+ * entirely: "This spec covers SEP-41-compliant Soroban tokens **only**. Classic Stellar assets are not
22
+ * supported", and the payment is an `invokeHostFunction` calling `transfer(from, to, amount)` where
23
+ * "Argument 1 (to): MUST equal `requirements.payTo` exactly".
24
+ *
25
+ * A muxed destination cannot appear in that call — there is no classic payment to mux, and an `M…` address
26
+ * would not equal `payTo` exactly. So a deployment settling through an x402-Stellar facilitator does not
27
+ * get this carrier. That is a scoping fact, not a defect: the binding has never declared `protocol`, and
28
+ * the mux weld is correct on the rail it targets. Stated here so the absence is a measured claim rather
29
+ * than an unexamined default.
30
+ */
31
+ export declare const STELLAR_MANIFEST: BindingManifest;
32
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAkB9B,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The Stellar CAP-67 muxed-address binding manifest.
3
+ *
4
+ * **pattern = "native-field"** — the binding rides `mux_id` inside a CAP-67 muxed M-address (an existing
5
+ * Stellar account primitive), not an overlay contract (canonical LCP §8.3.1 per the LCP per-chain table). The
6
+ * buyer signs the Soroban SAC `transfer` whose `to` is that M-address, so the weld is **signature-grade** —
7
+ * the payer's signature commits the mux id atomically with the transfer.
8
+ *
9
+ * **★ recovery.zeroPartyRecoverable = false AND recovery.forwardIndexable = false — deliberately honest.**
10
+ * A CAP-67 muxed id is exactly **8 bytes**, so only `atrHash[:8]` rides on-chain; the FULL 32-byte atrHash
11
+ * does NOT fit. From a settlement alone you can recover only the 8-byte prefix, which is not the atrHash —
12
+ * so the binding CONFIRMS a known atrHash's prefix-8 against the on-chain mux id (`verifyMuxedBinding`), it
13
+ * does NOT reconstruct the full hash from the chain (that comes from off-chain `extensions.legalContext.info`). Hence
14
+ * `zeroPartyRecoverable: false` (a party with only the settlement cannot derive the atrHash) and
15
+ * `forwardIndexable: false` (no native index over mux prefixes; `enumerate` is a best-effort account scan,
16
+ * `indexing: "account-scan:mux-prefix8"`). The prefix-8 truncation is stated in `finality.note` too.
17
+ *
18
+ * **NO `protocol`, and here is precisely what it is neutral OF.** This binding welds into the destination
19
+ * of a CLASSIC Stellar payment. x402's `exact` scheme for Stellar (read 2026-08-08) is a different flow
20
+ * entirely: "This spec covers SEP-41-compliant Soroban tokens **only**. Classic Stellar assets are not
21
+ * supported", and the payment is an `invokeHostFunction` calling `transfer(from, to, amount)` where
22
+ * "Argument 1 (to): MUST equal `requirements.payTo` exactly".
23
+ *
24
+ * A muxed destination cannot appear in that call — there is no classic payment to mux, and an `M…` address
25
+ * would not equal `payTo` exactly. So a deployment settling through an x402-Stellar facilitator does not
26
+ * get this carrier. That is a scoping fact, not a defect: the binding has never declared `protocol`, and
27
+ * the mux weld is correct on the rail it targets. Stated here so the absence is a measured claim rather
28
+ * than an unexamined default.
29
+ */
30
+ export const STELLAR_MANIFEST = {
31
+ rail: "stellar",
32
+ pattern: "native-field",
33
+ nativeField: "cap67-mux-id",
34
+ recovery: {
35
+ onChain: true,
36
+ zeroPartyRecoverable: false,
37
+ forwardIndexable: false,
38
+ },
39
+ assetBinding: "none", // envelope weld — the mux id carries atrHash[:8] only; the asset never appears in the view
40
+ successGate: "raw-field", // Horizon successful; a txFAILED tx keeps its M-address in the envelope
41
+ indexing: "account-scan:mux-prefix8",
42
+ finality: {
43
+ reversible: false,
44
+ note: "final on ledger close (Soroban SAC transfer) — no on-rail reversal; only atrHash[:8] rides in the CAP-67 mux id, so settlement alone confirms the prefix-8 match but does NOT recover the full hash (the full atrHash comes from off-chain extensions.legalContext.info); recourse is the record's elected forum (PAY-3/RCS-5), never dispute resolution",
45
+ },
46
+ weldGrades: { "cap67-mux": "signature" },
47
+ lifecycleStates: ["proposed", "settled"],
48
+ };
49
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,cAAc;IACvB,WAAW,EAAE,cAAc;IAC3B,QAAQ,EAAE;QACR,OAAO,EAAE,IAAI;QACb,oBAAoB,EAAE,KAAK;QAC3B,gBAAgB,EAAE,KAAK;KACxB;IACD,YAAY,EAAE,MAAM,EAAE,2FAA2F;IACjH,WAAW,EAAE,WAAW,EAAE,wEAAwE;IAClG,QAAQ,EAAE,0BAA0B;IACpC,QAAQ,EAAE;QACR,UAAU,EAAE,KAAK;QACjB,IAAI,EAAE,0VAA0V;KACjW;IACD,UAAU,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE;IACxC,eAAe,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC;CACzC,CAAC"}
package/dist/mux.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /** Derive the 8-byte mux id from a known atrHash: `mux_id = atrHash[:8]`. Throws on a malformed atrHash
2
+ * (fail-fast). Pure — no SDK. */
3
+ export declare function deriveMuxId(atrHash: string): Uint8Array;
4
+ /** Encode a base G-pubkey (StrKey) + 8-byte mux id as a 69-character CAP-67 M-address. Throws on a
5
+ * wrong-length mux id (fail-fast). */
6
+ export declare function encodeMuxedAddress(basePubkey: string, muxId: Uint8Array): string;
7
+ /** The decoded parts of a CAP-67 M-address: the base G-pubkey and the 8-byte mux id prefix. */
8
+ export interface DecodedMuxedAddress {
9
+ basePubkey: string;
10
+ muxId: Uint8Array;
11
+ }
12
+ /** Decode a CAP-67 M-address into its base G-pubkey and 8-byte mux id. Returns `null` for anything that is
13
+ * not a valid M-address (so a settlement scan skips a non-muxed destination without treating it as an
14
+ * error — mirrors the codec's null-vs-throw convention). */
15
+ export declare function decodeMuxedAddress(mAddr: string): DecodedMuxedAddress | null;
16
+ /** Recover the 8-byte mux id PREFIX from a settlement's CAP-67 M-address. This is the ONLY thing on-chain —
17
+ * it is `atrHash[:8]`, NOT the full atrHash. Returned as raw 8 bytes (never a `0x…64hex` value that would
18
+ * read as a full hash). `null` if the address is not a valid M-address. */
19
+ export declare function recoverMuxIdPrefix8(mAddr: string): Uint8Array | null;
20
+ /** CONFIRM (not recover): does a known atrHash's prefix-8 equal the mux id carried by `mAddr`? This is the
21
+ * primary honest surface — an observer holding the atrHash checks the on-chain destination binds to it.
22
+ * `false` for a non-M-address or a malformed atrHash (never throws on those; fail-CLOSED). */
23
+ export declare function verifyMuxedBinding(inputs: {
24
+ muxedM: string;
25
+ atrHash: string;
26
+ }): boolean;
27
+ //# sourceMappingURL=mux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mux.d.ts","sourceRoot":"","sources":["../src/mux.ts"],"names":[],"mappings":"AA0BA;kCACkC;AAClC,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAKvD;AAED;uCACuC;AACvC,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,UAAU,GAChB,MAAM,CAiBR;AAED,+FAA+F;AAC/F,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;6DAE6D;AAC7D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAS5E;AAED;;4EAE4E;AAC5E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAGpE;AAED;;+FAE+F;AAC/F,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAKV"}
package/dist/mux.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The CAP-67 muxed-address atrHash codec — the honest heart of the Stellar binding. Ported from the proven
3
+ * reference mux codec, restricted to the single canonical scheme `mux_id = atrHash[:8]`
4
+ * (project_stellar_mux_prefix8_audit — the HMAC variant is deliberately NOT ported; it trades the wanted
5
+ * auditability for unwanted per-seller unlinkability).
6
+ *
7
+ * ★ CONFIRM-NOT-RECOVER. A CAP-67 muxed id is exactly 8 bytes. `mux_id = atrHash[:8]` therefore carries
8
+ * only the FIRST 8 bytes of the 32-byte atrHash on-chain — the full hash does NOT fit. So this module can:
9
+ * - DERIVE the 8-byte prefix from a known atrHash (`deriveMuxId`);
10
+ * - ENCODE/DECODE a CAP-67 M-address (`encodeMuxedAddress` / `decodeMuxedAddress`), round-tripping the
11
+ * 8-byte id;
12
+ * - CONFIRM that a known atrHash's prefix-8 equals an M-address's on-chain mux id (`verifyMuxedBinding`).
13
+ * It CANNOT recover the full atrHash from a settlement alone — the settlement holds 8 bytes, not 32. The
14
+ * full atrHash is obtained off-chain from `extensions.legalContext.info`; the on-chain mux id is the public match
15
+ * check, not the source of the hash. `recoverMuxIdPrefix8` returns exactly those 8 bytes, labelled as a
16
+ * prefix — never a `0x…64hex` value that would falsely read as a full atrHash.
17
+ */
18
+ import { hexToBytes } from "@integraledger/lcp-binding-core";
19
+ import { bytesEqual, canonicalAtrHash, isAtrHash, } from "@integraledger/lcp-kernel";
20
+ import { StrKey } from "@stellar/stellar-sdk";
21
+ import { MUX_ID_BYTES } from "./constants.js";
22
+ /** Derive the 8-byte mux id from a known atrHash: `mux_id = atrHash[:8]`. Throws on a malformed atrHash
23
+ * (fail-fast). Pure — no SDK. */
24
+ export function deriveMuxId(atrHash) {
25
+ return hexToBytes(canonicalAtrHash(atrHash, "deriveMuxId")).slice(0, MUX_ID_BYTES);
26
+ }
27
+ /** Encode a base G-pubkey (StrKey) + 8-byte mux id as a 69-character CAP-67 M-address. Throws on a
28
+ * wrong-length mux id (fail-fast). */
29
+ export function encodeMuxedAddress(basePubkey, muxId) {
30
+ if (muxId.length !== MUX_ID_BYTES)
31
+ throw new Error(`encodeMuxedAddress: mux id must be exactly ${MUX_ID_BYTES} bytes, got ${muxId.length}`);
32
+ const baseBytes = StrKey.decodeEd25519PublicKey(basePubkey);
33
+ const combined = new Uint8Array(32 + MUX_ID_BYTES);
34
+ combined.set(new Uint8Array(baseBytes.buffer, baseBytes.byteOffset, baseBytes.byteLength), 0);
35
+ combined.set(muxId, 32);
36
+ return StrKey.encodeMed25519PublicKey(Buffer.from(combined));
37
+ }
38
+ /** Decode a CAP-67 M-address into its base G-pubkey and 8-byte mux id. Returns `null` for anything that is
39
+ * not a valid M-address (so a settlement scan skips a non-muxed destination without treating it as an
40
+ * error — mirrors the codec's null-vs-throw convention). */
41
+ export function decodeMuxedAddress(mAddr) {
42
+ if (!StrKey.isValidMed25519PublicKey(mAddr))
43
+ return null;
44
+ const bytes = StrKey.decodeMed25519PublicKey(mAddr);
45
+ const muxId = new Uint8Array(MUX_ID_BYTES);
46
+ muxId.set(bytes.subarray(32, 32 + MUX_ID_BYTES));
47
+ return {
48
+ basePubkey: StrKey.encodeEd25519PublicKey(bytes.subarray(0, 32)),
49
+ muxId,
50
+ };
51
+ }
52
+ /** Recover the 8-byte mux id PREFIX from a settlement's CAP-67 M-address. This is the ONLY thing on-chain —
53
+ * it is `atrHash[:8]`, NOT the full atrHash. Returned as raw 8 bytes (never a `0x…64hex` value that would
54
+ * read as a full hash). `null` if the address is not a valid M-address. */
55
+ export function recoverMuxIdPrefix8(mAddr) {
56
+ const decoded = decodeMuxedAddress(mAddr);
57
+ return decoded === null ? null : decoded.muxId;
58
+ }
59
+ /** CONFIRM (not recover): does a known atrHash's prefix-8 equal the mux id carried by `mAddr`? This is the
60
+ * primary honest surface — an observer holding the atrHash checks the on-chain destination binds to it.
61
+ * `false` for a non-M-address or a malformed atrHash (never throws on those; fail-CLOSED). */
62
+ export function verifyMuxedBinding(inputs) {
63
+ if (!isAtrHash(inputs.atrHash))
64
+ return false;
65
+ const onChain = recoverMuxIdPrefix8(inputs.muxedM);
66
+ if (onChain === null)
67
+ return false;
68
+ return bytesEqual(onChain, deriveMuxId(inputs.atrHash));
69
+ }
70
+ //# sourceMappingURL=mux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mux.js","sourceRoot":"","sources":["../src/mux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,SAAS,GACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;kCACkC;AAClC,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,CAC/D,CAAC,EACD,YAAY,CACb,CAAC;AACJ,CAAC;AAED;uCACuC;AACvC,MAAM,UAAU,kBAAkB,CAChC,UAAkB,EAClB,KAAiB;IAEjB,IAAI,KAAK,CAAC,MAAM,KAAK,YAAY;QAC/B,MAAM,IAAI,KAAK,CACb,8CAA8C,YAAY,eAAe,KAAK,CAAC,MAAM,EAAE,CACxF,CAAC;IACJ,MAAM,SAAS,GAAG,MAAM,CAAC,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;IACnD,QAAQ,CAAC,GAAG,CACV,IAAI,UAAU,CACZ,SAAS,CAAC,MAAM,EAChB,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,UAAU,CACrB,EACD,CAAC,CACF,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,uBAAuB,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC/D,CAAC;AAQD;;6DAE6D;AAC7D,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,KAAK,GAAG,MAAM,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC;IAC3C,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC;IACjD,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChE,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;4EAE4E;AAC5E,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AACjD,CAAC;AAED;;+FAE+F;AAC/F,MAAM,UAAU,kBAAkB,CAAC,MAGlC;IACC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1D,CAAC"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@integraledger/lcp-binding-stellar",
3
+ "version": "0.9.0",
4
+ "description": "Welds an ATR hash into a Stellar payment.",
5
+ "keywords": [
6
+ "lcp",
7
+ "legal-context-protocol",
8
+ "legal-terms",
9
+ "agentic-commerce",
10
+ "settlement",
11
+ "atr-hash",
12
+ "stellar"
13
+ ],
14
+ "type": "module",
15
+ "sideEffects": false,
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "src",
26
+ "CHANGELOG.md",
27
+ "LICENSE",
28
+ "NOTICE"
29
+ ],
30
+ "publishConfig": {
31
+ "registry": "https://registry.npmjs.org",
32
+ "access": "public"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/IntegraLedger/integra-protocol.git",
37
+ "directory": "packages/binding-stellar"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/IntegraLedger/integra-protocol/issues"
41
+ },
42
+ "homepage": "https://github.com/IntegraLedger/integra-protocol/tree/main/packages/binding-stellar#readme",
43
+ "dependencies": {
44
+ "@stellar/stellar-sdk": "16.2.0",
45
+ "@integraledger/lcp-binding-core": "0.9.0",
46
+ "@integraledger/lcp-kernel": "0.9.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/json-schema": "7.0.15",
50
+ "@types/node": "24.13.3",
51
+ "vitest": "4.1.10"
52
+ },
53
+ "license": "Apache-2.0",
54
+ "engines": {
55
+ "node": ">=24"
56
+ },
57
+ "scripts": {
58
+ "build": "tsc -p tsconfig.build.json",
59
+ "typecheck": "tsc -p tsconfig.json --noEmit",
60
+ "test": "vitest run"
61
+ }
62
+ }