@kassealhq/sdk 0.3.0 → 1.0.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +118 -2
  3. package/SECURITY.md +3 -2
  4. package/STABILITY.md +25 -12
  5. package/dist/artifacts/contracts/lock/v1/artifacts/build-report.txt +4 -0
  6. package/dist/artifacts/contracts/lock/v1/artifacts/factory.artifact.json +267 -0
  7. package/dist/artifacts/contracts/lock/v1/artifacts/factory.ctor.json +80 -0
  8. package/dist/artifacts/contracts/lock/v1/artifacts/lock.artifact.json +258 -0
  9. package/dist/artifacts/contracts/lock/v1/artifacts/lock.ctor.json +112 -0
  10. package/dist/artifacts/contracts/lock/v1/artifacts/manifest.json +70 -0
  11. package/dist/artifacts/manifest.json +18 -0
  12. package/dist/chunks/chunk-H7LB2HPQ.js +4 -0
  13. package/dist/chunks/chunk-WJFZETEQ.js +1 -0
  14. package/dist/chunks/token-lock-v1-763GG7M6.js +1 -0
  15. package/dist/index.d.ts +458 -12
  16. package/dist/index.js +1 -1
  17. package/dist/node.d.ts +1 -1
  18. package/dist/node.js +1 -1
  19. package/dist/web-lite-mainnet.d.ts +1 -1
  20. package/dist/web-lite-mainnet.js +1 -1
  21. package/dist/web-lite-testnet-10.d.ts +1 -1
  22. package/dist/web-lite-testnet-10.js +1 -1
  23. package/dist/web-mainnet.d.ts +1 -1
  24. package/dist/web-mainnet.js +1 -1
  25. package/dist/web-testnet-10.d.ts +1 -1
  26. package/dist/web-testnet-10.js +1 -1
  27. package/dist/web.d.ts +1 -1
  28. package/dist/web.js +1 -1
  29. package/docs/api.md +52 -0
  30. package/docs/contract-artifacts.md +32 -3
  31. package/docs/errors.md +8 -0
  32. package/docs/explorers.md +27 -1
  33. package/docs/partner-tag.md +134 -0
  34. package/docs/wallets.md +5 -0
  35. package/examples/README.md +1 -0
  36. package/examples/partner-tag.ts +58 -0
  37. package/package.json +2 -1
  38. package/dist/chunks/chunk-FYCRPHEE.js +0 -4
  39. package/dist/chunks/chunk-JZJ7MFR5.js +0 -1
