@chironbuilder/ootle-sdk 0.1.2 → 0.1.4

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/dist/wallet.d.ts CHANGED
@@ -387,6 +387,84 @@ export declare class OotleAccount implements WalletAccountApi {
387
387
  withdrawStealthAndExecute(resourceAddress: string, amount: bigint, workspaceVarName: string, followUpInstructions: Instruction[], relatedComponents?: string[], maxFee?: bigint): Promise<{
388
388
  transactionId: string;
389
389
  }>;
390
+ /**
391
+ * Redeems one *specific, externally-known* stealth (freestanding) UTXO — a commitment this
392
+ * account was told about out of band (e.g. a ticket/ballot/voucher token some other party
393
+ * minted straight to this wallet's address), as opposed to `withdrawStealthAndExecute`'s
394
+ * *amount* drawn from this account's own tracked vault balance. Reveals the output's full
395
+ * value as a `Bucket` on the workspace under id `0`, then runs `followUpInstructions` (which
396
+ * must reference that bucket via `{Workspace: {id: 0, offset: null}}`) in the same signed
397
+ * transaction — e.g. handing it straight to a voting/redemption contract's own method.
398
+ *
399
+ * `revealedAmount` must be the output's *actual* value — there is no client-side way to
400
+ * discover it other than decrypting the UTXO (which this method's `WalletStealthAuthorizer`
401
+ * step does internally, using this account's own view secret, as part of resolving the
402
+ * spend); the caller is expected to already know it from whatever protocol minted the token
403
+ * (e.g. a fixed "amount-1 ballot" convention). A wrong value fails the balance proof inside
404
+ * `prepare()`, not silently.
405
+ *
406
+ * Bypasses the `StealthTransfer` fluent builder (its `spendStealthInput` targets *this
407
+ * account's own* previously-shielded outputs, tracked in local storage — see `unshield`'s doc
408
+ * comment on why no scan-by-commitment API exists for outputs this account never shielded
409
+ * itself) and instead hand-builds the same wire statement `unshield`/`shield`/
410
+ * `withdrawStealthAndExecute` produce via the builder, the same way the reference voter
411
+ * client for this pattern does (a zero-stealth-input-count, `KeyPath`-witnessed, fully-revealed
412
+ * transfer) — `WalletStealthAuthorizer.prepare()` fetches and unblinds the named commitment the
413
+ * same way regardless of which path built the statement.
414
+ *
415
+ * @param relatedComponents Every *other* component `followUpInstructions` touches — same
416
+ * reasoning as `withdrawStealthAndExecute`'s own parameter of the same name.
417
+ */
418
+ redeemStealthOutputAndExecute(resourceAddress: string, commitmentHex: string, revealedAmount: bigint, followUpInstructions: Instruction[], relatedComponents?: string[], maxFee?: bigint): Promise<{
419
+ transactionId: string;
420
+ }>;
421
+ /**
422
+ * Like `redeemStealthOutputAndExecute`, but pays the transaction fee from a **second stealth
423
+ * UTXO** instead of this account's revealed balance — so the transaction never touches, and
424
+ * never reveals, this account's on-chain address at all. Confirmed live: the resulting
425
+ * transaction's `up_substates`/`down_substates` contain only the two stealth UTXOs, the
426
+ * redeemed resource, and whatever `relatedComponents` touch — no `component_...` belonging to
427
+ * this account appears anywhere in it.
428
+ *
429
+ * Required whenever the follow-up call itself carries information that would deanonymize the
430
+ * account if the fee input did (e.g. a voting ballot's ranking): a revealed fee input signs
431
+ * with this account's ordinary key, which links the transaction to the account exactly as
432
+ * plainly as if the whole thing were sent unshielded — see the confidential-rcv-template
433
+ * README's "Fee-from-stealth requirement (MUST)" for the canonical explanation.
434
+ *
435
+ * Both stealth inputs are spent via the same mechanism `redeemStealthOutputAndExecute` uses
436
+ * (KeyPath one-time-key ownership, resolved by decrypting each UTXO with this account's own
437
+ * view secret) — this method just does it twice, for two independent `StealthTransfer`
438
+ * instructions in the same transaction: the redeemed resource's spend carries the follow-up
439
+ * call (main instructions), the fee resource's spend carries `PayFeeFromBucket` (fee
440
+ * instructions, its own separate workspace scope — same convention as `followUpInstructions`,
441
+ * claims workspace id `0` there too).
442
+ *
443
+ * Neither stealth input's one-time key seals the transaction in the sense the protocol's
444
+ * `stealth_seal_with` API suggests one must — empirically (and consistent with how every other
445
+ * stealth-spending method in this file already works), the network accepts a transaction sealed
446
+ * by an arbitrary throwaway keypair as long as every stealth input's one-time-key authorization
447
+ * is signed with respect to that same seal key; `signTransaction` generates one automatically.
448
+ * Deliberately **omits** this account's own ordinary signature entirely (unlike every other
449
+ * stealth-spending method here, which signs with `mustSignWithAccountKey: true` by default) —
450
+ * adding it would attach the account's ordinary public key to the transaction, defeating the
451
+ * entire point of a stealth-funded fee.
452
+ *
453
+ * @param feeResourceAddress The fee-currency resource (almost always XTR/TARI).
454
+ * @param feeCommitmentHex A stealth UTXO of `feeResourceAddress` this account owns, with
455
+ * enough value to cover `maxFee` — e.g. produced by this account's own `shield()` call
456
+ * against `feeResourceAddress`. Consumed in full; the remainder above `maxFee` becomes a new
457
+ * stealth change output back to this account.
458
+ * @returns `feeChangeCommitment` — the new stealth UTXO holding the fee input's unspent
459
+ * remainder. There is no way to discover it other than being told, same as any other stealth
460
+ * output belonging to this account that wasn't created by this account's own `shield()`
461
+ * (which records its own outputs locally) — callers doing several of these in sequence must
462
+ * thread this value into the next call's `feeCommitmentHex` themselves.
463
+ */
464
+ redeemStealthOutputWithPrivateFee(resourceAddress: string, commitmentHex: string, revealedAmount: bigint, followUpInstructions: Instruction[], feeResourceAddress: string, feeCommitmentHex: string, maxFee: bigint, relatedComponents?: string[]): Promise<{
465
+ transactionId: string;
466
+ feeChangeCommitment: string;
467
+ }>;
390
468
  /**
391
469
  * Funds an HTLC (hashed timelock contract): creates a stealth output for `amount` of
392
470
  * `resourceAddress`, gated not by a normal one-time stealth key but by a two-leaf TIP-0006
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EA2BR,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,aAAa,EACb,mCAAmC,EACnC,WAAW,EAIX,mBAAmB,EACnB,aAAa,EACd,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAYxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAI9D,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,mBAAmB,CAAC;AAcrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAIzD,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf;;;wCAGoC;IACpC,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;kCAE8B;IAC9B,2BAA2B,EAAE,MAAM,CAAC;IACpC;yEACqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB;sEACkE;IAClE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;oDACgD;IAChD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;mGAE+F;IAC/F,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CACtC;AAED;;;4CAG4C;AAC5C,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB;iCAC6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf;gFAC4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAmCD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CASpF;AAoCD;;;GAGG;AACH,qBAAa,YAAa,YAAW,gBAAgB;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAgC;IAKhD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IAEzC,OAAO;IAOP,+FAA+F;IAC/F,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,YAAY;IAOrF,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC;IAqB7C;;;;;OAKG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAInC,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC;IAIzC;;;;;;;;OAQG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAKtC,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IA+I5C;;;;;;;;;;;;;;;;OAgBG;IACG,OAAO,CACX,YAAY,EAAE,WAAW,EAAE,EAC3B,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO;wBA8H1E,aAAa;gBAAU,aAAa;;IArBjE;;;;;;;;;;;;;;;;;OAiBG;YACW,YAAY;IA+C1B;;;;;;;;;;;OAWG;YACW,UAAU;IA+BxB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAQ;wBA/G/D,aAAa;gBAAU,aAAa;;IAiJjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,mBAAmB,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS;wBA/KrD,aAAa;gBAAU,aAAa;;IA4NjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,eAAe,CAAC,MAAM,SAAQ,EAAE,OAAO,SAAK,EAAE,YAAY,SAAM;IA0EtE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,MAAM,CACV,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,SAAS,EACf,IAAI,CAAC,EAAE,MAAM,EACb,mBAAmB,SAAK,GACvB,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IAoD1G;;;;;;;;;;;;;;;OAeG;IACG,kBAAkB,CACtB,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA4BzE;;;;;;;;;;;;;OAaG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAOxH;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACG,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,SAAU,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IA0DvI;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACG,yBAAyB,CAC7B,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,oBAAoB,EAAE,WAAW,EAAE,EACnC,iBAAiB,GAAE,MAAM,EAAO,EAChC,MAAM,SAAU,GACf,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IA0CrC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,6BAA6B,CACjC,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,WAAW,EAAE,EACnC,iBAAiB,GAAE,MAAM,EAAO,EAChC,MAAM,SAAU,GACf,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAuFrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACG,iCAAiC,CACrC,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,oBAAoB,EAAE,WAAW,EAAE,EACnC,kBAAkB,EAAE,MAAM,EAC1B,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,EACd,iBAAiB,GAAE,MAAM,EAAO,GAC/B,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IAyHlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,QAAQ,CACZ,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,qBAAqB,EAAE,MAAM,EAC7B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,SAAS,GACd,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IA4CtG;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACG,SAAS,CACb,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAAE,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,SAAS,GACd,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IA8CrC;;;;;;;;;;;;;;;;;OAiBG;IACG,UAAU,CACd,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,MAAM,SAAS,GACd,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAkCrC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACG,aAAa,CACjB,eAAe,EAAE,MAAM,EACvB,sBAAsB,EAAE,MAAM,EAC9B,MAAM,EAAE,MAAM,EACd,MAAM,SAAU,EAChB,IAAI,CAAC,EAAE,MAAM,EACb,mBAAmB,SAAK,GACvB,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IAsE5H;;;;;;;;;OASG;IACG,mBAAmB,CAAC,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAqBrH;;;;;;;;OAQG;IACG,0BAA0B,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAI3F;;;;;;;;;;;;;;;OAeG;IACG,kBAAkB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAiBrD;;;;;;;;;;;;;;OAcG;IACG,sBAAsB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,oBAAoB,EAAE,CAAA;KAAE,CAAC;CA2D5H;AAED;;;;;;;;;GASG;AACH;;;;;;;;;;;;;GAaG;AAIH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb;6DACyD;IACzD,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB,EAAE,MAAM,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,MAAM,CA2BT;AA8DD;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAC5B,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3C,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC5C,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GACzC,YAAY,EAAE,CAiBhB;AAoBD;;;;;;;;;;;GAWG;AACH;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAI9H;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,oBAAoB,EAAE,GAC9B;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EAAE,CASpE;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,oBAAoB,EAAE,EAC/B,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,GACnB;IAAE,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,oBAAoB,EAAE,CAAA;CAAE,CAiBzF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,eAAe,EAAE,MAAM,EACvB,iBAAiB,EAAE,MAAM,GACxB;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAmB9C;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAOjD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCpF;AAwFD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9E;AAED;;0GAE0G;AAC1G,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,eAAe,EACzB,aAAa,EAAE,MAAM,EACrB,SAAS,SAAS,GACjB,OAAO,CAAC,mCAAmC,CAAC,CAwB9C;AAmBD,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,eAAe,EACzB,YAAY,EAAE,mBAAmB,EAAE,EACnC,OAAO,SAAI,EACX,YAAY,SAAM,GACjB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAUhC;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQpG;AAmBD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM5E;AAOD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGvG"}
package/dist/wallet.js CHANGED
@@ -1,4 +1,4 @@
1
- import { OotleWallet, StealthTransfer, TransactionBuilder, WalletStealthAuthorizer, WasmStealthCrypto, XTR_FAUCET_CLAIM_RESOURCE_ADDRESS, XTR_FAUCET_COMPONENT_ADDRESS, XTR_FAUCET_VAULT_ADDRESS, amountLiteral, createOutput, decryptOwnedUtxo, defaultIndexerUrl, getVaultIdsForAccount, resolveMaxEpoch, resolveTransaction, resourceAddressLiteral, sealTransaction, sendTransaction, signTransaction, stealthUtxoSubstateId, submitTransaction, } from "@tari-project/ootle";
1
+ import { Mask, OotleWallet, StealthInput, StealthInputsStatement, StealthOutputsStatement, StealthTransfer, StealthTransferStatement, TransactionBuilder, WalletStealthAuthorizer, WasmStealthCrypto, XTR_FAUCET_CLAIM_RESOURCE_ADDRESS, XTR_FAUCET_COMPONENT_ADDRESS, XTR_FAUCET_VAULT_ADDRESS, amountLiteral, createOutput, decryptOwnedUtxo, defaultIndexerUrl, getVaultIdsForAccount, resolveMaxEpoch, resolveTransaction, resourceAddressLiteral, sealTransaction, sendTransaction, serializeUnsignedTx, signTransaction, stealthUtxoSubstateId, submitTransaction, } from "@tari-project/ootle";
2
2
  import { IndexerProvider } from "@tari-project/ootle-indexer";
3
3
  import { SecretKeyWallet } from "@tari-project/ootle-secret-key-wallet";
4
4
  import { buildScriptPathWitness, buildStealthTransferStatement, createConfidentialWithdrawProofLiteral, createStealthOutputWitness, parseOotleAddress, publicKeyFromSecretKey, schnorrSign, stealthDhSecret, validateStealthTransfer, } from "@tari-project/ootle-wasm";
@@ -993,6 +993,256 @@ export class OotleAccount {
993
993
  await recordKnownVersions(response);
994
994
  return { transactionId };
995
995
  }
996
+ /**
997
+ * Redeems one *specific, externally-known* stealth (freestanding) UTXO — a commitment this
998
+ * account was told about out of band (e.g. a ticket/ballot/voucher token some other party
999
+ * minted straight to this wallet's address), as opposed to `withdrawStealthAndExecute`'s
1000
+ * *amount* drawn from this account's own tracked vault balance. Reveals the output's full
1001
+ * value as a `Bucket` on the workspace under id `0`, then runs `followUpInstructions` (which
1002
+ * must reference that bucket via `{Workspace: {id: 0, offset: null}}`) in the same signed
1003
+ * transaction — e.g. handing it straight to a voting/redemption contract's own method.
1004
+ *
1005
+ * `revealedAmount` must be the output's *actual* value — there is no client-side way to
1006
+ * discover it other than decrypting the UTXO (which this method's `WalletStealthAuthorizer`
1007
+ * step does internally, using this account's own view secret, as part of resolving the
1008
+ * spend); the caller is expected to already know it from whatever protocol minted the token
1009
+ * (e.g. a fixed "amount-1 ballot" convention). A wrong value fails the balance proof inside
1010
+ * `prepare()`, not silently.
1011
+ *
1012
+ * Bypasses the `StealthTransfer` fluent builder (its `spendStealthInput` targets *this
1013
+ * account's own* previously-shielded outputs, tracked in local storage — see `unshield`'s doc
1014
+ * comment on why no scan-by-commitment API exists for outputs this account never shielded
1015
+ * itself) and instead hand-builds the same wire statement `unshield`/`shield`/
1016
+ * `withdrawStealthAndExecute` produce via the builder, the same way the reference voter
1017
+ * client for this pattern does (a zero-stealth-input-count, `KeyPath`-witnessed, fully-revealed
1018
+ * transfer) — `WalletStealthAuthorizer.prepare()` fetches and unblinds the named commitment the
1019
+ * same way regardless of which path built the statement.
1020
+ *
1021
+ * @param relatedComponents Every *other* component `followUpInstructions` touches — same
1022
+ * reasoning as `withdrawStealthAndExecute`'s own parameter of the same name.
1023
+ */
1024
+ async redeemStealthOutputAndExecute(resourceAddress, commitmentHex, revealedAmount, followUpInstructions, relatedComponents = [], maxFee = 100000n) {
1025
+ if (revealedAmount <= 0n) {
1026
+ throw new Error(`redeemStealthOutputAndExecute: revealedAmount must be > 0, got ${revealedAmount}`);
1027
+ }
1028
+ if (!/^[0-9a-f]{64}$/i.test(commitmentHex)) {
1029
+ throw new Error(`redeemStealthOutputAndExecute: commitmentHex must be exactly 64 hex characters (32 bytes)`);
1030
+ }
1031
+ const provider = await this.getProvider();
1032
+ const account = await this.getComponentAddress();
1033
+ const commitment = fromHex(commitmentHex);
1034
+ // An "incomplete" statement: the input side only names the commitment being spent (its mask
1035
+ // and value are recovered later, by the authorizer, from the on-chain UTXO) and declares a
1036
+ // `KeyPath` witness — ordinary one-time-key ownership, the same proof shield/unshield/
1037
+ // withdrawStealthAndExecute use, as opposed to htlcClaim/htlcRefund's script-path leaf. The
1038
+ // output side is empty (no new stealth output at all): the full value is revealed instead.
1039
+ const inputsJson = JSON.stringify({
1040
+ inputs: [{ commitment: commitmentHex, witness: "KeyPath" }],
1041
+ revealed_amount: "0",
1042
+ });
1043
+ const outputsJson = JSON.stringify({
1044
+ outputs: [],
1045
+ revealed_output_amount: revealedAmount.toString(),
1046
+ agg_range_proof: "",
1047
+ });
1048
+ const statement = new StealthTransferStatement(new StealthInputsStatement([], 0n, inputsJson), new StealthOutputsStatement(outputsJson));
1049
+ const maxEpoch = await resolveMaxEpoch(provider);
1050
+ const builder = TransactionBuilder.new(this.network, maxEpoch)
1051
+ .addInstruction({
1052
+ StealthTransfer: {
1053
+ resource_address_ref: { Address: resourceAddress },
1054
+ statement: { __ootleRawJson: statement.toCompactJson() },
1055
+ revealed_input_bucket: null,
1056
+ },
1057
+ })
1058
+ // Claims workspace id 0 for the revealed bucket above — followUpInstructions must reference
1059
+ // it as a plain numeric `{Workspace: {id: 0, offset: null}}`, not a named `{Workspace: ".."}`
1060
+ // (name resolution only applies to instructions built through *this* same chain; raw
1061
+ // pre-built instructions bypass it, same constraint `withdrawStealthAndExecute` documents).
1062
+ .saveVar("redeemed")
1063
+ .withInstructions(followUpInstructions)
1064
+ .feeTransactionPayFromComponent(account, maxFee)
1065
+ .addInput({ substate_id: resourceAddress, version: null })
1066
+ .addInput({ substate_id: stealthUtxoSubstateId(resourceAddress, commitment), version: null })
1067
+ .addInput({ substate_id: account, version: null });
1068
+ for (const vaultId of await getVaultIdsForAccount(provider, account)) {
1069
+ builder.addInput({ substate_id: vaultId, version: null });
1070
+ }
1071
+ for (const component of relatedComponents) {
1072
+ builder.addInput({ substate_id: component, version: null });
1073
+ for (const vaultId of await getVaultIdsForAccount(provider, component)) {
1074
+ builder.addInput({ substate_id: vaultId, version: null });
1075
+ }
1076
+ }
1077
+ const unsignedTx = await resolveTransaction(provider, builder.buildUnsignedTransaction());
1078
+ const spec = {
1079
+ unsignedTx,
1080
+ statement,
1081
+ outputMask: Mask.zero(),
1082
+ state: {
1083
+ resource: resourceAddress,
1084
+ revealedInput: null,
1085
+ inputsToSpend: new Map([[commitmentHex, { input: new StealthInput(commitment), owner: account }]]),
1086
+ outputs: [],
1087
+ revealedOutputAmount: revealedAmount,
1088
+ },
1089
+ requiredSigners: [account],
1090
+ inputs: [{ input: new StealthInput(commitment), owner: account }],
1091
+ };
1092
+ const wallet = new OotleWallet().registerKeyProvider(account, this.signer).setDefaultSigner(account);
1093
+ const viewSecret = await this.signer.getViewSecret();
1094
+ const authorized = await WalletStealthAuthorizer.fromSpec(wallet, spec, { viewSecret, crypto: new WasmStealthCrypto(this.network) }).prepare(provider);
1095
+ const envelope = await authorized.seal();
1096
+ const transactionId = await submitTransaction(provider, envelope);
1097
+ const response = await withTimeout(pollTransactionResult(provider, transactionId), 60_000, "submitting the redemption transaction");
1098
+ await recordKnownVersions(response);
1099
+ return { transactionId };
1100
+ }
1101
+ /**
1102
+ * Like `redeemStealthOutputAndExecute`, but pays the transaction fee from a **second stealth
1103
+ * UTXO** instead of this account's revealed balance — so the transaction never touches, and
1104
+ * never reveals, this account's on-chain address at all. Confirmed live: the resulting
1105
+ * transaction's `up_substates`/`down_substates` contain only the two stealth UTXOs, the
1106
+ * redeemed resource, and whatever `relatedComponents` touch — no `component_...` belonging to
1107
+ * this account appears anywhere in it.
1108
+ *
1109
+ * Required whenever the follow-up call itself carries information that would deanonymize the
1110
+ * account if the fee input did (e.g. a voting ballot's ranking): a revealed fee input signs
1111
+ * with this account's ordinary key, which links the transaction to the account exactly as
1112
+ * plainly as if the whole thing were sent unshielded — see the confidential-rcv-template
1113
+ * README's "Fee-from-stealth requirement (MUST)" for the canonical explanation.
1114
+ *
1115
+ * Both stealth inputs are spent via the same mechanism `redeemStealthOutputAndExecute` uses
1116
+ * (KeyPath one-time-key ownership, resolved by decrypting each UTXO with this account's own
1117
+ * view secret) — this method just does it twice, for two independent `StealthTransfer`
1118
+ * instructions in the same transaction: the redeemed resource's spend carries the follow-up
1119
+ * call (main instructions), the fee resource's spend carries `PayFeeFromBucket` (fee
1120
+ * instructions, its own separate workspace scope — same convention as `followUpInstructions`,
1121
+ * claims workspace id `0` there too).
1122
+ *
1123
+ * Neither stealth input's one-time key seals the transaction in the sense the protocol's
1124
+ * `stealth_seal_with` API suggests one must — empirically (and consistent with how every other
1125
+ * stealth-spending method in this file already works), the network accepts a transaction sealed
1126
+ * by an arbitrary throwaway keypair as long as every stealth input's one-time-key authorization
1127
+ * is signed with respect to that same seal key; `signTransaction` generates one automatically.
1128
+ * Deliberately **omits** this account's own ordinary signature entirely (unlike every other
1129
+ * stealth-spending method here, which signs with `mustSignWithAccountKey: true` by default) —
1130
+ * adding it would attach the account's ordinary public key to the transaction, defeating the
1131
+ * entire point of a stealth-funded fee.
1132
+ *
1133
+ * @param feeResourceAddress The fee-currency resource (almost always XTR/TARI).
1134
+ * @param feeCommitmentHex A stealth UTXO of `feeResourceAddress` this account owns, with
1135
+ * enough value to cover `maxFee` — e.g. produced by this account's own `shield()` call
1136
+ * against `feeResourceAddress`. Consumed in full; the remainder above `maxFee` becomes a new
1137
+ * stealth change output back to this account.
1138
+ * @returns `feeChangeCommitment` — the new stealth UTXO holding the fee input's unspent
1139
+ * remainder. There is no way to discover it other than being told, same as any other stealth
1140
+ * output belonging to this account that wasn't created by this account's own `shield()`
1141
+ * (which records its own outputs locally) — callers doing several of these in sequence must
1142
+ * thread this value into the next call's `feeCommitmentHex` themselves.
1143
+ */
1144
+ async redeemStealthOutputWithPrivateFee(resourceAddress, commitmentHex, revealedAmount, followUpInstructions, feeResourceAddress, feeCommitmentHex, maxFee, relatedComponents = []) {
1145
+ if (revealedAmount <= 0n)
1146
+ throw new Error(`redeemStealthOutputWithPrivateFee: revealedAmount must be > 0, got ${revealedAmount}`);
1147
+ if (maxFee <= 0n)
1148
+ throw new Error(`redeemStealthOutputWithPrivateFee: maxFee must be > 0, got ${maxFee}`);
1149
+ const provider = await this.getProvider();
1150
+ const crypto = new WasmStealthCrypto(this.network);
1151
+ const walletAddress = await this.getWalletAddress();
1152
+ const viewSecret = await this.signer.getViewSecret();
1153
+ const decryptStealthInput = async (resource, commitmentHexIn) => {
1154
+ const commitment = fromHex(commitmentHexIn);
1155
+ const substateId = stealthUtxoSubstateId(resource, commitment);
1156
+ const substate = await provider.getSubstate(substateId);
1157
+ const decrypted = await decryptOwnedUtxo(crypto, viewSecret, substate, substateId);
1158
+ if (!decrypted) {
1159
+ throw new Error(`redeemStealthOutputWithPrivateFee: cannot decrypt ${substateId} -- it doesn't belong to this account, or is already spent.`);
1160
+ }
1161
+ return { commitmentHex: commitmentHexIn, substateId, mask: decrypted.mask, value: decrypted.value };
1162
+ };
1163
+ const redeemed = await decryptStealthInput(resourceAddress, commitmentHex);
1164
+ const feeInput = await decryptStealthInput(feeResourceAddress, feeCommitmentHex);
1165
+ if (feeInput.value <= maxFee) {
1166
+ throw new Error(`redeemStealthOutputWithPrivateFee: fee UTXO (${feeInput.value}) is too small to cover maxFee (${maxFee})`);
1167
+ }
1168
+ const feeChange = feeInput.value - maxFee;
1169
+ const inputSkeleton = (hex) => JSON.stringify({ inputs: [{ commitment: hex, witness: "KeyPath" }], revealed_amount: "0" });
1170
+ // Redeemed resource: 1 stealth input -> 0 stealth outputs, fully revealed into the bucket
1171
+ // `followUpInstructions` consumes.
1172
+ const redeemedInputsStatement = new StealthInputsStatement([], 0n, inputSkeleton(redeemed.commitmentHex));
1173
+ const redeemedOutputsStatement = new StealthOutputsStatement(JSON.stringify({ outputs: [], revealed_output_amount: revealedAmount.toString(), agg_range_proof: "" }));
1174
+ const redeemedAggInputMask = await crypto.aggregateInputMasks([redeemed.mask]);
1175
+ const redeemedBalanceProof = await crypto.generateBalanceProofSignature(redeemedAggInputMask, Mask.zero(), redeemedInputsStatement.statementJson, redeemedOutputsStatement.statementJson);
1176
+ const redeemedStatement = new StealthTransferStatement(redeemedInputsStatement, redeemedOutputsStatement, redeemedBalanceProof);
1177
+ await crypto.validateTransfer(redeemedStatement);
1178
+ // Fee resource: 1 stealth input -> 1 stealth change output + revealed maxFee.
1179
+ const feeChangeOutput = createOutput({ destination: walletAddress, amount: feeChange, resourceAddress: feeResourceAddress });
1180
+ const { statement: feeOutputsStatement, outputMask: feeOutputMask } = await crypto.generateOutputsStatement([feeChangeOutput], maxFee);
1181
+ const feeInputsStatement = new StealthInputsStatement([], 0n, inputSkeleton(feeInput.commitmentHex));
1182
+ const feeAggInputMask = await crypto.aggregateInputMasks([feeInput.mask]);
1183
+ const feeBalanceProof = await crypto.generateBalanceProofSignature(feeAggInputMask, feeOutputMask, feeInputsStatement.statementJson, feeOutputsStatement.statementJson);
1184
+ const feeStatement = new StealthTransferStatement(feeInputsStatement, feeOutputsStatement, feeBalanceProof);
1185
+ await crypto.validateTransfer(feeStatement);
1186
+ const feeChangeCommitment = feeOutputsStatement.parsed().outputs[0].output.commitment;
1187
+ const maxEpoch = await resolveMaxEpoch(provider);
1188
+ const builder = TransactionBuilder.new(this.network, maxEpoch)
1189
+ .addInstruction({
1190
+ StealthTransfer: {
1191
+ resource_address_ref: { Address: resourceAddress },
1192
+ statement: { __ootleRawJson: redeemedStatement.toCompactJson() },
1193
+ revealed_input_bucket: null,
1194
+ },
1195
+ })
1196
+ .addInstruction({ PutLastInstructionOutputOnWorkspace: { key: 0 } })
1197
+ .withInstructions(followUpInstructions)
1198
+ .addFeeInstruction({
1199
+ StealthTransfer: {
1200
+ resource_address_ref: { Address: feeResourceAddress },
1201
+ statement: { __ootleRawJson: feeStatement.toCompactJson() },
1202
+ revealed_input_bucket: null,
1203
+ },
1204
+ })
1205
+ .addFeeInstruction({ PutLastInstructionOutputOnWorkspace: { key: 0 } })
1206
+ .addFeeInstruction({ PayFeeFromBucket: { bucket: { id: 0, offset: null } } })
1207
+ .addInput({ substate_id: resourceAddress, version: null })
1208
+ .addInput({ substate_id: redeemed.substateId, version: null })
1209
+ .addInput({ substate_id: feeResourceAddress, version: null })
1210
+ .addInput({ substate_id: feeInput.substateId, version: null });
1211
+ for (const component of relatedComponents) {
1212
+ builder.addInput({ substate_id: component, version: null });
1213
+ for (const vaultId of await getVaultIdsForAccount(provider, component)) {
1214
+ builder.addInput({ substate_id: vaultId, version: null });
1215
+ }
1216
+ }
1217
+ const unsignedTx = await resolveTransaction(provider, builder.buildUnsignedTransaction());
1218
+ // One addStealthSignature per stealth input, bound to a shared (arbitrary) seal key that
1219
+ // signTransaction generates -- see this method's own doc comment for why no ordinary
1220
+ // account-key signature is added.
1221
+ const oneTimeSigner = (publicNonceHex) => ({
1222
+ getAddress: async () => walletAddress,
1223
+ getPublicKey: async () => parseOotleAddress(walletAddress).owner_key,
1224
+ signTransaction: async (tx, sealPublicKey) => {
1225
+ const json = serializeUnsignedTx(tx);
1226
+ const sig = await this.signer.addStealthSignature(json, fromHex(publicNonceHex), sealPublicKey, { crypto });
1227
+ return [sig];
1228
+ },
1229
+ });
1230
+ // Each stealth input's own sender_public_nonce lives on its UTXO substate -- fetched again
1231
+ // here (decryptOwnedUtxo above didn't return it) rather than parsed out of the substate
1232
+ // response type, whose shape `decryptOwnedUtxo` already validated once.
1233
+ const redeemedSubstate = await provider.getSubstate(redeemed.substateId);
1234
+ const feeInputSubstate = await provider.getSubstate(feeInput.substateId);
1235
+ const redeemedNonce = redeemedSubstate.substate.Utxo
1236
+ .output.output.public_nonce;
1237
+ const feeNonce = feeInputSubstate.substate.Utxo.output
1238
+ .output.public_nonce;
1239
+ const signed = await signTransaction([oneTimeSigner(redeemedNonce), oneTimeSigner(feeNonce)], unsignedTx);
1240
+ const envelope = sealTransaction(signed);
1241
+ const transactionId = await submitTransaction(provider, envelope);
1242
+ const response = await withTimeout(pollTransactionResult(provider, transactionId), 60_000, "submitting the private-fee redemption transaction");
1243
+ await recordKnownVersions(response);
1244
+ return { transactionId, feeChangeCommitment };
1245
+ }
996
1246
  /**
997
1247
  * Funds an HTLC (hashed timelock contract): creates a stealth output for `amount` of
998
1248
  * `resourceAddress`, gated not by a normal one-time stealth key but by a two-leaf TIP-0006
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chironbuilder/ootle-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Shared TypeScript client for Tari Ootle (L2): account derivation, balances, transactions, HTLCs, and stealth/confidential transfers — the account core behind Sapient and the Tari L1 web wallet's Ootle support.",
5
5
  "type": "module",
6
6
  "license": "MIT",