@secondlayer/stacks 2.11.0 → 2.13.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 (75) hide show
  1. package/README.md +47 -0
  2. package/dist/shared/{stacks-v150hffx.js → stacks-01pbr7gf.js} +13 -12
  3. package/dist/shared/stacks-01pbr7gf.js.map +11 -0
  4. package/dist/shared/stacks-0cdm20eh.js +225 -0
  5. package/dist/shared/stacks-0cdm20eh.js.map +11 -0
  6. package/dist/shared/{stacks-hxm7r5ay.cjs → stacks-44y18a8e.cjs} +3 -10
  7. package/dist/shared/stacks-44y18a8e.cjs.map +10 -0
  8. package/dist/shared/{stacks-7nvbv61d.js → stacks-59xy6t1p.js} +27 -25
  9. package/dist/shared/{stacks-7nvbv61d.js.map → stacks-59xy6t1p.js.map} +6 -6
  10. package/dist/shared/{stacks-63xbc6cj.js → stacks-6n2m9hyk.js} +3 -3
  11. package/dist/shared/stacks-bnbdqznq.cjs +211 -0
  12. package/dist/shared/stacks-bnbdqznq.cjs.map +11 -0
  13. package/dist/shared/stacks-esn3wcw5.cjs +416 -0
  14. package/dist/shared/stacks-esn3wcw5.cjs.map +18 -0
  15. package/dist/shared/{stacks-3kmj5yre.js → stacks-g67f4w1d.js} +5 -12
  16. package/dist/shared/stacks-g67f4w1d.js.map +10 -0
  17. package/dist/shared/stacks-kjg7fw4y.js +434 -0
  18. package/dist/shared/stacks-kjg7fw4y.js.map +18 -0
  19. package/dist/shared/{stacks-maamjqma.cjs → stacks-tbv5p6pn.cjs} +7 -9
  20. package/dist/shared/stacks-tbv5p6pn.cjs.map +11 -0
  21. package/dist/shared/{stacks-k5an9zcw.cjs → stacks-y5epf0sb.cjs} +19 -22
  22. package/dist/shared/{stacks-k5an9zcw.cjs.map → stacks-y5epf0sb.cjs.map} +6 -6
  23. package/dist/src/accounts/index.cjs +28 -1
  24. package/dist/src/accounts/index.cjs.map +4 -3
  25. package/dist/src/accounts/index.d.cts +23 -1
  26. package/dist/src/accounts/index.d.ts +23 -1
  27. package/dist/src/accounts/index.js +33 -1
  28. package/dist/src/accounts/index.js.map +4 -3
  29. package/dist/src/actions/index.cjs +8 -1
  30. package/dist/src/actions/index.cjs.map +1 -1
  31. package/dist/src/actions/index.d.cts +140 -6
  32. package/dist/src/actions/index.d.ts +140 -6
  33. package/dist/src/actions/index.js +22 -8
  34. package/dist/src/actions/index.js.map +1 -1
  35. package/dist/src/bitcoin/index.cjs +4 -175
  36. package/dist/src/bitcoin/index.cjs.map +4 -6
  37. package/dist/src/bitcoin/index.d.cts +18 -2
  38. package/dist/src/bitcoin/index.d.ts +18 -2
  39. package/dist/src/bitcoin/index.js +18 -181
  40. package/dist/src/bitcoin/index.js.map +4 -6
  41. package/dist/src/bns/index.js +3 -3
  42. package/dist/src/index.cjs +10 -1
  43. package/dist/src/index.cjs.map +3 -3
  44. package/dist/src/index.d.cts +167 -9
  45. package/dist/src/index.d.ts +167 -9
  46. package/dist/src/index.js +23 -7
  47. package/dist/src/index.js.map +3 -3
  48. package/dist/src/pox/index.js +3 -3
  49. package/dist/src/sbtc/index.cjs +49 -7
  50. package/dist/src/sbtc/index.cjs.map +6 -6
  51. package/dist/src/sbtc/index.d.cts +8 -2
  52. package/dist/src/sbtc/index.d.ts +8 -2
  53. package/dist/src/sbtc/index.js +56 -10
  54. package/dist/src/sbtc/index.js.map +6 -6
  55. package/dist/src/stackingdao/index.js +3 -3
  56. package/dist/src/tools/index.cjs +194 -13
  57. package/dist/src/tools/index.cjs.map +12 -9
  58. package/dist/src/tools/index.js +194 -13
  59. package/dist/src/tools/index.js.map +12 -9
  60. package/dist/src/x402/index.cjs +5 -2
  61. package/dist/src/x402/index.cjs.map +3 -3
  62. package/dist/src/x402/index.d.cts +36 -0
  63. package/dist/src/x402/index.d.ts +36 -0
  64. package/dist/src/x402/index.js +7 -4
  65. package/dist/src/x402/index.js.map +3 -3
  66. package/package.json +2 -4
  67. package/dist/shared/stacks-3kmj5yre.js.map +0 -10
  68. package/dist/shared/stacks-502j0efj.js +0 -210
  69. package/dist/shared/stacks-502j0efj.js.map +0 -15
  70. package/dist/shared/stacks-hxm7r5ay.cjs.map +0 -10
  71. package/dist/shared/stacks-maamjqma.cjs.map +0 -11
  72. package/dist/shared/stacks-v150hffx.js.map +0 -11
  73. package/dist/shared/stacks-xmsms921.cjs +0 -196
  74. package/dist/shared/stacks-xmsms921.cjs.map +0 -15
  75. /package/dist/shared/{stacks-63xbc6cj.js.map → stacks-6n2m9hyk.js.map} +0 -0
package/README.md CHANGED
@@ -58,6 +58,53 @@ multi-broadcast gap, which is why it lives here rather than being deferred to
58
58
  | `@secondlayer/stacks/pox` | PoX stacking — solo and delegated |
59
59
  | `@secondlayer/stacks/stackingdao` | StackingDAO liquid staking (STX/stSTX) |
60
60
 