@@ -0,0 +1,134 @@
1
+ # Wallets: adding your partner tag
2
+
3
+ A wallet partner's trades on Kasseal are recognised by a **partner tag**: 6 bytes in the transaction's payload that
4
+ name the partner and the channel the trade came through. Tagged trades are credited to the partner under its partner
5
+ agreement with Kasseal. This page covers the format, what a wallet has to do for each channel, and how to add and
6
+ check the tag with the SDK.
7
+
8
+ Only trades of Kasseal tokens (a curve buy or sell, or a swap on a Kasseal pool) are credited: the share is a part of
9
+ Kasseal's own fee. An imported coin (a token whose `venue` field is set, see [api.md](api.md)) pays Kasseal no fee, so
10
+ its trades earn no share, tagged or not.
11
+
12
+ ## The tag
13
+
14
+ The tag is the transaction's whole payload, exactly 6 bytes:
15
+
16
+ | Bytes | Field | Value |
17
+ |---|---|---|
18
+ | 0..1 | Magic | `4B 53` (`"KS"`) |
19
+ | 2 | Version | `01` |
20
+ | 3..4 | Partner id | u16, big-endian |
21
+ | 5 | Channel | u8 |
22
+
23
+ For example, KasWare (partner 1) on the in-wallet channel (3) is `4B 53 01 00 01 03`, or `4b5301000103` in hex.
24
+
25
+ A payload is a tag only when it is exactly these 6 bytes with a known partner and a known channel. Anything else,
26
+ including a valid tag followed by more bytes, is not a tag, and the trade is untagged.
27
+
28
+ The payload is part of the transaction id and of every input's signature hash, so the user's signature commits to the
29
+ tag. The contracts never read it: a tagged trade executes exactly as an untagged one, and costs only the network fee
30
+ of 6 more bytes, which the SDK includes in its fee.
31
+
32
+ Only curve buys, curve sells and pool swaps carry a tag. Liquidity, fee payouts (sweeps) and the other builders always
33
+ build an empty payload.
34
+
35
+ ## Partner ids and channels
36
+
37
+ | Partner id | Partner | SDK constant |
38
+ |---|---|---|
39
+ | 1 | KasWare | `PARTNER_IDS.kasware` |
40
+ | 2 | Kaspire | `PARTNER_IDS.kaspire` |
41
+ | 3 | Reserved for Kastle | `PARTNER_IDS.kastle` |
42
+ | 1000 | BraidSwap (an app, not a wallet: its own app builds every trade, so it uses channel 3 only) | `PARTNER_IDS.braidswap` |
43
+ | 1001 and up | Future integrators | |
44
+
45
+ | Channel | Name | SDK constant | Who adds the tag |
46
+ |---|---|---|---|
47
+ | 1 | Extension: a trade on the Kasseal website, signed with the partner's browser extension | `PARTNER_CHANNELS.extension` | The Kasseal website |
48
+ | 2 | WalletConnect: a trade on the Kasseal website, signed with the partner's mobile wallet over WalletConnect | `PARTNER_CHANNELS.walletconnect` | The Kasseal website |
49
+ | 3 | In-wallet: a swap inside the partner's own app | `PARTNER_CHANNELS.embedded` | The partner's app |
50
+
51
+ Partner ids are assigned by Kasseal; do not pick one yourself. An id is never reused or given a new meaning. A newly
52
+ assigned id is added to `PARTNER_IDS` in an SDK minor release; until the SDK version you use knows your id, the
53
+ builders and `encodePartnerTag` refuse it with a `RangeError` rather than write a tag nobody can read.
54
+
55
+ ## Connected trades (channels 1 and 2): sign the payload unchanged
56
+
57
+ When a user trades on the Kasseal website with your extension or over WalletConnect, the website builds the
58
+ transaction with your tag already in the payload. Your wallet does not need any Kasseal code. It only has to:
59
+
60
+ - sign the transaction it was given, with its payload unchanged;
61
+ - never strip, rewrite, re-encode or append to the payload, and never rebuild the transaction from its parts in a way
62
+ that loses the payload.
63
+
64
+ Changing the payload changes the transaction id. The website checks that the signed transaction has the id it built
65
+ (`finalize` and `signBuilt` refuse anything else), so a wallet that drops or alters the payload does not just lose the
66
+ tag: the trade fails and nothing is submitted.
67
+
68
+ ## In-wallet trades (channel 3): add the tag with the SDK
69
+
70
+ A swap screen inside your own app builds the trade itself, so your code adds the tag. Pass `partner` to the builder
71
+ from `createTxBuilder`. It takes a `PartnerTag`, `{ partner, channel }`, on all four trade builders:
72
+
73
+ ```ts
74
+ import type { BuiltTx, LaunchProofVerdict, PartnerTag, PublicTxBuilder } from '@kassealhq/sdk/web';
75
+
76
+ const PARTNER: PartnerTag = { partner: 1, channel: 3 }; // your id from Kasseal, channel 3 (in-wallet)
77
+
78
+ declare const builder: PublicTxBuilder; // createTxBuilder({ sources, networkId })
79
+ declare const tokenId: string, poolId: string, address: string, xOnly: Uint8Array, proofVerdict: LaunchProofVerdict;
80
+
81
+ // Curve buy and sell
82
+ const buy: BuiltTx = await builder.buildBuy({ covenantId: tokenId, tokenId, buyer: address, buyerXOnlyPubkey: xOnly, lots: 10n, proofVerdict, partner: PARTNER });
83
+ const sell: BuiltTx = await builder.buildSell({ covenantId: tokenId, tokenId, seller: address, sellerXOnlyPubkey: xOnly, lots: 10n, proofVerdict, partner: PARTNER });
84
+
85
+ // Pool swap, either side
86
+ const swap: BuiltTx = await builder.buildSwap({ poolId, expectedPoolId: poolId, tokenId, trader: address, traderXOnlyPubkey: xOnly, side: 'kas->tok', amountIn: 100_000_000n, partner: PARTNER });
87
+
88
+ // Pool sell of a script-held token cell
89
+ declare const payout: string, redeem: Uint8Array, signerXOnly: Uint8Array, scriptAddress: string;
90
+ const scriptSell: BuiltTx = await builder.buildScriptSell({ poolId, expectedPoolId: poolId, tokenId, payout, redeem, signerXOnly, scriptAddress, partner: PARTNER });
91
+ ```
92
+
93
+ The synchronous shapes take the same tag as `partnerTag`: `buildBuy`, `buildSell`, `buildSwapKasForTokens` and
94
+ `buildSwapTokensForKas` (`{ ...params, partnerTag: PARTNER }`).
95
+
96
+ - Pass the same tag on every build and rebuild of the same trade (a retry, a replacement, a build on a newer pending
97
+ state), so every attempt is credited alike.
98
+ - Leave `partner` out and the payload stays empty: the transaction is byte for byte what an untagged build gives.
99
+ - Use channel 3 only for trades your own app builds. Trades your users make on the Kasseal website are tagged by the
100
+ website (channels 1 and 2).
101
+
102
+ [examples/partner-tag.ts](../examples/partner-tag.ts) has these builders as functions, with the checks below.
103
+
104
+ ## Building the tag by hand
105
+
106
+ If your app builds Kasseal transactions without the SDK's builders, write the payload with `encodePartnerTag` and set
107
+ it as the transaction's whole payload:
108
+
109
+ ```ts
110
+ import { encodePartnerTag } from '@kassealhq/sdk';
111
+
112
+ const payload: Uint8Array = encodePartnerTag({ partner: 1, channel: 3 }); // 4b 53 01 00 01 03
113
+ ```
114
+
115
+ `encodePartnerTag` throws a `RangeError` on a partner id or channel it does not know. The format constants are
116
+ exported too: `PARTNER_TAG_MAGIC_0` (`0x4B`), `PARTNER_TAG_MAGIC_1` (`0x53`), `PARTNER_TAG_VERSION` (`1`) and
117
+ `PARTNER_TAG_BYTES` (`6`). Remember the network fee of the 6 payload bytes when you compute your fee.
118
+
119
+ ## Checking a transaction carries the tag
120
+
121
+ `decodePartnerTagHex` reads a payload in lowercase hex, the form `built.txJson` and the Kaspa node use, and returns
122
+ the tag or `null` (lowercase a payload from another source first). `decodePartnerTag` does the same for bytes.
123
+
124
+ ```ts
125
+ import { decodePartnerTagHex, type BuiltTx } from '@kassealhq/sdk';
126
+
127
+ declare const built: BuiltTx;
128
+ const payloadHex: string = (JSON.parse(built.txJson) as { payload?: string }).payload ?? '';
129
+ const tag = decodePartnerTagHex(payloadHex); // { partner: 1, channel: 3 }, or null when untagged
130
+ if (tag === null || tag.partner !== 1) throw new Error('not tagged as ours');
131
+ ```
132
+
133
+ Run this check on a built trade before you show the signing prompt, and in your tests. `isPartnerId` and
134
+ `isPartnerChannel` tell whether a number is a known id or channel.
package/docs/wallets.md CHANGED
@@ -149,6 +149,11 @@ After the wallet answers, `signBuilt`:
149
149
 
