From 0c3b998f45be825b4520db207209c7c8b02377f1 Mon Sep 17 00:00:00 2001 From: Vladimir Rogojin Date: Fri, 22 May 2026 22:21:52 +0200 Subject: [PATCH 1/2] fix(invoice): accept @nametag (and chain pubkey / alpha1) as --target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `sphere invoice create --target @bob-tag --asset "1000000 UCT"` now resolves the @nametag (or chain pubkey, or alpha1 address) to the canonical `DIRECT://` address before calling `AccountingModule.create Invoice`. Symmetric with `payments send --recipient @nametag` which already accepts these forms. Why resolve at the CLI layer: - `AccountingModule.createInvoice` validates `target.address.starts With('DIRECT://')` (modules/accounting/AccountingModule.ts:906) and throws `INVOICE_INVALID_ADDRESS` otherwise. This is correct SDK behaviour — invoice terms cryptographically bind the recipient identity, so the canonical DIRECT:// form is what gets signed and shipped. - The CLI is the right layer to translate user-facing identifiers (@nametag, chain pubkey, alpha1) into canonical addresses. The same pattern is already in `dm-history` (legacy-cli.ts:3108) and in `payments send --recipient`. - Resolution happens once at create-time; the resolved DIRECT:// address is what's persisted in the invoice's signed terms, so a later nametag rename does NOT invalidate the invoice (which is the correct semantic). Before this fix: $ sphere invoice create --target @bob-tag --asset "1000000 UCT" Error: Invalid target address: must be DIRECT:// format After: $ sphere invoice create --target @bob-tag --asset "1000000 UCT" Invoice created: { ... "address": "DIRECT://0000..." ... } Validated against live testnet during issue-223 cross-process manual recovery test (see sphere-sdk's manual-test-full-recovery.sh + walkthrough doc on PR #222 / branch docs/issue-218-full-recovery-manual-test). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/legacy/legacy-cli.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/legacy/legacy-cli.ts b/src/legacy/legacy-cli.ts index a8ff6d8..632db66 100644 --- a/src/legacy/legacy-cli.ts +++ b/src/legacy/legacy-cli.ts @@ -3761,7 +3761,25 @@ async function main(): Promise { console.error('Usage: invoice-create --target
--asset " " [--nft ] [--due ] [--memo ] [--delivery ] [--terms ]'); process.exit(1); } - const targetAddress = args[targetIdx + 1]; + let targetAddress = args[targetIdx + 1]; + // Accept `@nametag` (and chain-pubkey / alpha1...) as targets for + // user convenience — symmetric with `payments send --recipient`. + // AccountingModule.createInvoice itself requires a canonical + // `DIRECT://` address because invoice terms commit (cryptographically + // bind) the recipient identity, so we resolve once here before + // constructing the request. The resolved address is what gets baked + // into the invoice's signed terms. + if (!targetAddress.startsWith('DIRECT://')) { + const resolved = await sphere.resolve(targetAddress); + if (!resolved || !resolved.directAddress) { + console.error( + `Could not resolve target "${targetAddress}" to a DIRECT:// address. ` + + 'Provide an @nametag, chain pubkey, alpha1 address, or a DIRECT:// address.', + ); + process.exit(1); + } + targetAddress = resolved.directAddress; + } const nftId = nftIdx !== -1 ? args[nftIdx + 1] : undefined; const dueDate = dueIdx !== -1 ? new Date(args[dueIdx + 1]).getTime() : undefined; if (dueDate !== undefined && isNaN(dueDate)) { From 89166a1b38af51b244ca652bce12043b435a6dfd Mon Sep 17 00:00:00 2001 From: Vladimir Rogojin Date: Fri, 22 May 2026 22:30:08 +0200 Subject: [PATCH 2/2] =?UTF-8?q?ci:=20bump=20pinned=20sphere-sdk=20SHA=20?= =?UTF-8?q?=E2=80=94=20refactor=20branch=20deleted;=20pin=20to=20integrati?= =?UTF-8?q?on/all-fixes=20tip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous pinned SHA `86468103a` was the tip of `refactor/extract-cli-to-sphere-cli` at the time the workflow was added. That branch has since been deleted from the public sphere-sdk repo. The commit still exists in the GitHub repo's object database but is no longer reachable via any branch tip, so a default `git clone` does not fetch it and the subsequent `git checkout --detach $SHA` fails with `fatal: unable to read tree`. PR #17's CI started failing for this reason — symptom unrelated to PR contents. Fix: re-pin to `02cb4550fac` (the tip of `integration/all-fixes` after PR #225, the cross-process UXF delivery fix). That branch contains the same CLI-consumed type exports (`CreateInvoiceRequest`, `PayInvoice Params`, `InvoiceRequestedAsset`, encrypt/decrypt helpers, ...) that the original pin provided. Verified locally: grep -E 'CreateInvoiceRequest|PayInvoiceParams|InvoiceRequestedAsset' \ sphere-sdk/index.ts CreateInvoiceRequest, InvoiceRequestedAsset, PayInvoiceParams, Defense-in-depth: add `git fetch origin "$SPHERE_SDK_SHA" || true` before checkout so the workflow keeps working when integration/all- fixes advances past this commit (the SHA stays pinned for supply-chain integrity, but the explicit fetch picks it up via the object database even if it's no longer on a branch tip). Both `ci.yml` and `integration-nightly.yml` updated together so a nightly run stays hermetic with PR CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/ci.yml | 27 ++++++++++++++++------- .github/workflows/integration-nightly.yml | 10 ++++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abf9ec6..eb44df7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,21 +39,32 @@ jobs: - name: Clone sphere-sdk sibling # Pin to a specific commit SHA (not a branch name) for supply-chain # integrity — a branch pointer can be force-pushed or rebased, - # silently changing the code CI builds against. This SHA points at - # the tip of `refactor/extract-cli-to-sphere-cli` at the time of - # this commit; that branch contains `bc07e89 feat(cli-extraction)` - # which promoted CLI-consumed types (CreateInvoiceRequest, - # PayInvoiceParams, encrypt/decrypt helpers, etc.) to the public - # module surface. Those exports have not yet landed on `main` or - # in any published npm version. + # silently changing the code CI builds against. This SHA is the + # tip of `integration/all-fixes` after PR #225 (issue-223 cross- + # process UXF delivery fix) landed; that branch contains the + # CLI-consumed type exports (CreateInvoiceRequest, PayInvoice + # Params, encrypt/decrypt helpers, ...) on the public module + # surface. Those exports have not yet landed on `main` or in any + # published npm version. + # + # Why the bump: the previous pin (86468103a, tip of + # `refactor/extract-cli-to-sphere-cli`) became unreachable to + # `git clone` after the refactor branch was deleted from origin — + # the commit still exists in the GitHub repo object database but + # isn't on any branch tip, so a default `git clone` doesn't fetch + # it and `checkout --detach` fails with "unable to read tree". # # Bump this SHA when a new sphere-sdk commit is required; remove # this whole workaround once sphere-sdk publishes v0.7.1+ to npm # with the post-extraction exports. env: - SPHERE_SDK_SHA: 86468103ac25271b96a338f64349dd0eb472689f + SPHERE_SDK_SHA: 02cb4550facae0bea58c3b04aceaf3059599464b run: | git clone https://github.com/unicity-sphere/sphere-sdk.git ../../sphere-sdk + # The pinned SHA may not be on a branch tip after future merges; + # fetch it explicitly before checkout so the workflow keeps + # working when integration/all-fixes advances past this commit. + git -C ../../sphere-sdk fetch origin "$SPHERE_SDK_SHA" || true git -C ../../sphere-sdk checkout --detach "$SPHERE_SDK_SHA" - name: "Build sphere-sdk (required for file: dependency to resolve types)" diff --git a/.github/workflows/integration-nightly.yml b/.github/workflows/integration-nightly.yml index 1121d04..8808b44 100644 --- a/.github/workflows/integration-nightly.yml +++ b/.github/workflows/integration-nightly.yml @@ -35,11 +35,15 @@ jobs: cache: npm # See ci.yml for the rationale behind the sibling-clone workaround. - # Kept identical here so a nightly run is hermetic w.r.t. ci.yml state. + # Kept identical here (same SHA pin) so a nightly run is hermetic + # w.r.t. ci.yml state — bump both together when needed. - name: Clone sphere-sdk sibling + env: + SPHERE_SDK_SHA: 02cb4550facae0bea58c3b04aceaf3059599464b run: | - git clone --depth 1 --branch refactor/extract-cli-to-sphere-cli \ - https://github.com/unicity-sphere/sphere-sdk.git ../../sphere-sdk + git clone https://github.com/unicity-sphere/sphere-sdk.git ../../sphere-sdk + git -C ../../sphere-sdk fetch origin "$SPHERE_SDK_SHA" || true + git -C ../../sphere-sdk checkout --detach "$SPHERE_SDK_SHA" - name: Build sphere-sdk (required for file: dependency to resolve types) run: |