61
+ ## Fee tiers
62
+
63
+ Every send action takes `fee` as an exact amount **or a named tier** — `'min' | 'low' | 'mid' | 'high'`. Tiers map to the node's three estimations; `'min'` is the minimum relay fee (1 uSTX per serialized byte), computed offline with no round-trip. Omitting `fee` estimates mid, and if the node can't produce an estimate (`NoEstimateAvailable`), the SDK falls back to `'min'` instead of failing.
64
+
65
+ ```ts
66
+ await client.transferStx({ to, amount: 1000n, fee: "low" });
67
+ await client.callContract({ contract, functionName: "mint", fee: "min" });
68
+ ```
69
+
70
+ ## Wait for confirmation
71
+
72
+ `waitForTransactionReceipt` polls until a transaction is mined (optionally N confirmations deep) and returns a normalized receipt with the decoded Clarity result. It rejects with typed errors when the tx aborts (`TransactionAbortedError`, receipt attached), drops from the mempool (`TransactionDroppedError`), or times out — and it re-reads block placement every cycle, so reorgs don't strand the wait.
73
+
74
+ ```ts
75
+ const { txid } = await client.callContract({ contract, functionName: "mint" });
76
+ const receipt = await client.waitForTransactionReceipt({ txid, confirmations: 2 });
77
+ receipt.result; // decoded ClarityValue
78
+
79
+ // or in one step:
80
+ const { receipt } = await sendTransaction(client, { transaction, wait: 2 });
81
+ ```
82
+
83
+ Status reads are pluggable, like nonce sources: the default reads `/extended/v1/tx` on your transport host; `indexTxSource()` reads Secondlayer's index, which returns the chain tip in the same response — N-confirmation waits cost one request per poll. Rejection reasons are typed too: `BroadcastError.reason` is a literal union of all 26 stacks-node rejection strings (with `reasonData` and `txid` attached).
84
+
85
+ ## Bitcoin addresses from the same mnemonic
86
+
87
+ Derive the paired BTC account (what Leather/Xverse show next to your Stacks address) with no extra dependencies — BIP84 native segwit or BIP86 taproot, network-aware:
88
+
89
+ ```ts
90
+ import { mnemonicToBitcoinKeys } from "@secondlayer/stacks/accounts";
91
+
92
+ const btc = mnemonicToBitcoinKeys(mnemonic, { type: "p2tr" });
93
+ btc.address; // bc1p… (path m/86'/0'/0'/0/0)
94
+
95
+ mnemonicToBitcoinKeys(mnemonic, { type: "p2wpkh", network: "testnet" }).address; // tb1q…
96
+ ```
97
+
98
+ Pure derivation — no Bitcoin transaction building or signing. The pubkey→address helpers (`publicKeyToP2wpkhAddress`, `publicKeyToP2trAddress`, `taprootTweakPubkey`) are exported from `@secondlayer/stacks/bitcoin`, validated against the BIP84/86/341 test vectors.
99
+
100
+ The sBTC extension uses the same machinery to derive the **signers' deposit address** straight from the on-chain registry — network-aware, so testnet gives `tb1p…` instead of a wrong-network address:
101
+
102
+ ```ts
103
+ const client = createPublicClient({ chain: mainnet, transport: http() }).extend(sbtc());
104
+ await client.sbtc.getSignersAddress(); // bc1p… (derived from get-current-aggregate-pubkey)
105
+ await client.sbtc.getSignersPublicKey(); // 33-byte aggregate key
106
+ ```
107
+
61
108
  ## Nonce management
62
109
 
63
110
  Stacks' `/v2/accounts` returns only the confirmed nonce — it ignores the mempool. Broadcasting several transactions from one account before the first confirms makes them reuse the same nonce, so every one after the first is rejected (`ConflictingNonceInMempool`). The usual workaround is tracking nonces by hand.