150
150
  Anything else is refused with `FinalizeError` and nothing is submitted.
151
151
 
152
+ **Trades made in your own app.** A wallet partner that builds Kasseal trades in its own app passes its partner id and
153
+ the `embedded` channel as the builder's `partner` option, on every build and every rebuild of a trade. The tag is the
154
+ transaction's 6-byte payload, covered by the txid, so the check above also refuses a signed transaction whose tag
155
+ was removed or changed. See [Wallets: adding your partner tag](partner-tag.md).
156
+
152
157
  **Before you show a signing prompt**, show the user what the SDK computed: the tokens or KAS they receive, the
153
158
  all-in cost (`maxAllIn`) or the net amount (`minNetOut`), the cell deposit and the network fee. The builder refuses
154
159
  to build when those bounds are not met (`NetBoundExceeded`).
@@ -12,6 +12,7 @@ Run them with Node 22.6 or later (`node --experimental-strip-types examples/<fil
12
12
  | [`pool-buy.ts`](pool-buy.ts) | The full flow: proof, build on the latest state, sign, submit, safe retry | Yes (`KEY`) |
13
13
  | [`swap-and-deposit.ts`](swap-and-deposit.ts) | A pool buy delivered to a key-locked script | Yes (`KEY`) |
14
14
  | [`pool-sell-wallet.ts`](pool-sell-wallet.ts) | A pool sell signed by a browser wallet (module for a web page) | Wallet |
15
+ | [`partner-tag.ts`](partner-tag.ts) | A wallet's own swap screen: every trade builder with the wallet's partner tag, and the tag checks | Wallet |
15
16
  | [`lib/api.ts`](lib/api.ts) | A minimal REST client: reads, submission and status (the builder's sources are the SDK's `createApiSources`) | |
16
17
  | [`lib/proof.ts`](lib/proof.ts) | Launch-proof check with the public Kaspa API graduation check | |
17
18
 
@@ -0,0 +1,58 @@
1
+ /**
2
+ * A wallet's own swap screen: every Kasseal trade it builds carries the wallet's partner tag (docs/partner-tag.md).
3
+ *
4
+ * This file is a module for a wallet. It assumes the wallet has loaded the SDK's web entry once (`initWeb`) and has a
5
+ * builder from `createTxBuilder`, as in pool-sell-wallet.ts. The tag below is KasWare's (partner 1) on the in-wallet
6
+ * channel (3); use the partner id Kasseal assigned to you.
7
+ */
8
+ import {
9
+ PARTNER_TAG_BYTES,
10
+ decodePartnerTagHex,
11
+ encodePartnerTag,
12
+ type BuiltTx,
13
+ type LaunchProofVerdict,
14
+ type PartnerTag,
15
+ type PublicTxBuilder,
16
+ } from '@kassealhq/sdk/web';
17
+
18
+ /** Your partner id and the in-wallet channel. Pass the same tag on every build and rebuild of a trade. */
19
+ export const PARTNER: PartnerTag = { partner: 1, channel: 3 };
20
+
21
+ /** A curve buy of `lots` lots, tagged. */
22
+ export function curveBuy(builder: PublicTxBuilder, tokenId: string, address: string, xOnly: Uint8Array, lots: bigint, maxAllIn: bigint, proofVerdict: LaunchProofVerdict): Promise<BuiltTx> {
23
+ return builder.buildBuy({ covenantId: tokenId, tokenId, buyer: address, buyerXOnlyPubkey: xOnly, lots, maxAllIn, proofVerdict, partner: PARTNER });
24
+ }
25
+
26
+ /** A curve sell of `lots` lots, tagged. */
27
+ export function curveSell(builder: PublicTxBuilder, tokenId: string, address: string, xOnly: Uint8Array, lots: bigint, minNetOut: bigint, proofVerdict: LaunchProofVerdict): Promise<BuiltTx> {
28
+ return builder.buildSell({ covenantId: tokenId, tokenId, seller: address, sellerXOnlyPubkey: xOnly, lots, minNetOut, proofVerdict, partner: PARTNER });
29
+ }
30
+
31
+ /** A pool swap either way, tagged: `amountIn` is the KAS leg (kas->tok) or the token amount (tok->kas). */
32
+ export function poolSwap(builder: PublicTxBuilder, poolId: string, tokenId: string, address: string, xOnly: Uint8Array, side: 'kas->tok' | 'tok->kas', amountIn: bigint): Promise<BuiltTx> {
33
+ return builder.buildSwap({ poolId, expectedPoolId: poolId, tokenId, trader: address, traderXOnlyPubkey: xOnly, side, amountIn, partner: PARTNER });
34
+ }
35
+
36
+ /** A pool sell of a token cell held by a key-locked script, tagged. */
37
+ export function scriptSell(builder: PublicTxBuilder, poolId: string, tokenId: string, payout: string, redeem: Uint8Array, signerXOnly: Uint8Array, scriptAddress: string): Promise<BuiltTx> {
38
+ return builder.buildScriptSell({ poolId, expectedPoolId: poolId, tokenId, payout, redeem, signerXOnly, scriptAddress, partner: PARTNER });
39
+ }
40
+
41
+ /** The 6 payload bytes by hand, for a wallet that builds its transactions without the SDK's builders. */
42
+ export function partnerPayload(): Uint8Array {
43
+ const payload = encodePartnerTag(PARTNER); // 4b 53 01 00 01 03
44
+ if (payload.length !== PARTNER_TAG_BYTES) throw new Error('unexpected tag length');
45
+ return payload;
46
+ }
47
+
48
+ /** Whether a transaction's payload (lowercase hex, as the node and `built.txJson` give it) carries your tag. */
49
+ export function carriesOurTag(payloadHex: string): boolean {
50
+ const tag = decodePartnerTagHex(payloadHex);
51
+ return tag !== null && tag.partner === PARTNER.partner && tag.channel === PARTNER.channel;
52
+ }
53
+
54
+ /** Check a built trade before you show the signing prompt. */
55
+ export function assertTagged(built: BuiltTx): void {
56
+ const payload = (JSON.parse(built.txJson) as { payload?: string }).payload ?? '';
57
+ if (!carriesOurTag(payload)) throw new Error(`trade ${built.txid} does not carry the partner tag`);
58
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kassealhq/sdk",
3
- "version": "0.3.0",
3
+ "version": "1.0.0",
4
4
  "description": "Quotes, transaction builders, launch-proof verification and wallet adapters for Kasseal tokens on Kaspa.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -71,6 +71,7 @@
71
71
  "docs/errors.md",
72
72
  "docs/explorers.md",
73
73
  "docs/launch-proof.md",
74
+ "docs/partner-tag.md",
74
75
  "docs/trading-bots.md",
75
76
  "docs/wallets.md",
76
77
  "examples/"
@@ -1,4 +0,0 @@
1
- import{Ch as Z,Fe as $,He as J,Je as G,Ke as X,Lh as v,Oh as N,Qh as ee,Rd as F,Rf as R,Ud as L,Uh as ne,Vd as H,Vf as j,Xm as te,Ye as Y,Zf as k,_d as I,_m as se,bn as U,cg as Q,dg as V,hg as S,in as ae,jn as re,kn as g,l as K,lg as W,ln as E,m as T,mg as z,mn as x,nn as ie,p as w,ue as _,yd as O}from"./chunk-JZJ7MFR5.js";import{a as c}from"./chunk-XLPNXOE2.js";var ce=Object.freeze({"genesis.assembled.fullySigned":"true","genesis.assembled.signed":"1","genesis.assembled.txid":"027b480b96236872627bfc9d63c236b83b71d05c31c4a94e742c77ac0039fdb7","genesis.fee":"28752100","genesis.genesis.covenantId":"d9312320443dd64203d4cae0bf2c11f487a131172014b90562815d63dc1d6865","genesis.sighash.0":"728f7651f7bbb15a6fac1edb212125882b74d4312f834221d070bde6bdd924f3","genesis.sighash.1":"ec6c50baca35a61c4181393d7cc8ef011de15afb21a0305b55ceac10052c118e","genesis.signed.refinalized":"true","genesis.signed.txJson":'{"id":"027b480b96236872627bfc9d63c236b83b71d05c31c4a94e742c77ac0039fdb7","version":1,"inputs":[{"transactionId":"b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2","index":0,"sequence":"42","sigOpCount":0,"computeBudget":7,"signatureScript":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627","utxo":{"address":null,"amount":"300000000","scriptPublicKey":"0000aa20cc6a27ad71bdbdbced89b58583949e40228e1fb7352e9af8e7410e352339ce0e87","blockDaaScore":"222","isCoinbase":false,"covenantId":"c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3"}},{"transactionId":"d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4","index":3,"sequence":"0","sigOpCount":0,"computeBudget":11,"signatureScript":"410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001","utxo":{"address":null,"amount":"1000000000","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","blockDaaScore":"333","isCoinbase":false,"covenantId":null}}],"outputs":[{"value":"300000000","scriptPublicKey":"0000aa20cc6a27ad71bdbdbced89b58583949e40228e1fb7352e9af8e7410e352339ce0e87","covenant":{"authorizingInput":0,"covenantId":"c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3"}},{"value":"50000000","scriptPublicKey":"0000aa20ce572c79db7139e1d5abe9b363274c23b0f93b0896c603d8c337c83a62e6fd1287","covenant":{"authorizingInput":1,"covenantId":"d9312320443dd64203d4cae0bf2c11f487a131172014b90562815d63dc1d6865"}},{"value":"20000000","scriptPublicKey":"0000aa20ce572c79db7139e1d5abe9b363274c23b0f93b0896c603d8c337c83a62e6fd1287","covenant":{"authorizingInput":1,"covenantId":"d9312320443dd64203d4cae0bf2c11f487a131172014b90562815d63dc1d6865"}},{"value":"901247900","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","covenant":null}],"subnetworkId":"0000000000000000000000000000000000000000","lockTime":"1000","gas":"0","storageMass":"0","payload":""}',"genesis.signed.txid":"027b480b96236872627bfc9d63c236b83b71d05c31c4a94e742c77ac0039fdb7","genesis.signed.verifies":"true","genesis.txJson":'{"id":"027b480b96236872627bfc9d63c236b83b71d05c31c4a94e742c77ac0039fdb7","version":1,"inputs":[{"transactionId":"b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2","index":0,"sequence":"42","sigOpCount":0,"computeBudget":7,"signatureScript":"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627","utxo":{"address":null,"amount":"300000000","scriptPublicKey":"0000aa20cc6a27ad71bdbdbced89b58583949e40228e1fb7352e9af8e7410e352339ce0e87","blockDaaScore":"222","isCoinbase":false,"covenantId":"c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3"}},{"transactionId":"d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4d4","index":3,"sequence":"0","sigOpCount":0,"computeBudget":11,"signatureScript":"410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","utxo":{"address":null,"amount":"1000000000","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","blockDaaScore":"333","isCoinbase":false,"covenantId":null}}],"outputs":[{"value":"300000000","scriptPublicKey":"0000aa20cc6a27ad71bdbdbced89b58583949e40228e1fb7352e9af8e7410e352339ce0e87","covenant":{"authorizingInput":0,"covenantId":"c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3"}},{"value":"50000000","scriptPublicKey":"0000aa20ce572c79db7139e1d5abe9b363274c23b0f93b0896c603d8c337c83a62e6fd1287","covenant":{"authorizingInput":1,"covenantId":"d9312320443dd64203d4cae0bf2c11f487a131172014b90562815d63dc1d6865"}},{"value":"20000000","scriptPublicKey":"0000aa20ce572c79db7139e1d5abe9b363274c23b0f93b0896c603d8c337c83a62e6fd1287","covenant":{"authorizingInput":1,"covenantId":"d9312320443dd64203d4cae0bf2c11f487a131172014b90562815d63dc1d6865"}},{"value":"901247900","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","covenant":null}],"subnetworkId":"0000000000000000000000000000000000000000","lockTime":"1000","gas":"0","storageMass":"0","payload":""}',"genesis.txid":"027b480b96236872627bfc9d63c236b83b71d05c31c4a94e742c77ac0039fdb7","p2pk.assembled.fullySigned":"true","p2pk.assembled.signed":"0","p2pk.assembled.txid":"33fd0d9c3f1f910010e0e5803deee9599c812aac3c5ec3a0c7b4784dba88512d","p2pk.fee":"876100","p2pk.sighash.0":"a9b830e90d2339ec46592b948fc2fc75903a66e9d6e9a0aca5ec670ca7e8593a","p2pk.signed.refinalized":"true","p2pk.signed.txJson":'{"id":"33fd0d9c3f1f910010e0e5803deee9599c812aac3c5ec3a0c7b4784dba88512d","version":1,"inputs":[{"transactionId":"a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1","index":1,"sequence":"0","sigOpCount":0,"computeBudget":11,"signatureScript":"410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001","utxo":{"address":null,"amount":"500000000","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","blockDaaScore":"123456","isCoinbase":false,"covenantId":null}}],"outputs":[{"value":"123456789","scriptPublicKey":"0000aa20ea40d7af7830163e4abaee51621985ba50d1a918c206c3330d15048d55ce442087","covenant":null},{"value":"375667111","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","covenant":null}],"subnetworkId":"0000000000000000000000000000000000000000","lockTime":"0","gas":"0","storageMass":"0","payload":"6b61737365616c206b6e6f776e2d616e737765722074657374"}',"p2pk.signed.txid":"33fd0d9c3f1f910010e0e5803deee9599c812aac3c5ec3a0c7b4784dba88512d","p2pk.signed.verifies":"true","p2pk.txJson":'{"id":"33fd0d9c3f1f910010e0e5803deee9599c812aac3c5ec3a0c7b4784dba88512d","version":1,"inputs":[{"transactionId":"a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1","index":1,"sequence":"0","sigOpCount":0,"computeBudget":11,"signatureScript":"410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","utxo":{"address":null,"amount":"500000000","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","blockDaaScore":"123456","isCoinbase":false,"covenantId":null}}],"outputs":[{"value":"123456789","scriptPublicKey":"0000aa20ea40d7af7830163e4abaee51621985ba50d1a918c206c3330d15048d55ce442087","covenant":null},{"value":"375667111","scriptPublicKey":"000020cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","covenant":null}],"subnetworkId":"0000000000000000000000000000000000000000","lockTime":"0","gas":"0","storageMass":"0","payload":"6b61737365616c206b6e6f776e2d616e737765722074657374"}',"p2pk.txid":"33fd0d9c3f1f910010e0e5803deee9599c812aac3c5ec3a0c7b4784dba88512d","scripts.key.address.mainnet":"kaspa:qr93f565yswpmw47rtc86j9ycsz4dq47estnrfme3jfxsuy40l3ysvjv666lu","scripts.key.address.testnet-10":"kaspatest:qr93f565yswpmw47rtc86j9ycsz4dq47estnrfme3jfxsuy40l3ysd52p4ywc","scripts.key.script.mainnet":"20cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","scripts.key.script.testnet-10":"20cb14d354241c1dbabe1af07d48a4c4055682becc1731a7798c926870957fe248ac","scripts.p2sh.address.mainnet":"kaspa:pr4yp4a00qcpv0j2hth9zcseska9p5dfrrpqdsenp52sfr24eezzqre9sdvf8","scripts.p2sh.address.testnet-10":"kaspatest:pr4yp4a00qcpv0j2hth9zcseska9p5dfrrpqdsenp52sfr24eezzqzlrtzjcr","scripts.p2sh.script.mainnet":"aa20ea40d7af7830163e4abaee51621985ba50d1a918c206c3330d15048d55ce442087","scripts.p2sh.script.testnet-10":"aa20ea40d7af7830163e4abaee51621985ba50d1a918c206c3330d15048d55ce442087","version":"2.1.0"});var Ae="@kassealhq/sdk known-answer test key (public, holds nothing)";var D=Object.freeze({mainnet:"kaspa:qr93f565yswpmw47rtc86j9ycsz4dq47estnrfme3jfxsuy40l3ysvjv666lu","testnet-10":"kaspatest:qr93f565yswpmw47rtc86j9ycsz4dq47estnrfme3jfxsuy40l3ysd52p4ywc"});var Pe=["version","Transaction","TransactionOutput","ScriptPublicKey","GenesisCovenantGroup","CovenantBinding","Hash","PrivateKey","payToAddressScript","addressFromScriptPublicKey","createInputSignature"];var Oe=["finalize","populateGenesisCovenants","serializeToSafeJSON"];var oe={cells:{consumed:[],produced:[]},funding:{reserved:[]}};var P=c(e=>new TextEncoder().encode(e),"enc");function Ee(e){if(e===null||typeof e!=="object"&&typeof e!=="function")return["the module is not an object"];const n=e;const t=[];for(const r of Pe)if(typeof n[r]!=="function")t.push(`missing function ${r}`);const a=n["Transaction"];if(typeof a==="function"){for(const r of Oe)if(typeof a.prototype?.[r]!=="function")t.push(`missing method Transaction.prototype.${r}`);if(typeof a.deserializeFromSafeJSON!=="function")t.push("missing static Transaction.deserializeFromSafeJSON")}const s=n["SighashType"];if(s===null||typeof s!=="object"||typeof s.All!=="number")t.push("missing SighashType.All");return t}c(Ee,"missingSdkSurface");function de(e,n){const t=JSON.parse(e).inputs[n]?.signatureScript??"";if(t.length!==132||!t.startsWith("41")||!t.endsWith("01"))throw new Error(`input ${n}: not a P2PK signature script`);return t.slice(2,130)}c(de,"p2pkSignatureHex");function Ce(e,n){const t=e.indexOf(n);if(t<0||e.indexOf(n,t+1)>=0)throw new Error("signature not found exactly once in the transaction");return e.slice(0,t)+"0".repeat(n.length)+e.slice(t+n.length)}c(Ce,"masked");function Ke(e,n,t){return Z(t.subarray(1,33),T(v(e,n)),T(de(e,n)))}c(Ke,"verifies");function Te(e){const n=w(P("kasseal kat program A"));for(const t of["mainnet","testnet-10"]){const a=S(D[t]);e[`key.script.${t}`]=K(a);e[`key.address.${t}`]=W(a,t);const s=W(n,t);e[`p2sh.address.${t}`]=s;e[`p2sh.script.${t}`]=K(S(s))}}c(Te,"scriptsCase");function Ie(e,n){const t=D["testnet-10"];const a=S(t);const s={name:"kat-p2pk",inputs:[z({outpoint:{txid:"a1".repeat(32),index:1},amount:500000000n,spk:a,daaScore:123456n,address:t},"funding",_.p2pk,R)],outputs:[{label:"pay",value:123456789n,spk:w(P("kasseal kat program A")),binding:void 0,cell:void 0}],residual:{label:"change",spk:a,binding:void 0,cell:void 0,minimum:0n,dropBelow:j},genesisGroups:[],payload:P("kasseal known-answer test"),feeMargin:0n};const r=k(s);e["txid"]=r.txid;e["fee"]=String(r.fee);const i=N(r,{feerate:I,produces:[],optimistic:oe});e["txJson"]=i.txJson;e["sighash.0"]=v(i.txJson,0);ue(e,i,n,[0],a);fe(e,k(s),n)}c(Ie,"p2pkCase");function _e(e,n){const t=D.mainnet;const a=S(t);const s=w(P("kasseal kat covenant cell"));const r=P("kasseal kat genesis");const i=w(r);const o="c3".repeat(32);const u={predicted:{kind:"token",state:Y(1000n,o)},program:r,covenantId:void 0};const f={name:"kat-genesis",inputs:[{label:"cell",outpoint:{txid:"b2".repeat(32),index:0},amount:300000000n,spk:s,daaScore:222n,covenantId:o,budget:7,sigscript:Uint8Array.from({length:40},(p,h)=>h),signature:void 0,sequence:42n},z({outpoint:{txid:"d4".repeat(32),index:3},amount:1000000000n,spk:a,daaScore:333n,address:t},"funding",_.p2pk,R)],outputs:[{label:"cell",value:300000000n,spk:s,binding:{authorizingInput:0,covenantId:o},cell:void 0},{label:"genesis-a",value:50000000n,spk:i,binding:void 0,cell:u},{label:"genesis-b",value:20000000n,spk:i,binding:void 0,cell:u}],residual:{label:"change",spk:a,binding:void 0,cell:void 0,minimum:0n,dropBelow:j},genesisGroups:[{authorizingInput:1,outputs:[1,2]}],payload:new Uint8Array(0),feeMargin:0n,lockTime:1000n};const d=k(f);e["txid"]=d.txid;e["fee"]=String(d.fee);e["genesis.covenantId"]=d.genesis.map(p=>p.covenantId).join(",");const l=N(d,{feerate:I,produces:[],optimistic:oe});e["txJson"]=l.txJson;e["sighash.0"]=v(l.txJson,0);e["sighash.1"]=v(l.txJson,1);ue(e,l,n,[1],a);fe(e,k(f),n)}c(_e,"genesisCase");function ue(e,n,t,a,s){const r=ne(n,t);e["signed.txid"]=r.txid;e["signed.verifies"]=String(a.every(o=>Ke(r.txJson,o,s)));let i=r.txJson;for(const o of a)i=Ce(i,de(r.txJson,o));e["signed.txJson"]=i;e["signed.refinalized"]=String(ee(n,r.txJson).txJson===r.txJson)}c(ue,"signedAnswers");function fe(e,n,t){e["assembled.signed"]=Q(n,()=>t).join(",");e["assembled.fullySigned"]=String(V(n));e["assembled.txid"]=n.tx.id}c(fe,"assembledSigning");function $e(e){return X(e,()=>{const n={version:String(e.version())};let t;const a=c((s,r)=>{const i={};try{r(i)}catch(o){i["error"]=o instanceof Error?o.message:String(o)}for(const[o,u]of Object.entries(i))n[`${s}.${o}`]=u},"run");a("key",()=>{t=new e.PrivateKey(O(Ae))});a("scripts",Te);a("p2pk",s=>Ie(s,t));a("genesis",s=>_e(s,t));return n})}c($e,"knownAnswers");var A=c((e,n=80)=>e===void 0?"(none)":e.length>n?`${e.slice(0,n)}... (${e.length} chars)`:e,"clip");function Je(e,n=ce){const t=[];const a=new Set;for(const[s,r]of Object.entries(e)){if(!s.endsWith(".error")||n[s]!==void 0)continue;const i=s.slice(0,-".error".length);a.add(i);t.push(`${i}: threw ${A(r,240)}`)}for(const s of[...new Set([...Object.keys(n),...Object.keys(e)])].sort()){const r=e[s];const i=n[s];if(r===i)continue;const o=s.slice(0,s.indexOf(".")<0?s.length:s.indexOf("."));if(a.has(o)&&(r===void 0||s===`${o}.error`))continue;if(i===void 0)t.push(`${s}: unexpected answer ${A(r)}`);else if(r===void 0)t.push(`${s}: no answer, expected ${A(i)}`);else{let u=0;while(u<r.length&&r[u]===i[u])u++;t.push(`${s}: got ${A(r)}, expected ${A(i)} (first difference at character ${u})`)}}return t}c(Je,"compareKnownAnswers");function le(e){const n=e;if(n!==null&&typeof n==="object"&&typeof n["version"]==="function"){let r;try{r=n["version"]()}catch(i){throw new x("version",[`version() threw: ${i instanceof Error?i.message:String(i)} (is the WASM initialised?)`])}if(r!==$)throw new x("version",[`reports version ${JSON.stringify(r)}, expected ${$}`])}const t=Ee(e);if(t.length>0)throw new x("surface",t);const a=e;const s=Je($e(a));if(s.length>0)throw new x("known-answer",s);return a}c(le,"verifyKaspaSdk");var b=c(e=>typeof e==="object"&&e!==null&&!Array.isArray(e),"isObject");function be(e){return b(e)&&e.curvePatch===1&&b(e.files)}c(be,"isCurvePatchChunk");function ge(e){return b(e)&&e.curveTemplate===1&&b(e.docs)}c(ge,"isCurveTemplateChunk");var me=c(e=>JSON.stringify(e),"pathKey");function Re(e,n,t,a){if(!Number.isInteger(n)||n<1)throw new Error("unsupported indent");let s="";const r=c(o=>" ".repeat(n*o),"pad");const i=c((o,u,f)=>{if(Array.isArray(o)){const d=s.length;const l=me(f);const p=t.get(l);if(o.length===0){s+="[]"}else if(p===0){s+="[";o.forEach((h,m)=>{if(m>0)s+=", ";i(h,u+1,[...f,m])});s+="]"}else{s+="[\n";o.forEach((h,m)=>{if(m>0)s+=p===void 0||m%p===0?`,
2
- ${r(u+1)}`:", ";else s+=r(u+1);i(h,u+1,[...f,m])});s+=`
3
- ${r(u)}]`}a?.set(l,[d,s.length])}else if(typeof o==="object"&&o!==null){const d=Object.keys(o);if(d.length===0){s+="{}";return}s+="{\n";d.forEach((l,p)=>{if(p>0)s+=",\n";s+=`${r(u+1)}${JSON.stringify(l)}: `;i(o[l],u+1,[...f,l])});s+=`
4
- ${r(u)}}`}else{const d=JSON.stringify(o);if(d===void 0)throw new Error("not a JSON value");s+=d}},"rec");i(e,0,[]);return s}c(Re,"renderJson");var B=/^(?:[0-9a-f]{2})*$/;function je(e){if(!B.test(e))throw new Error("malformed hex");const n=new Array(e.length/2);for(let t=0;t<n.length;t++)n[t]=parseInt(e.slice(2*t,2*t+2),16);return n}c(je,"bytesOfHex");function q(e){if(Array.isArray(e))return e.map(q);if(b(e)){const n=Object.keys(e);if(n.length===1&&n[0]==="$hex"){const a=e.$hex;if(typeof a!=="string"||a.length===0)throw new Error("malformed $hex value");return je(a)}const t={};for(const a of n)t[a]=q(e[a]);return t}return e}c(q,"expandCompact");function We(e,n){if(!B.test(e)||!Array.isArray(n)||n.length%3!==0)throw new Error("malformed byte edit");const t=e.length/2;let a="";let s=0;for(let r=0;r<n.length;r+=3){const i=n[r];const o=n[r+1];const u=n[r+2];if(!Number.isSafeInteger(i)||!Number.isSafeInteger(o)||typeof u!=="string"||!B.test(u))throw new Error("malformed byte edit");const f=i;const d=o;if(f<0||d<0||s+f+d>t)throw new Error("byte edit out of range");a+=e.slice(2*s,2*(s+f))+u;s+=f+d}return a+e.slice(2*s)}c(We,"applyHunks");function ye(e){return JSON.parse(JSON.stringify(e))}c(ye,"clone");function ze(e,n){if(!b(n)||!Array.isArray(n.p))throw new Error("malformed patch op");const t=n.p;const a=c(u=>{if("v"in n)return ye(n.v);if(!b(u)||typeof u.$hex!=="string"||Object.keys(u).length!==1)throw new Error("byte edit on a value that is not bytes");const f=We(u.$hex,n.x);if(f.length===0)throw new Error("byte edit leaves no bytes");return{$hex:f}},"replace");if(t.length===0)return a(e);let s=e;for(let u=0;u<t.length-1;u++)s=pe(s,t[u]);const r=t[t.length-1];const i=pe(s,r);const o=a(i);if(Array.isArray(s))s[r]=o;else s[r]=o;return e}c(ze,"applyOp");function pe(e,n){if(Array.isArray(e)&&typeof n==="number"&&Number.isInteger(n)&&n>=0&&n<e.length)return e[n];if(b(e)&&typeof n==="string"&&Object.hasOwn(e,n))return e[n];throw new Error("patch path not in the template")}c(pe,"child");function Ne(e,n){const t=b(n)&&typeof n.t==="string"&&Object.hasOwn(e.docs,n.t)?e.docs[n.t]:void 0;if(t===void 0||!Array.isArray(n.ops))throw new Error("malformed file patch");if(!Number.isInteger(t.indent)||t.indent<1||t.indent>10||typeof t.eol!=="string"||!Array.isArray(t.wrap))throw new Error("malformed template document");const a=new Map;for(const r of t.wrap){if(!Array.isArray(r)||!Array.isArray(r[0])||!Number.isInteger(r[1])||r[1]<0)throw new Error("malformed template layout");a.set(me(r[0]),r[1])}let s=ye(t.doc);for(const r of n.ops)s=ze(s,r);return Re(q(s),t.indent,a)+t.eol}c(Ne,"decodeFile");function he(e,n){const t={};for(const[a,s]of Object.entries(n.files))t[a]=Ne(e,s);return t}c(he,"decodeCurvePatchChunk");var we=re["web/kaspa_bg.wasm"];async function M(e){const n=globalThis.crypto?.subtle;if(n===void 0)return O(e);const t=new Uint8Array(await n.digest("SHA-256",e));let a="";for(const s of t)a+=s.toString(16).padStart(2,"0");return a}c(M,"sha256Of");async function xe(e,n="web/kaspa_bg.wasm"){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);const t=typeof e==="string"||e instanceof URL?await fetch(e):e;if(!t.ok)throw new E(n,`HTTP ${t.status}`);return new Uint8Array(await t.arrayBuffer())}c(xe,"wasmBytes");var ke="kaspa_bg.wasm (caller-supplied)";function Ue(e,n){const t=n.kaspa;if(t===void 0){if(e.bundled===void 0)throw new TypeError("initWeb: this entry bundles no Kaspa SDK: pass your own as kaspa: { module, wasm }");return}if(n.wasm!==void 0)throw new TypeError("initWeb: pass the WASM of a caller-supplied SDK as kaspa.wasm, not wasm");if(t===null||typeof t!=="object"||t.module===null||typeof t.module!=="object")throw new TypeError("initWeb: kaspa.module must be the imported bindings namespace");if(t.wasm!==void 0&&typeof t.module.default!=="function")throw new TypeError("initWeb: kaspa.module has no default init function to instantiate kaspa.wasm with");if(t.sha256!==void 0){if(t.wasm===void 0)throw new TypeError("initWeb: kaspa.sha256 needs kaspa.wasm");if(typeof t.sha256!=="string"||!/^[0-9a-fA-F]{64}$/.test(t.sha256))throw new TypeError("initWeb: kaspa.sha256 must be 64 hex characters")}}c(Ue,"checkKaspaOption");async function De(e){if(e.wasm!==void 0){const n=await xe(e.wasm,ke);if(e.sha256!==void 0){const t=e.sha256.toLowerCase();const a=await M(n);if(a!==t)throw new E(ke,`sha256 ${a} does not match the given ${t}`)}await e.module.default({module_or_path:n})}return le(e.module)}c(De,"callerSdk");async function Se(e,n,t){const a=await e.importChunk(n,t);return a.default}c(Se,"importChunk");async function ve(e,n,t){const a=await Se(e,n,t);let s;if(be(a)){const i=await Se(e,n,"curve-template");if(!ge(i))throw new g(`${n}--curve-template`,"is not a curve template");try{s=he(i,a)}catch(o){throw new g(`${n}--${t}`,`could not be decoded (${o instanceof Error?o.message:String(o)})`)}}else{s=a}const r=new TextEncoder;for(const[i,o]of Object.entries(s)){if(typeof o!=="string")throw new g(i,"is not text");ie(i,await M(r.encode(o)))}return s}c(ve,"loadChunk");function Be(e){const n=ae.builds[e];if(n===void 0)throw new g(e,"is not a bundled build");return Object.keys(n.presets).sort()}c(Be,"presetsOfBuild");var y;var C;function qe(e,n,t){U(n);Ue(e,t);if(y!==void 0){if(C!==n)return Promise.reject(new Error(`initWeb already ran for ${C}`));return y}C=n;y=(async()=>{if(G())throw new Error("a Kaspa SDK is already installed in this context");if(t.kaspa!==void 0){J(await De(t.kaspa))}else{const d=e.bundled;const l=await xe(t.wasm??d.wasmUrl());const p=await M(l);if(p!==we)throw new E("web/kaspa_bg.wasm",`sha256 ${p} does not match the pinned ${we}`);await d.initWasm({module_or_path:l});J(d.kaspa)}const a=te[n];const s=new Map(a.map(d=>[d,Be(d)]));const r=[...new Set(a.flatMap(d=>s.get(d)))].sort();const i=c(async d=>{const l={};for(const p of a)if(s.get(p).includes(d))Object.assign(l,await ve(e,p,d));return l},"loadPreset");const o={};for(const d of r)o[d]=()=>i(d);F(o);const u={};for(const d of a)Object.assign(u,await ve(e,d,"base"));const f=t.preload==="all"?r:t.preload??[];for(const d of f){if(!r.includes(d))throw new g(d,`is not a preset of ${a.join(" or ")}`);Object.assign(u,await i(d))}H(L(u))})();y.catch(()=>{y=void 0;C=void 0});return y}c(qe,"initWebWith");function mn(e,n,t={}){const a=t.network;if(a!==void 0&&a!==n){U(a);const s=new se(a);s.message=`network ${JSON.stringify(a)} is not served by the ${n} web entry: import '@kassealhq/sdk/web/${a}' (or '@kassealhq/sdk/web')`;throw s}return qe(e,n,t)}c(mn,"initWebFor");function yn(e,n){if(!n.includes(e))throw new g(e,`is not bundled with the ${n.join(" + ")} web entry`)}c(yn,"assertEntryBuild");export{qe as a,mn as b,yn as c};