@@ -1,9 +1,12 @@
1
1
  import {
2
+ assertNoFeeTierForProvider,
2
3
  broadcastWithNonceReset,
3
- estimateFee,
4
+ isFeeTier,
4
5
  isProviderAccount,
5
- resolveNonce
6
- } from "./stacks-502j0efj.js";
6
+ resolveFee,
7
+ resolveNonce,
8
+ setUnsignedFee
9
+ } from "./stacks-kjg7fw4y.js";
7
10
  import {
8
11
  buildContractCall,
9
12
  signTransactionWithAccount
@@ -38,6 +41,7 @@ async function callContract(client, params) {
38
41
  throw new Error("Account required");
39
42
  const [contractAddress, contractName] = parseContractId(params.contract);
40
43
  if (isProviderAccount(account)) {
44
+ assertNoFeeTierForProvider(params.fee);
41
45
  const result = await account.provider.request("stx_callContract", {
42
46
  contract: params.contract,
43
47
  functionName: params.functionName,
@@ -46,24 +50,21 @@ async function callContract(client, params) {
46
50
  return result.txid;
47
51
  }
48
52
  const nonce = params.nonce ?? await resolveNonce(client, account.address);
53
+ const needsFeeResolution = params.fee === undefined || isFeeTier(params.fee);
49
54
  const unsigned = buildContractCall({
50
55
  contractAddress,
51
56
  contractName,
52
57
  functionName: params.functionName,
53
58
  functionArgs: params.functionArgs ?? [],
54
- fee: params.fee ?? 0n,
59
+ fee: needsFeeResolution ? 0n : params.fee,
55
60
  nonce,
56
61
  publicKey: account.publicKey,
57
62
  chain: client.chain,
58
63
  postConditionMode: params.postConditionMode,
59
64
  postConditions: params.postConditions
60
65
  });
61
- if (params.fee === undefined) {
62
- const estimates = await estimateFee(client, { transaction: unsigned });
63
- const mid = estimates[1] ?? estimates[0];
64
- if (mid) {
65
- unsigned.auth.spendingCondition.fee = BigInt(mid.fee);
66
- }
66
+ if (needsFeeResolution) {
67
+ setUnsignedFee(unsigned, await resolveFee(client, unsigned, params.fee));
67
68
  }
68
69
  const signed = await signTransactionWithAccount(unsigned, account);
69
70
  return broadcastWithNonceReset(client, {
@@ -74,5 +75,5 @@ async function callContract(client, params) {
74
75
 
75
76
  export { getMapEntry, callContract };
76
77
 
77
- //# debugId=38BA122B145AC1B064756E2164756E21
78
- //# sourceMappingURL=stacks-v150hffx.js.map
78
+ //# debugId=4BCB4DDE739B706C64756E2164756E21
79
+ //# sourceMappingURL=stacks-01pbr7gf.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/actions/public/getMapEntry.ts", "../src/actions/wallet/callContract.ts"],
4
+ "sourcesContent": [
5
+ "import { deserializeCVBytes } from \"../../clarity/deserialize.ts\";\nimport { serializeCVBytes } from \"../../clarity/serialize.ts\";\nimport type { ClarityValue } from \"../../clarity/types.ts\";\nimport type { Client } from \"../../clients/types.ts\";\nimport { parseContractId } from \"../../utils/address.ts\";\nimport { bytesToHex, with0x } from \"../../utils/encoding.ts\";\n\nexport type GetMapEntryParams = {\n\tcontract: string; // \"address.name\"\n\tmapName: string;\n\tkey: ClarityValue;\n};\n\nexport async function getMapEntry<T extends ClarityValue = ClarityValue>(\n\tclient: Client,\n\tparams: GetMapEntryParams,\n): Promise<T> {\n\tconst [address, name] = parseContractId(params.contract);\n\tconst serializedKey = with0x(bytesToHex(serializeCVBytes(params.key)));\n\n\tconst data = await client.request(\n\t\t`/v2/map_entry/${address}/${name}/${params.mapName}`,\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: serializedKey,\n\t\t},\n\t);\n\n\treturn deserializeCVBytes<T>(data.data);\n}\n",
6
+ "import type { ClarityValue } from \"../../clarity/types.ts\";\nimport type { Client } from \"../../clients/types.ts\";\nimport type { PostCondition } from \"../../postconditions/types.ts\";\nimport { buildContractCall } from \"../../transactions/build.ts\";\nimport { signTransactionWithAccount } from \"../../transactions/signer.ts\";\nimport { parseContractId } from \"../../utils/address.ts\";\nimport type { IntegerType } from \"../../utils/encoding.ts\";\nimport { broadcastWithNonceReset, resolveNonce } from \"./nonceManager.ts\";\nimport {\n\ttype FeeParam,\n\tassertNoFeeTierForProvider,\n\tisFeeTier,\n\tisProviderAccount,\n\tresolveFee,\n\tsetUnsignedFee,\n} from \"./utils.ts\";\n\nexport type CallContractParams = {\n\tcontract: string; // \"address.name\"\n\tfunctionName: string;\n\tfunctionArgs?: ClarityValue[];\n\tfee?: FeeParam;\n\tnonce?: IntegerType;\n\tpostConditionMode?: \"allow\" | \"deny\";\n\tpostConditions?: PostCondition[];\n};\n\n/** Build, sign, and broadcast a contract call */\nexport async function callContract(\n\tclient: Client,\n\tparams: CallContractParams,\n): Promise<string> {\n\tconst account = client.account;\n\tif (!account) throw new Error(\"Account required\");\n\n\t// Validate the contract id up front so both the provider and local paths\n\t// reject malformed input instead of forwarding it to the wallet.\n\tconst [contractAddress, contractName] = parseContractId(params.contract);\n\n\t// Provider: delegate to wallet\n\tif (isProviderAccount(account)) {\n\t\tassertNoFeeTierForProvider(params.fee);\n\t\tconst result = await account.provider.request(\"stx_callContract\", {\n\t\t\tcontract: params.contract,\n\t\t\tfunctionName: params.functionName,\n\t\t\tfunctionArgs: params.functionArgs ?? [],\n\t\t});\n\t\treturn result.txid;\n\t}\n\n\t// Local/Custom: build → sign → broadcast\n\tconst nonce = params.nonce ?? (await resolveNonce(client, account.address));\n\n\tconst needsFeeResolution = params.fee === undefined || isFeeTier(params.fee);\n\n\tconst unsigned = buildContractCall({\n\t\tcontractAddress,\n\t\tcontractName,\n\t\tfunctionName: params.functionName,\n\t\tfunctionArgs: params.functionArgs ?? [],\n\t\tfee: needsFeeResolution ? 0n : (params.fee as IntegerType),\n\t\tnonce,\n\t\tpublicKey: account.publicKey,\n\t\tchain: client.chain,\n\t\tpostConditionMode: params.postConditionMode,\n\t\tpostConditions: params.postConditions,\n\t});\n\n\tif (needsFeeResolution) {\n\t\tsetUnsignedFee(unsigned, await resolveFee(client, unsigned, params.fee));\n\t}\n\n\tconst signed = await signTransactionWithAccount(unsigned, account);\n\treturn broadcastWithNonceReset(client, {\n\t\ttransaction: signed,\n\t\taddress: account.address,\n\t});\n}\n"
7
+ ],
8
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,eAAsB,WAAkD,CACvE,QACA,QACa;AAAA,EACb,OAAO,SAAS,QAAQ,gBAAgB,OAAO,QAAQ;AAAA,EACvD,MAAM,gBAAgB,OAAO,WAAW,iBAAiB,OAAO,GAAG,CAAC,CAAC;AAAA,EAErE,MAAM,OAAO,MAAM,OAAO,QACzB,iBAAiB,WAAW,QAAQ,OAAO,WAC3C;AAAA,IACC,QAAQ;AAAA,IACR,MAAM;AAAA,EACP,CACD;AAAA,EAEA,OAAO,mBAAsB,KAAK,IAAI;AAAA;;;ACAvC,eAAsB,YAAY,CACjC,QACA,QACkB;AAAA,EAClB,MAAM,UAAU,OAAO;AAAA,EACvB,IAAI,CAAC;AAAA,IAAS,MAAM,IAAI,MAAM,kBAAkB;AAAA,EAIhD,OAAO,iBAAiB,gBAAgB,gBAAgB,OAAO,QAAQ;AAAA,EAGvE,IAAI,kBAAkB,OAAO,GAAG;AAAA,IAC/B,2BAA2B,OAAO,GAAG;AAAA,IACrC,MAAM,SAAS,MAAM,QAAQ,SAAS,QAAQ,oBAAoB;AAAA,MACjE,UAAU,OAAO;AAAA,MACjB,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO,gBAAgB,CAAC;AAAA,IACvC,CAAC;AAAA,IACD,OAAO,OAAO;AAAA,EACf;AAAA,EAGA,MAAM,QAAQ,OAAO,SAAU,MAAM,aAAa,QAAQ,QAAQ,OAAO;AAAA,EAEzE,MAAM,qBAAqB,OAAO,QAAQ,aAAa,UAAU,OAAO,GAAG;AAAA,EAE3E,MAAM,WAAW,kBAAkB;AAAA,IAClC;AAAA,IACA;AAAA,IACA,cAAc,OAAO;AAAA,IACrB,cAAc,OAAO,gBAAgB,CAAC;AAAA,IACtC,KAAK,qBAAqB,KAAM,OAAO;AAAA,IACvC;AAAA,IACA,WAAW,QAAQ;AAAA,IACnB,OAAO,OAAO;AAAA,IACd,mBAAmB,OAAO;AAAA,IAC1B,gBAAgB,OAAO;AAAA,EACxB,CAAC;AAAA,EAED,IAAI,oBAAoB;AAAA,IACvB,eAAe,UAAU,MAAM,WAAW,QAAQ,UAAU,OAAO,GAAG,CAAC;AAAA,EACxE;AAAA,EAEA,MAAM,SAAS,MAAM,2BAA2B,UAAU,OAAO;AAAA,EACjE,OAAO,wBAAwB,QAAQ;AAAA,IACtC,aAAa;AAAA,IACb,SAAS,QAAQ;AAAA,EAClB,CAAC;AAAA;",
9
+ "debugId": "4BCB4DDE739B706C64756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,225 @@
1
+ import {
2
+ base58,
3
+ bech32,
4
+ bech32m
5
+ } from "./stacks-5nmz5ad9.js";
6
+ import {
7
+ concatBytes,
8
+ hash160,
9
+ hexToBytes,
10
+ sha256
11
+ } from "./stacks-qs5fzts5.js";
12
+
13
+ // src/bitcoin/serialize.ts
14
+ function doubleSha256(bytes) {
15
+ return sha256(sha256(bytes));
16
+ }
17
+ function reverseBytes(bytes) {
18
+ const out = new Uint8Array(bytes.length);
19
+ for (let i = 0;i < bytes.length; i++) {
20
+ out[i] = bytes[bytes.length - 1 - i];
21
+ }
22
+ return out;
23
+ }
24
+
25
+ class BtcReader {
26
+ data;
27
+ view;
28
+ offset = 0;
29
+ constructor(data) {
30
+ this.data = data;
31
+ this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
32
+ }
33
+ get length() {
34
+ return this.data.length;
35
+ }
36
+ readUInt8() {
37
+ const v = this.view.getUint8(this.offset);
38
+ this.offset += 1;
39
+ return v;
40
+ }
41
+ peekUInt8() {
42
+ return this.view.getUint8(this.offset);
43
+ }
44
+ readUInt32LE() {
45
+ const v = this.view.getUint32(this.offset, true);
46
+ this.offset += 4;
47
+ return v;
48
+ }
49
+ readUInt64LE() {
50
+ const v = this.view.getBigUint64(this.offset, true);
51
+ this.offset += 8;
52
+ return v;
53
+ }
54
+ readBytes(n) {
55
+ if (this.offset + n > this.data.length) {
56
+ throw new Error(`Bitcoin tx underflow: need ${n} bytes at offset ${this.offset}, have ${this.data.length}`);
57
+ }
58
+ const slice = this.data.slice(this.offset, this.offset + n);
59
+ this.offset += n;
60
+ return slice;
61
+ }
62
+ readVarInt() {
63
+ const first = this.readUInt8();
64
+ if (first < 253)
65
+ return first;
66
+ if (first === 253) {
67
+ const v = this.view.getUint16(this.offset, true);
68
+ this.offset += 2;
69
+ return v;
70
+ }
71
+ if (first === 254) {
72
+ return this.readUInt32LE();
73
+ }
74
+ const big = this.readUInt64LE();
75
+ if (big > BigInt(Number.MAX_SAFE_INTEGER)) {
76
+ throw new Error("Bitcoin varint exceeds safe integer range");
77
+ }
78
+ return Number(big);
79
+ }
80
+ }
81
+ function scanTx(rawTx) {
82
+ const r = new BtcReader(rawTx);
83
+ const version = r.readUInt32LE();
84
+ let hasWitness = false;
85
+ if (r.peekUInt8() === 0) {
86
+ r.readUInt8();
87
+ const flag = r.readUInt8();
88
+ if (flag !== 1) {
89
+ throw new Error(`Unexpected SegWit flag 0x${flag.toString(16)}`);
90
+ }
91
+ hasWitness = true;
92
+ }
93
+ const bodyStart = r.offset;
94
+ const inputCount = r.readVarInt();
95
+ const inputs = [];
96
+ for (let i = 0;i < inputCount; i++) {
97
+ const prevTxid = r.readBytes(32);
98
+ const vout = r.readUInt32LE();
99
+ const scriptSig = r.readBytes(r.readVarInt());
100
+ const sequence = r.readUInt32LE();
101
+ inputs.push({ prevTxid, vout, scriptSig, sequence });
102
+ }
103
+ const outputCount = r.readVarInt();
104
+ const outputs = [];
105
+ for (let i = 0;i < outputCount; i++) {
106
+ const value = r.readUInt64LE();
107
+ const scriptPubKey = r.readBytes(r.readVarInt());
108
+ outputs.push({ value, scriptPubKey });
109
+ }
110
+ const bodyEnd = r.offset;
111
+ if (hasWitness) {
112
+ for (let i = 0;i < inputCount; i++) {
113
+ const itemCount = r.readVarInt();
114
+ for (let j = 0;j < itemCount; j++) {
115
+ r.readBytes(r.readVarInt());
116
+ }
117
+ }
118
+ }
119
+ const locktime = r.readUInt32LE();
120
+ const legacy = concatBytes(rawTx.slice(0, 4), rawTx.slice(bodyStart, bodyEnd), rawTx.slice(r.offset - 4, r.offset));
121
+ return { version, hasWitness, inputs, outputs, locktime, legacy };
122
+ }
123
+ function parseBitcoinTx(rawTx) {
124
+ const s = scanTx(rawTx);
125
+ return {
126
+ version: s.version,
127
+ hasWitness: s.hasWitness,
128
+ inputs: s.inputs,
129
+ outputs: s.outputs,
130
+ locktime: s.locktime,
131
+ txidInternal: doubleSha256(s.legacy)
132
+ };
133
+ }
134
+ function stripWitness(rawTx) {
135
+ return scanTx(rawTx).legacy;
136
+ }
137
+ function bitcoinTxid(rawTx, { display = false } = {}) {
138
+ const txid = doubleSha256(scanTx(rawTx).legacy);
139
+ return display ? reverseBytes(txid) : txid;
140
+ }
141
+ function parseBlockHeader(header) {
142
+ if (header.length !== 80) {
143
+ throw new Error(`Bitcoin block header must be 80 bytes, got ${header.length}`);
144
+ }
145
+ const r = new BtcReader(header);
146
+ const version = r.readUInt32LE();
147
+ const prevBlock = r.readBytes(32);
148
+ const merkleRoot = r.readBytes(32);
149
+ const timestamp = r.readUInt32LE();
150
+ const bits = r.readUInt32LE();
151
+ const nonce = r.readUInt32LE();
152
+ return { version, prevBlock, merkleRoot, timestamp, bits, nonce };
153
+ }
154
+ function blockHash(header, { display = false } = {}) {
155
+ const hash = doubleSha256(header);
156
+ return display ? reverseBytes(hash) : hash;
157
+ }
158
+
159
+ // src/bitcoin/address.ts
160
+ import { schnorr, secp256k1 } from "@noble/curves/secp256k1.js";
161
+ var BITCOIN_NETWORK_PARAMS = {
162
+ mainnet: { p2pkh: 0, p2sh: 5, hrp: "bc" },
163
+ testnet: { p2pkh: 111, p2sh: 196, hrp: "tb" },
164
+ regtest: { p2pkh: 111, p2sh: 196, hrp: "bcrt" }
165
+ };
166
+ var NETWORK_PARAMS = BITCOIN_NETWORK_PARAMS;
167
+ function base58Check(version, payload) {
168
+ const data = concatBytes(Uint8Array.of(version), payload);
169
+ const checksum = doubleSha256(data).slice(0, 4);
170
+ return base58.encode(concatBytes(data, checksum));
171
+ }
172
+ function formatBitcoinAddress(parsed, network = "mainnet") {
173
+ const params = NETWORK_PARAMS[network];
174
+ const hash = parsed.hash;
175
+ if (!hash)
176
+ return;
177
+ switch (parsed.type) {
178
+ case "p2pkh":
179
+ return base58Check(params.p2pkh, hash);
180
+ case "p2sh":
181
+ return base58Check(params.p2sh, hash);
182
+ case "p2wpkh":
183
+ case "p2wsh":
184
+ return bech32.encode(params.hrp, [0, ...bech32.toWords(hash)]);
185
+ case "p2tr":
186
+ return bech32m.encode(params.hrp, [1, ...bech32m.toWords(hash)]);
187
+ default:
188
+ return;
189
+ }
190
+ }
191
+ function toPubkeyBytes(publicKey) {
192
+ return typeof publicKey === "string" ? hexToBytes(publicKey) : publicKey;
193
+ }
194
+ function taprootTweakPubkey(xonly) {
195
+ if (xonly.length !== 32)
196
+ throw new Error(`Expected 32-byte x-only pubkey, got ${xonly.length}`);
197
+ const tweak = schnorr.utils.taggedHash("TapTweak", xonly);
198
+ const t = BigInt(`0x${Array.from(tweak, (b) => b.toString(16).padStart(2, "0")).join("")}`);
199
+ if (t >= secp256k1.Point.Fn.ORDER)
200
+ throw new Error("Invalid tap tweak (exceeds curve order)");
201
+ const internal = secp256k1.Point.fromBytes(concatBytes(Uint8Array.of(2), xonly));
202
+ const output = internal.add(secp256k1.Point.BASE.multiply(t));
203
+ return output.toBytes(true).slice(1);
204
+ }
205
+ function publicKeyToP2wpkhAddress(publicKey, network = "mainnet") {
206
+ const pubkey = toPubkeyBytes(publicKey);
207
+ if (pubkey.length !== 33)
208
+ throw new Error(`Expected 33-byte compressed pubkey, got ${pubkey.length}`);
209
+ const params = NETWORK_PARAMS[network];
210
+ return bech32.encode(params.hrp, [0, ...bech32.toWords(hash160(pubkey))]);
211
+ }
212
+ function publicKeyToP2trAddress(publicKey, network = "mainnet") {
213
+ const pubkey = toPubkeyBytes(publicKey);
214
+ const xonly = pubkey.length === 33 ? pubkey.slice(1) : pubkey.length === 32 ? pubkey : undefined;
215
+ if (!xonly)
216
+ throw new Error(`Expected 33-byte compressed or 32-byte x-only pubkey, got ${pubkey.length}`);
217
+ const params = NETWORK_PARAMS[network];
218
+ const outputKey = taprootTweakPubkey(xonly);
219
+ return bech32m.encode(params.hrp, [1, ...bech32m.toWords(outputKey)]);
220
+ }
221
+
222
+ export { doubleSha256, reverseBytes, BtcReader, parseBitcoinTx, stripWitness, bitcoinTxid, parseBlockHeader, blockHash, BITCOIN_NETWORK_PARAMS, formatBitcoinAddress, taprootTweakPubkey, publicKeyToP2wpkhAddress, publicKeyToP2trAddress };
223
+
224
+ //# debugId=2F165CAF7A83BCB564756E2164756E21
225
+ //# sourceMappingURL=stacks-0cdm20eh.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/bitcoin/serialize.ts", "../src/bitcoin/address.ts"],
4
+ "sourcesContent": [
5
+ "import { concatBytes } from \"../utils/encoding.ts\";\nimport { sha256 } from \"../utils/hash.ts\";\n\n/**\n * Bitcoin double-SHA256: `sha256(sha256(bytes))`. This is the hash Bitcoin uses\n * for txids, block headers, and merkle nodes — NOT the same as the Stacks\n * `txidFromBytes` (which uses sha512_256), so it lives here, not in `utils/hash`.\n */\nexport function doubleSha256(bytes: Uint8Array): Uint8Array {\n\treturn sha256(sha256(bytes));\n}\n\n/**\n * Reverse a byte array. Bitcoin hashes are computed and stored in *internal*\n * (little-endian) order but *displayed* big-endian, so the two differ by a\n * reversal. The SIP-044 built-ins consume internal order; only reverse for\n * display / when matching an explorer value.\n */\nexport function reverseBytes(bytes: Uint8Array): Uint8Array {\n\tconst out = new Uint8Array(bytes.length);\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tout[i] = bytes[bytes.length - 1 - i] as number;\n\t}\n\treturn out;\n}\n\n/**\n * A little-endian, varint-aware byte reader for Bitcoin serialization. The\n * shared `utils/BytesReader` is big-endian only; Bitcoin tx fields are\n * little-endian with compact-size (varint) length prefixes.\n */\nexport class BtcReader {\n\tprivate readonly data: Uint8Array;\n\tprivate readonly view: DataView;\n\tpublic offset = 0;\n\n\tconstructor(data: Uint8Array) {\n\t\tthis.data = data;\n\t\tthis.view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\t}\n\n\tget length(): number {\n\t\treturn this.data.length;\n\t}\n\n\treadUInt8(): number {\n\t\tconst v = this.view.getUint8(this.offset);\n\t\tthis.offset += 1;\n\t\treturn v;\n\t}\n\n\t/** Read the next byte without advancing. */\n\tpeekUInt8(): number {\n\t\treturn this.view.getUint8(this.offset);\n\t}\n\n\treadUInt32LE(): number {\n\t\tconst v = this.view.getUint32(this.offset, true);\n\t\tthis.offset += 4;\n\t\treturn v;\n\t}\n\n\treadUInt64LE(): bigint {\n\t\tconst v = this.view.getBigUint64(this.offset, true);\n\t\tthis.offset += 8;\n\t\treturn v;\n\t}\n\n\treadBytes(n: number): Uint8Array {\n\t\tif (this.offset + n > this.data.length) {\n\t\t\tthrow new Error(\n\t\t\t\t`Bitcoin tx underflow: need ${n} bytes at offset ${this.offset}, have ${this.data.length}`,\n\t\t\t);\n\t\t}\n\t\tconst slice = this.data.slice(this.offset, this.offset + n);\n\t\tthis.offset += n;\n\t\treturn slice;\n\t}\n\n\t/** Read a Bitcoin compact-size unsigned integer (varint). */\n\treadVarInt(): number {\n\t\tconst first = this.readUInt8();\n\t\tif (first < 0xfd) return first;\n\t\tif (first === 0xfd) {\n\t\t\tconst v = this.view.getUint16(this.offset, true);\n\t\t\tthis.offset += 2;\n\t\t\treturn v;\n\t\t}\n\t\tif (first === 0xfe) {\n\t\t\treturn this.readUInt32LE();\n\t\t}\n\t\tconst big = this.readUInt64LE();\n\t\tif (big > BigInt(Number.MAX_SAFE_INTEGER)) {\n\t\t\tthrow new Error(\"Bitcoin varint exceeds safe integer range\");\n\t\t}\n\t\treturn Number(big);\n\t}\n}\n\nexport interface BitcoinTxInput {\n\t/** Previous output txid, in serialized (internal) byte order. */\n\tprevTxid: Uint8Array;\n\tvout: number;\n\tscriptSig: Uint8Array;\n\tsequence: number;\n}\n\nexport interface BitcoinTxOutput {\n\t/** Output value in satoshis. */\n\tvalue: bigint;\n\tscriptPubKey: Uint8Array;\n}\n\nexport interface ParsedBitcoinTx {\n\tversion: number;\n\thasWitness: boolean;\n\tinputs: BitcoinTxInput[];\n\toutputs: BitcoinTxOutput[];\n\tlocktime: number;\n\t/**\n\t * The legacy txid as the raw double-SHA256 in *internal* byte order — ready\n\t * to pass as the leaf to `verify-merkle-proof`. Witness data is excluded\n\t * (the txid is computed over the legacy serialization), so this is stable for\n\t * both legacy and SegWit txs. Use `reverseBytes` for the displayed form.\n\t */\n\ttxidInternal: Uint8Array;\n}\n\ninterface ScanResult {\n\tversion: number;\n\thasWitness: boolean;\n\tinputs: BitcoinTxInput[];\n\toutputs: BitcoinTxOutput[];\n\tlocktime: number;\n\t/** The legacy (witness-stripped) serialization — what the txid is hashed over. */\n\tlegacy: Uint8Array;\n}\n\n/**\n * Single-pass scan of a raw Bitcoin tx. Captures the inputs/outputs slice and\n * reassembles the legacy serialization so both `parseBitcoinTx` and\n * `stripWitness` share one parser (and one set of foot-guns).\n */\nfunction scanTx(rawTx: Uint8Array): ScanResult {\n\tconst r = new BtcReader(rawTx);\n\tconst version = r.readUInt32LE();\n\n\t// SegWit marker (0x00) + flag (0x01) sit immediately after the version. A\n\t// legacy tx can never have a zero input count, so 0x00 here is unambiguous.\n\tlet hasWitness = false;\n\tif (r.peekUInt8() === 0x00) {\n\t\tr.readUInt8(); // marker\n\t\tconst flag = r.readUInt8();\n\t\tif (flag !== 0x01) {\n\t\t\tthrow new Error(`Unexpected SegWit flag 0x${flag.toString(16)}`);\n\t\t}\n\t\thasWitness = true;\n\t}\n\n\tconst bodyStart = r.offset;\n\tconst inputCount = r.readVarInt();\n\tconst inputs: BitcoinTxInput[] = [];\n\tfor (let i = 0; i < inputCount; i++) {\n\t\tconst prevTxid = r.readBytes(32);\n\t\tconst vout = r.readUInt32LE();\n\t\tconst scriptSig = r.readBytes(r.readVarInt());\n\t\tconst sequence = r.readUInt32LE();\n\t\tinputs.push({ prevTxid, vout, scriptSig, sequence });\n\t}\n\n\tconst outputCount = r.readVarInt();\n\tconst outputs: BitcoinTxOutput[] = [];\n\tfor (let i = 0; i < outputCount; i++) {\n\t\tconst value = r.readUInt64LE();\n\t\tconst scriptPubKey = r.readBytes(r.readVarInt());\n\t\toutputs.push({ value, scriptPubKey });\n\t}\n\tconst bodyEnd = r.offset;\n\n\tif (hasWitness) {\n\t\tfor (let i = 0; i < inputCount; i++) {\n\t\t\tconst itemCount = r.readVarInt();\n\t\t\tfor (let j = 0; j < itemCount; j++) {\n\t\t\t\tr.readBytes(r.readVarInt());\n\t\t\t}\n\t\t}\n\t}\n\n\tconst locktime = r.readUInt32LE();\n\n\tconst legacy = concatBytes(\n\t\trawTx.slice(0, 4),\n\t\trawTx.slice(bodyStart, bodyEnd),\n\t\trawTx.slice(r.offset - 4, r.offset),\n\t);\n\n\treturn { version, hasWitness, inputs, outputs, locktime, legacy };\n}\n\n/** Parse a serialized Bitcoin tx (legacy or SegWit) into its fields + txid. */\nexport function parseBitcoinTx(rawTx: Uint8Array): ParsedBitcoinTx {\n\tconst s = scanTx(rawTx);\n\treturn {\n\t\tversion: s.version,\n\t\thasWitness: s.hasWitness,\n\t\tinputs: s.inputs,\n\t\toutputs: s.outputs,\n\t\tlocktime: s.locktime,\n\t\ttxidInternal: doubleSha256(s.legacy),\n\t};\n}\n\n/**\n * Return the legacy (witness-stripped) serialization of a tx. For a legacy tx\n * this is the input unchanged; for a SegWit tx the marker, flag, and witness\n * stack are removed. This is the byte string the txid is hashed over.\n */\nexport function stripWitness(rawTx: Uint8Array): Uint8Array {\n\treturn scanTx(rawTx).legacy;\n}\n\n/**\n * Compute a tx's id from its raw serialization. Internal byte order by default\n * (the merkle leaf / built-in input); pass `{ display: true }` for the\n * explorer-style big-endian form.\n */\nexport function bitcoinTxid(\n\trawTx: Uint8Array,\n\t{ display = false }: { display?: boolean } = {},\n): Uint8Array {\n\tconst txid = doubleSha256(scanTx(rawTx).legacy);\n\treturn display ? reverseBytes(txid) : txid;\n}\n\nexport interface BlockHeader {\n\tversion: number;\n\t/** Previous block hash, internal byte order. */\n\tprevBlock: Uint8Array;\n\t/** Merkle root, internal byte order — pairs with `verify-merkle-proof`. */\n\tmerkleRoot: Uint8Array;\n\ttimestamp: number;\n\tbits: number;\n\tnonce: number;\n}\n\n/** Parse an 80-byte Bitcoin block header into its fields (hashes internal order). */\nexport function parseBlockHeader(header: Uint8Array): BlockHeader {\n\tif (header.length !== 80) {\n\t\tthrow new Error(\n\t\t\t`Bitcoin block header must be 80 bytes, got ${header.length}`,\n\t\t);\n\t}\n\tconst r = new BtcReader(header);\n\tconst version = r.readUInt32LE();\n\tconst prevBlock = r.readBytes(32);\n\tconst merkleRoot = r.readBytes(32);\n\tconst timestamp = r.readUInt32LE();\n\tconst bits = r.readUInt32LE();\n\tconst nonce = r.readUInt32LE();\n\treturn { version, prevBlock, merkleRoot, timestamp, bits, nonce };\n}\n\n/**\n * Hash an 80-byte block header (double-SHA256). Internal byte order by default;\n * `{ display: true }` for the explorer-style block hash.\n */\nexport function blockHash(\n\theader: Uint8Array,\n\t{ display = false }: { display?: boolean } = {},\n): Uint8Array {\n\tconst hash = doubleSha256(header);\n\treturn display ? reverseBytes(hash) : hash;\n}\n",
6
+ "import { schnorr, secp256k1 } from \"@noble/curves/secp256k1.js\";\nimport { base58, bech32, bech32m } from \"@scure/base\";\nimport { concatBytes, hexToBytes } from \"../utils/encoding.ts\";\nimport { hash160 } from \"../utils/hash.ts\";\nimport type { ParsedOutputScript } from \"./codec.ts\";\nimport type { BitcoinNetwork } from \"./constants.ts\";\nimport { doubleSha256 } from \"./serialize.ts\";\n\n/** Address-encoding parameters (base58 version bytes + bech32 hrp) per network. */\nexport const BITCOIN_NETWORK_PARAMS = {\n\tmainnet: { p2pkh: 0x00, p2sh: 0x05, hrp: \"bc\" },\n\ttestnet: { p2pkh: 0x6f, p2sh: 0xc4, hrp: \"tb\" },\n\tregtest: { p2pkh: 0x6f, p2sh: 0xc4, hrp: \"bcrt\" },\n} as const;\n\nconst NETWORK_PARAMS = BITCOIN_NETWORK_PARAMS;\n\n/** Base58Check-encode a versioned 20-byte payload (legacy P2PKH / P2SH). */\nfunction base58Check(version: number, payload: Uint8Array): string {\n\tconst data = concatBytes(Uint8Array.of(version), payload);\n\tconst checksum = doubleSha256(data).slice(0, 4);\n\treturn base58.encode(concatBytes(data, checksum));\n}\n\n/**\n * Render a parsed output script as a Bitcoin address for the given network.\n * Returns `undefined` for scripts without a standard address (OP_RETURN, P2PK,\n * unknown). Address encoding is network-dependent, which is why this is separate\n * from the pure `parseOutputScript` decoder.\n */\nexport function formatBitcoinAddress(\n\tparsed: ParsedOutputScript,\n\tnetwork: BitcoinNetwork = \"mainnet\",\n): string | undefined {\n\tconst params = NETWORK_PARAMS[network];\n\tconst hash = parsed.hash;\n\tif (!hash) return undefined;\n\tswitch (parsed.type) {\n\t\tcase \"p2pkh\":\n\t\t\treturn base58Check(params.p2pkh, hash);\n\t\tcase \"p2sh\":\n\t\t\treturn base58Check(params.p2sh, hash);\n\t\tcase \"p2wpkh\":\n\t\tcase \"p2wsh\":\n\t\t\treturn bech32.encode(params.hrp, [0, ...bech32.toWords(hash)]);\n\t\tcase \"p2tr\":\n\t\t\treturn bech32m.encode(params.hrp, [1, ...bech32m.toWords(hash)]);\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction toPubkeyBytes(publicKey: Uint8Array | string): Uint8Array {\n\treturn typeof publicKey === \"string\" ? hexToBytes(publicKey) : publicKey;\n}\n\n/**\n * BIP341 key-path tweak: lift the x-only internal key to a point, add\n * `tapTweakHash(P)·G` (no script tree), and return the x-only output key.\n */\nexport function taprootTweakPubkey(xonly: Uint8Array): Uint8Array {\n\tif (xonly.length !== 32)\n\t\tthrow new Error(`Expected 32-byte x-only pubkey, got ${xonly.length}`);\n\tconst tweak = schnorr.utils.taggedHash(\"TapTweak\", xonly);\n\tconst t = BigInt(\n\t\t`0x${Array.from(tweak, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")}`,\n\t);\n\tif (t >= secp256k1.Point.Fn.ORDER)\n\t\tthrow new Error(\"Invalid tap tweak (exceeds curve order)\");\n\tconst internal = secp256k1.Point.fromBytes(\n\t\tconcatBytes(Uint8Array.of(0x02), xonly),\n\t);\n\tconst output = internal.add(secp256k1.Point.BASE.multiply(t));\n\treturn output.toBytes(true).slice(1);\n}\n\n/**\n * Derive the native-segwit (P2WPKH, bech32 v0) address for a compressed\n * public key.\n */\nexport function publicKeyToP2wpkhAddress(\n\tpublicKey: Uint8Array | string,\n\tnetwork: BitcoinNetwork = \"mainnet\",\n): string {\n\tconst pubkey = toPubkeyBytes(publicKey);\n\tif (pubkey.length !== 33)\n\t\tthrow new Error(`Expected 33-byte compressed pubkey, got ${pubkey.length}`);\n\tconst params = NETWORK_PARAMS[network];\n\treturn bech32.encode(params.hrp, [0, ...bech32.toWords(hash160(pubkey))]);\n}\n\n/**\n * Derive the taproot (P2TR, bech32m v1) address for a public key — BIP341\n * key-path spend, no script tree. Accepts a 33-byte compressed key (the\n * parity byte is dropped) or a 32-byte x-only key.\n */\nexport function publicKeyToP2trAddress(\n\tpublicKey: Uint8Array | string,\n\tnetwork: BitcoinNetwork = \"mainnet\",\n): string {\n\tconst pubkey = toPubkeyBytes(publicKey);\n\tconst xonly =\n\t\tpubkey.length === 33\n\t\t\t? pubkey.slice(1)\n\t\t\t: pubkey.length === 32\n\t\t\t\t? pubkey\n\t\t\t\t: undefined;\n\tif (!xonly)\n\t\tthrow new Error(\n\t\t\t`Expected 33-byte compressed or 32-byte x-only pubkey, got ${pubkey.length}`,\n\t\t);\n\tconst params = NETWORK_PARAMS[network];\n\tconst outputKey = taprootTweakPubkey(xonly);\n\treturn bech32m.encode(params.hrp, [1, ...bech32m.toWords(outputKey)]);\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "2F165CAF7A83BCB564756E2164756E21",
10
+ "names": []
11
+ }
@@ -11,14 +11,7 @@ async function sponsorTransaction(client, params) {
11
11
  throw new Error("Provider accounts cannot sponsor transactions");
12
12
  }
13
13
  const nonce = params.nonce != null ? intToBigInt(params.nonce) : await resolveNonce(client, account.address);
14
- let fee;
15
- if (params.fee != null) {
16
- fee = intToBigInt(params.fee);
17
- } else {
18
- const estimates = await estimateFee(client, { transaction });
19
- const mid = estimates[1] ?? estimates[0];
20
- fee = mid ? BigInt(mid.fee) : 0n;
21
- }
14
+ const fee = await resolveFee(client, transaction, params.fee);
22
15
  const sponsorCondition = createSingleSigSpendingCondition(account.publicKey, nonce, fee);
23
16
  const auth = transaction.auth;
24
17
  const sponsored = {
@@ -31,5 +24,5 @@ async function sponsorTransaction(client, params) {
31
24
  return signSponsorWithAccount(sponsored, account);
32
25
  }
33
26
 
34
- //# debugId=DF17C72EEC5BCD5964756E2164756E21
35
- //# sourceMappingURL=stacks-hxm7r5ay.cjs.map
27
+ //# debugId=2C7F1B8FDFB94A5364756E2164756E21
28
+ //# sourceMappingURL=stacks-44y18a8e.cjs.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/actions/wallet/sponsorTransaction.ts"],
4
+ "sourcesContent": [
5
+ "import type { Client } from \"../../clients/types.ts\";\nimport { createSingleSigSpendingCondition } from \"../../transactions/authorization.ts\";\nimport { signSponsorWithAccount } from \"../../transactions/signer.ts\";\nimport {\n\tAuthType,\n\ttype SponsoredAuthorization,\n\ttype StacksTransaction,\n} from \"../../transactions/types.ts\";\nimport type { IntegerType } from \"../../utils/encoding.ts\";\nimport { intToBigInt } from \"../../utils/encoding.ts\";\nimport { resolveNonce } from \"./nonceManager.ts\";\nimport { type FeeParam, isProviderAccount, resolveFee } from \"./utils.ts\";\n\nexport type SponsorTransactionParams = {\n\ttransaction: StacksTransaction;\n\tfee?: FeeParam;\n\tnonce?: IntegerType;\n};\n\n/** Sponsor a transaction: set sponsor spending condition, sign as sponsor */\nexport async function sponsorTransaction(\n\tclient: Client,\n\tparams: SponsorTransactionParams,\n): Promise<StacksTransaction> {\n\tconst { transaction } = params;\n\n\tif (transaction.auth.authType !== AuthType.Sponsored) {\n\t\tthrow new Error(\"Transaction must have sponsored authorization\");\n\t}\n\n\tconst account = client.account;\n\tif (!account) throw new Error(\"Account required\");\n\tif (isProviderAccount(account)) {\n\t\tthrow new Error(\"Provider accounts cannot sponsor transactions\");\n\t}\n\n\t// Resolve sponsor nonce\n\tconst nonce =\n\t\tparams.nonce != null\n\t\t\t? intToBigInt(params.nonce)\n\t\t\t: await resolveNonce(client, account.address);\n\n\t// Resolve sponsor fee. Estimation failure falls back to the minimum relay\n\t// fee instead of 0 (a 0-fee tx would be rejected at broadcast).\n\tconst fee = await resolveFee(client, transaction, params.fee);\n\n\t// Create sponsor spending condition\n\tconst sponsorCondition = createSingleSigSpendingCondition(\n\t\taccount.publicKey,\n\t\tnonce,\n\t\tfee,\n\t);\n\n\t// Set sponsor spending condition on the tx\n\tconst auth = transaction.auth as SponsoredAuthorization;\n\tconst sponsored: StacksTransaction = {\n\t\t...transaction,\n\t\tauth: {\n\t\t\t...auth,\n\t\t\tsponsorSpendingCondition: sponsorCondition,\n\t\t},\n\t};\n\n\t// Sign as sponsor\n\treturn signSponsorWithAccount(sponsored, account);\n}\n"
6
+ ],
7
+ "mappings": ";AAoBA,eAAsB,kBAAkB,CACvC,QACA,QAC6B;AAAA,EAC7B,QAAQ,gBAAgB;AAAA,EAExB,IAAI,YAAY,KAAK,aAAa,SAAS,WAAW;AAAA,IACrD,MAAM,IAAI,MAAM,+CAA+C;AAAA,EAChE;AAAA,EAEA,MAAM,UAAU,OAAO;AAAA,EACvB,IAAI,CAAC;AAAA,IAAS,MAAM,IAAI,MAAM,kBAAkB;AAAA,EAChD,IAAI,kBAAkB,OAAO,GAAG;AAAA,IAC/B,MAAM,IAAI,MAAM,+CAA+C;AAAA,EAChE;AAAA,EAGA,MAAM,QACL,OAAO,SAAS,OACb,YAAY,OAAO,KAAK,IACxB,MAAM,aAAa,QAAQ,QAAQ,OAAO;AAAA,EAI9C,MAAM,MAAM,MAAM,WAAW,QAAQ,aAAa,OAAO,GAAG;AAAA,EAG5D,MAAM,mBAAmB,iCACxB,QAAQ,WACR,OACA,GACD;AAAA,EAGA,MAAM,OAAO,YAAY;AAAA,EACzB,MAAM,YAA+B;AAAA,OACjC;AAAA,IACH,MAAM;AAAA,SACF;AAAA,MACH,0BAA0B;AAAA,IAC3B;AAAA,EACD;AAAA,EAGA,OAAO,uBAAuB,WAAW,OAAO;AAAA;",
8
+ "debugId": "2C7F1B8FDFB94A5364756E2164756E21",
9
+ "names": []
10
+ }
@@ -2,11 +2,16 @@ import {
2
2
  readContract
3
3
  } from "./stacks-msmgyerb.js";
4
4
  import {
5
+ assertNoFeeTierForProvider,
5
6
  broadcastWithNonceReset,
6
7
  estimateFee,
8
+ extendedApiSource,
9
+ isFeeTier,
7
10
  isProviderAccount,
8
- resolveNonce
9
- } from "./stacks-502j0efj.js";
11
+ resolveFee,
12
+ resolveNonce,
13
+ setUnsignedFee
14
+ } from "./stacks-kjg7fw4y.js";
10
15
  import {
11
16
  BaseError
12
17
  } from "./stacks-709tra19.js";
@@ -75,12 +80,6 @@ async function getBlock(client, params) {
75
80
  return client.request("/extended/v2/blocks?limit=1", { method: "GET" });
76
81
  }
77
82
 
78
- // src/actions/public/getBlockHeight.ts
79
- async function getBlockHeight(client) {
80
- const data = await client.request("/v2/info", { method: "GET" });
81
- return data.stacks_tip_height;
82
- }
83
-
84
83
  // src/actions/public/getContractAbi.ts
85
84
  async function getContractAbi(client, params) {
86
85
  const [address, name] = parseContractId(params.contract);
@@ -89,6 +88,13 @@ async function getContractAbi(client, params) {
89
88
  });
90
89
  }
91
90
 
91
+ // src/actions/public/getTransaction.ts
92
+ async function getTransaction(client, params) {
93
+ const source = params.source ?? extendedApiSource();
94
+ const { receipt } = await source.get({ client, txid: params.txid });
95
+ return receipt;
96
+ }
97
+
92
98
  // src/actions/public/multicall.ts
93
99
  async function multicall(client, params) {
94
100
  const { calls, allowFailure = true } = params;
@@ -183,6 +189,7 @@ async function deployContract(client, params) {
183
189
  if (!isClarityName(params.contractName))
184
190
  throw new Error(`Invalid contract name: ${params.contractName}`);
185
191
  if (isProviderAccount(account)) {
192
+ assertNoFeeTierForProvider(params.fee);
186
193
  const result = await account.provider.request("stx_deployContract", {
187
194
  contractName: params.contractName,
188
195
  codeBody: params.codeBody,
@@ -191,23 +198,20 @@ async function deployContract(client, params) {
191
198
  return result.txid;
192
199
  }
193
200
  const nonce = params.nonce ?? await resolveNonce(client, account.address);
201
+ const needsFeeResolution = params.fee === undefined || isFeeTier(params.fee);
194
202
  const unsigned = buildContractDeploy({
195
203
  contractName: params.contractName,
196
204
  codeBody: params.codeBody,
197
205
  clarityVersion: params.clarityVersion,
198
- fee: params.fee ?? 0n,
206
+ fee: needsFeeResolution ? 0n : params.fee,
199
207
  nonce,
200
208
  publicKey: account.publicKey,
201
209
  chain: client.chain,
202
210
  postConditionMode: params.postConditionMode,
203
211
  postConditions: params.postConditions
204
212
  });
205
- if (params.fee === undefined) {
206
- const estimates = await estimateFee(client, { transaction: unsigned });
207
- const mid = estimates[1] ?? estimates[0];
208
- if (mid) {
209
- unsigned.auth.spendingCondition.fee = BigInt(mid.fee);
210
- }
213
+ if (needsFeeResolution) {
214
+ setUnsignedFee(unsigned, await resolveFee(client, unsigned, params.fee));
211
215
  }
212
216
  const signed = await signTransactionWithAccount(unsigned, account);
213
217
  return broadcastWithNonceReset(client, {
@@ -279,6 +283,7 @@ async function transferStx(client, params) {
279
283
  if (!validateStacksAddress(params.to))
280
284
  throw new Error(`Invalid recipient address: ${params.to}`);
281
285
  if (isProviderAccount(account)) {
286
+ assertNoFeeTierForProvider(params.fee);
282
287
  const result = await account.provider.request("stx_transferStx", {
283
288
  recipient: params.to,
284
289
  amount: String(params.amount),
@@ -287,23 +292,20 @@ async function transferStx(client, params) {
287
292
  return result.txid;
288
293
  }
289
294
  const nonce = params.nonce ?? await resolveNonce(client, account.address);
295
+ const needsFeeResolution = params.fee === undefined || isFeeTier(params.fee);
290
296
  const unsigned = buildTokenTransfer({
291
297
  recipient: params.to,
292
298
  amount: params.amount,
293
299
  memo: params.memo,
294
- fee: params.fee ?? 0n,
300
+ fee: needsFeeResolution ? 0n : params.fee,
295
301
  nonce,
296
302
  publicKey: account.publicKey,
297
303
  chain: client.chain,
298
304
  postConditionMode: params.postConditionMode,
299
305
  postConditions: params.postConditions
300
306
  });
301
- if (params.fee === undefined) {
302
- const estimates = await estimateFee(client, { transaction: unsigned });
303
- const mid = estimates[1] ?? estimates[0];
304
- if (mid) {
305
- unsigned.auth.spendingCondition.fee = BigInt(mid.fee);
306
- }
307
+ if (needsFeeResolution) {
308
+ setUnsignedFee(unsigned, await resolveFee(client, unsigned, params.fee));
307
309
  }
308
310
  const signed = await signTransactionWithAccount(unsigned, account);
309
311
  return broadcastWithNonceReset(client, {
@@ -312,7 +314,7 @@ async function transferStx(client, params) {
312
314
  });
313
315
  }
314
316
 
315
- export { getAccountInfo, getBalance, getBlock, getBlockHeight, getContractAbi, multicall, SimulationError, simulateCall, simulateTransaction, deployContract, signMessage, signTransactionAction, transferStx };
317
+ export { getAccountInfo, getBalance, getBlock, getContractAbi, getTransaction, multicall, SimulationError, simulateCall, simulateTransaction, deployContract, signMessage, signTransactionAction, transferStx };
316
318
 
317
- //# debugId=315A19FD4484DD8064756E2164756E21
318
- //# sourceMappingURL=stacks-7nvbv61d.js.map
319
+ //# debugId=CD5517B72817ABFE64756E2164756E21
320
+ //# sourceMappingURL=stacks-59xy6t1p.js.map