@secondlayer/stacks 4.2.0 → 4.3.1

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 (62) hide show
  1. package/dist/shared/stacks-03vfm21t.cjs +222 -0
  2. package/dist/shared/stacks-03vfm21t.cjs.map +12 -0
  3. package/dist/shared/stacks-0eatsx6d.cjs +25 -0
  4. package/dist/shared/stacks-0eatsx6d.cjs.map +10 -0
  5. package/dist/shared/stacks-1arrcd11.js.map +2 -2
  6. package/dist/shared/{stacks-mrk6tkkh.cjs → stacks-3mt2q2na.cjs} +26 -2
  7. package/dist/shared/{stacks-mrk6tkkh.cjs.map → stacks-3mt2q2na.cjs.map} +1 -1
  8. package/dist/shared/{stacks-rndfw2vh.js → stacks-7wkf2rph.js} +3 -26
  9. package/dist/shared/{stacks-rndfw2vh.js.map → stacks-7wkf2rph.js.map} +3 -5
  10. package/dist/shared/stacks-8pfdscq6.js +52 -0
  11. package/dist/shared/stacks-8pfdscq6.js.map +12 -0
  12. package/dist/shared/stacks-e4xn4m7j.js +27 -0
  13. package/dist/shared/stacks-e4xn4m7j.js.map +10 -0
  14. package/dist/shared/stacks-enpj9krt.cjs.map +2 -2
  15. package/dist/shared/{stacks-9qcr921s.cjs → stacks-kem68d80.cjs} +3 -3
  16. package/dist/shared/stacks-kem68d80.cjs.map +10 -0
  17. package/dist/shared/stacks-wdp5yr8n.cjs +39 -0
  18. package/dist/shared/stacks-wdp5yr8n.cjs.map +12 -0
  19. package/dist/shared/{stacks-0nedd34w.cjs → stacks-ycbq8pf7.cjs} +2 -25
  20. package/dist/shared/{stacks-0nedd34w.cjs.map → stacks-ycbq8pf7.cjs.map} +3 -5
  21. package/dist/shared/{stacks-rpqtgpyj.js → stacks-zcpvzbr0.js} +3 -3
  22. package/dist/shared/stacks-zcpvzbr0.js.map +10 -0
  23. package/dist/shared/stacks-ztzygy90.js +237 -0
  24. package/dist/shared/stacks-ztzygy90.js.map +12 -0
  25. package/dist/src/actions/index.js +5 -5
  26. package/dist/src/actions/index.js.map +1 -1
  27. package/dist/src/bitcoin/index.cjs +1 -217
  28. package/dist/src/bitcoin/index.cjs.map +3 -5
  29. package/dist/src/bitcoin/index.js +11 -223
  30. package/dist/src/bitcoin/index.js.map +3 -5
  31. package/dist/src/bns/index.js +1 -1
  32. package/dist/src/clarity/index.d.cts +1 -1
  33. package/dist/src/clarity/index.d.ts +1 -1
  34. package/dist/src/index.js +5 -5
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/postconditions/index.d.cts +3 -2
  37. package/dist/src/postconditions/index.d.ts +3 -2
  38. package/dist/src/postconditions/index.js +1 -1
  39. package/dist/src/pox/index.cjs +1 -24
  40. package/dist/src/pox/index.cjs.map +3 -4
  41. package/dist/src/pox/index.js +8 -25
  42. package/dist/src/pox/index.js.map +3 -4
  43. package/dist/src/pox5/index.cjs +1118 -204
  44. package/dist/src/pox5/index.cjs.map +13 -8
  45. package/dist/src/pox5/index.d.cts +621 -162
  46. package/dist/src/pox5/index.d.ts +621 -162
  47. package/dist/src/pox5/index.js +1136 -208
  48. package/dist/src/pox5/index.js.map +13 -8
  49. package/dist/src/stackingdao/index.js +1 -1
  50. package/dist/src/tools/index.cjs.map +2 -2
  51. package/dist/src/tools/index.js.map +2 -2
  52. package/package.json +4 -3
  53. package/dist/shared/stacks-2evvn48s.js +0 -22
  54. package/dist/shared/stacks-2evvn48s.js.map +0 -10
  55. package/dist/shared/stacks-3kj51c6p.cjs +0 -16
  56. package/dist/shared/stacks-3kj51c6p.cjs.map +0 -10
  57. package/dist/shared/stacks-9qcr921s.cjs.map +0 -10
  58. package/dist/shared/stacks-rdgg7mj3.js +0 -7
  59. package/dist/shared/stacks-rdgg7mj3.js.map +0 -10
  60. package/dist/shared/stacks-rpqtgpyj.js.map +0 -10
  61. package/dist/shared/stacks-wscmfs7q.cjs +0 -5
  62. package/dist/shared/stacks-wscmfs7q.cjs.map +0 -10
@@ -1,19 +1,32 @@
1
1
  import {
2
- EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET
3
- } from "../../shared/stacks-rdgg7mj3.js";
2
+ EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET,
3
+ buildTxProof
4
+ } from "../../shared/stacks-ztzygy90.js";
4
5
  import {
5
- BITCOIN_NETWORK_PARAMS
6
+ POX_ADDRESS_VERSION
7
+ } from "../../shared/stacks-e4xn4m7j.js";
8
+ import {
9
+ BITCOIN_NETWORK_PARAMS,
10
+ doubleSha256,
11
+ parseBitcoinTx,
12
+ stripWitness
6
13
  } from "../../shared/stacks-0cdm20eh.js";
7
14
  import {
8
- bech32
15
+ base58,
16
+ bech32,
17
+ bech32m
9
18
  } from "../../shared/stacks-5nmz5ad9.js";
10
19
  import {
11
20
  getContract
12
21
  } from "../../shared/stacks-jpt52csy.js";
13
22
  import {
23
+ getBalance,
24
+ getDataVar,
14
25
  multicall
15
- } from "../../shared/stacks-2evvn48s.js";
16
- import"../../shared/stacks-fb75yew8.js";
26
+ } from "../../shared/stacks-8pfdscq6.js";
27
+ import {
28
+ getMapEntry
29
+ } from "../../shared/stacks-fb75yew8.js";
17
30
  import"../../shared/stacks-27fmgajb.js";
18
31
  import"../../shared/stacks-709tra19.js";
19
32
  import"../../shared/stacks-4z72akdf.js";
@@ -24,6 +37,7 @@ import"../../shared/stacks-hnqt5rz4.js";
24
37
  import"../../shared/stacks-w23294am.js";
25
38
  import {
26
39
  Cl,
40
+ deserializeCVBytes,
27
41
  serializeCVBytes
28
42
  } from "../../shared/stacks-ttdk2g2f.js";
29
43
  import"../../shared/stacks-bfan7ex7.js";
@@ -277,154 +291,6 @@ function describePox5Error(code) {
277
291
  return;
278
292
  return { code: n, name, description: POX5_ERROR_DESCRIPTIONS[n] };
279
293
  }
280
- // src/pox5/cycles.ts
281
- function burnHeightToRewardCycle(burnHeight, params) {
282
- if (burnHeight < params.firstBurnchainBlockHeight) {
283
- throw new Error(`burnHeight ${burnHeight} precedes first burnchain block ${params.firstBurnchainBlockHeight}`);
284
- }
285
- return Math.floor((burnHeight - params.firstBurnchainBlockHeight) / params.rewardCycleLength);
286
- }
287
- function rewardCycleToBurnHeight(cycle, params) {
288
- return params.firstBurnchainBlockHeight + cycle * params.rewardCycleLength;
289
- }
290
- function bondPeriodToRewardCycle(bondIndex, params) {
291
- return params.firstBondPeriodCycle + bondIndex * BOND_GAP_CYCLES;
292
- }
293
- function bondPeriodToBurnHeight(bondIndex, params) {
294
- return rewardCycleToBurnHeight(bondPeriodToRewardCycle(bondIndex, params), params);
295
- }
296
- function bondUnlockCycle(bondIndex, params) {
297
- return bondPeriodToRewardCycle(bondIndex, params) + BOND_LENGTH_CYCLES;
298
- }
299
- function burnHeightToDistributionIndex(burnHeight, params) {
300
- return Math.floor((burnHeight - params.firstBurnchainBlockHeight) / Math.floor(params.rewardCycleLength / 2));
301
- }
302
- function isInPreparePhase(burnHeight, params) {
303
- const offset = (burnHeight - params.firstBurnchainBlockHeight) % params.rewardCycleLength;
304
- return offset >= params.rewardCycleLength - params.prepareCycleLength;
305
- }
306
- function bondPhaseAtHeight(bondIndex, burnHeight, params) {
307
- const cycle = burnHeightToRewardCycle(burnHeight, params);
308
- const start = bondPeriodToRewardCycle(bondIndex, params);
309
- const unlock = bondUnlockCycle(bondIndex, params);
310
- if (cycle < start - BOND_GAP_CYCLES)
311
- return "too-early";
312
- if (cycle < start)
313
- return "open";
314
- if (cycle < unlock)
315
- return "locked";
316
- return "unlocked";
317
- }
318
- // src/pox5/script.ts
319
- import { sha256 } from "@noble/hashes/sha2.js";
320
- function serializeCScriptNum(n) {
321
- const big = typeof n === "bigint" ? n : BigInt(n);
322
- if (big < 0n)
323
- throw new Error("serializeCScriptNum: negative value");
324
- if (big >= C_SCRIPT_NUM_MAX) {
325
- throw new Error("serializeCScriptNum: n >= 2^39 (contract rejects with ERR_INVALID_UNLOCK_HEIGHT)");
326
- }
327
- if (big === 0n)
328
- return new Uint8Array(0);
329
- const out = [];
330
- let v = big;
331
- while (v > 0n) {
332
- out.push(Number(v & 0xffn));
333
- v >>= 8n;
334
- }
335
- if (out[out.length - 1] & 128)
336
- out.push(0);
337
- return Uint8Array.from(out);
338
- }
339
- function pushScriptBytes(bytes) {
340
- const len = bytes.length;
341
- if (len > 65535)
342
- throw new Error(`pushScriptBytes: payload too large (${len} > 65535)`);
343
- let prefix;
344
- if (len < 76)
345
- prefix = Uint8Array.of(len);
346
- else if (len < 256)
347
- prefix = Uint8Array.of(76, len);
348
- else
349
- prefix = Uint8Array.of(77, len & 255, len >> 8);
350
- return concatBytes(prefix, bytes);
351
- }
352
- function pushCScriptNum(n) {
353
- const big = typeof n === "bigint" ? n : BigInt(n);
354
- if (big === 0n)
355
- return Uint8Array.of(0);
356
- if (big >= 1n && big <= 16n)
357
- return Uint8Array.of(80 + Number(big));
358
- return pushScriptBytes(serializeCScriptNum(big));
359
- }
360
- function stakerConsensusBuff(stxAddress) {
361
- return serializeCVBytes(Cl.principal(stxAddress));
362
- }
363
- function stakerPreimage(stxAddress) {
364
- return sha256(stakerConsensusBuff(stxAddress));
365
- }
366
- function toBytes(input) {
367
- return typeof input === "string" ? hexToBytes(input) : input;
368
- }
369
- function buildLockupScript(opts) {
370
- const height = BigInt(opts.unlockBurnHeight);
371
- if (height >= BITCOIN_LOCKTIME_THRESHOLD) {
372
- throw new Error("unlockBurnHeight >= 500,000,000 would be read by Bitcoin as a timestamp (contract rejects it)");
373
- }
374
- const stakerHash = sha256(stakerPreimage(opts.stxAddress));
375
- return concatBytes(Uint8Array.of(99), pushCScriptNum(height), Uint8Array.of(177, 103), hexToBytes("82012088a820"), stakerHash, Uint8Array.of(136), toBytes(opts.earlyUnlockBytes), Uint8Array.of(104, 105), toBytes(opts.stakerUnlockBytes));
376
- }
377
- function buildLockupOutputScript(opts) {
378
- return concatBytes(Uint8Array.of(0, 32), sha256(buildLockupScript(opts)));
379
- }
380
- function buildLockupAddress(opts, network = "mainnet") {
381
- const hash = sha256(buildLockupScript(opts));
382
- return bech32.encode(BITCOIN_NETWORK_PARAMS[network].hrp, [
383
- 0,
384
- ...bech32.toWords(hash)
385
- ]);
386
- }
387
- function buildDefaultStakerUnlockBytes(publicKey) {
388
- const pubkey = toBytes(publicKey);
389
- if (pubkey.length !== 33)
390
- throw new Error(`Expected 33-byte compressed pubkey, got ${pubkey.length}`);
391
- return concatBytes(pushScriptBytes(pubkey), Uint8Array.of(172));
392
- }
393
- // src/pox5/grants.ts
394
- import { secp256k1 } from "@noble/curves/secp256k1.js";
395
- function computeSignerGrantHash(opts) {
396
- return structuredDataHash({
397
- domain: Cl.tuple({
398
- name: Cl.stringAscii(POX5_SIGNER_DOMAIN.name),
399
- version: Cl.stringAscii(POX5_SIGNER_DOMAIN.version),
400
- "chain-id": Cl.uint(opts.chainId)
401
- }),
402
- message: Cl.tuple({
403
- topic: Cl.stringAscii("grant-authorization"),
404
- "signer-manager": Cl.principal(opts.signerManager),
405
- "auth-id": Cl.uint(opts.authId)
406
- })
407
- });
408
- }
409
- async function signSignerGrant(account, opts) {
410
- const vrs = await account.sign(computeSignerGrantHash(opts));
411
- if (vrs.length !== 65)
412
- throw new Error(`Expected 65-byte recoverable signature, got ${vrs.length}`);
413
- return bytesToHex(concatBytes(vrs.slice(1), vrs.slice(0, 1)));
414
- }
415
- function verifySignerGrant(opts) {
416
- try {
417
- const sig = typeof opts.signature === "string" ? hexToBytes(opts.signature) : opts.signature;
418
- if (sig.length !== 65)
419
- return false;
420
- const pubkey = typeof opts.publicKey === "string" ? hexToBytes(opts.publicKey) : opts.publicKey;
421
- const hash = computeSignerGrantHash(opts);
422
- const recovered = secp256k1.Signature.fromBytes(sig.slice(0, 64)).addRecoveryBit(sig[64]).recoverPublicKey(hash).toBytes(true);
423
- return bytesToHex(recovered) === bytesToHex(pubkey);
424
- } catch {
425
- return false;
426
- }
427
- }
428
294
  // src/pox5/abi.ts
429
295
  var POX5_ABI = {
430
296
  functions: [
@@ -537,6 +403,42 @@ var POX5_ABI = {
537
403
  ],
538
404
  outputs: { response: { ok: "bool", error: "uint128" } }
539
405
  },
406
+ {
407
+ name: "get-earned",
408
+ access: "read-only",
409
+ args: [
410
+ { name: "signer", type: "principal" },
411
+ { name: "reward-cycle", type: "uint128" },
412
+ { name: "bond-index", type: { optional: "uint128" } }
413
+ ],
414
+ outputs: "uint128"
415
+ },
416
+ {
417
+ name: "get-earned-staker-rewards",
418
+ access: "read-only",
419
+ args: [
420
+ { name: "signer", type: "principal" },
421
+ { name: "reward-cycle", type: "uint128" },
422
+ { name: "bond-index", type: { optional: "uint128" } },
423
+ { name: "staker", type: "principal" }
424
+ ],
425
+ outputs: "uint128"
426
+ },
427
+ {
428
+ name: "get-last-reward-compute-height",
429
+ access: "read-only",
430
+ args: [],
431
+ outputs: "uint128"
432
+ },
433
+ {
434
+ name: "get-total-shares-staked-for-cycle",
435
+ access: "read-only",
436
+ args: [
437
+ { name: "reward-cycle", type: "uint128" },
438
+ { name: "bond-index", type: { optional: "uint128" } }
439
+ ],
440
+ outputs: "uint128"
441
+ },
540
442
  {
541
443
  name: "announce-l1-early-exit",
542
444
  access: "public",
@@ -990,6 +892,49 @@ var POX5_ABI = {
990
892
  error: "uint128"
991
893
  }
992
894
  }
895
+ },
896
+ {
897
+ name: "set-bond-admin",
898
+ access: "public",
899
+ args: [{ name: "new-admin", type: "principal" }],
900
+ outputs: {
901
+ response: {
902
+ ok: {
903
+ tuple: [
904
+ { name: "new-admin", type: "principal" },
905
+ { name: "old-admin", type: "principal" }
906
+ ]
907
+ },
908
+ error: "uint128"
909
+ }
910
+ }
911
+ },
912
+ {
913
+ name: "set-pause-admin",
914
+ access: "public",
915
+ args: [{ name: "new-admin", type: "principal" }],
916
+ outputs: {
917
+ response: {
918
+ ok: {
919
+ tuple: [
920
+ { name: "new-admin", type: "principal" },
921
+ { name: "old-admin", type: "principal" }
922
+ ]
923
+ },
924
+ error: "uint128"
925
+ }
926
+ }
927
+ },
928
+ {
929
+ name: "pause-rewards",
930
+ access: "public",
931
+ args: [],
932
+ outputs: {
933
+ response: {
934
+ ok: "bool",
935
+ error: "uint128"
936
+ }
937
+ }
993
938
  }
994
939
  ]
995
940
  };
@@ -1005,11 +950,11 @@ function getPox5Contract(client) {
1005
950
  const [address, name] = pox5ContractId(client).split(".");
1006
951
  return getContract({ client, address, name, abi: POX5_ABI });
1007
952
  }
1008
- function toBytes2(input) {
953
+ function toBytes(input) {
1009
954
  return typeof input === "string" ? hexToBytes(input) : input;
1010
955
  }
1011
956
  function optionalBytes(input) {
1012
- return input === undefined ? null : toBytes2(input);
957
+ return input === undefined ? null : toBytes(input);
1013
958
  }
1014
959
  var MAX_LOCKUP_OUTPUTS = 10;
1015
960
  var MAX_LEAF_HASHES = 14;
@@ -1032,16 +977,16 @@ function btcLockupArg(lockup) {
1032
977
  ok: {
1033
978
  outputs: lockup.l1Outputs.map((o) => ({
1034
979
  height: intToBigInt(o.height),
1035
- tx: toBytes2(o.tx),
980
+ tx: toBytes(o.tx),
1036
981
  outputIndex: intToBigInt(o.outputIndex),
1037
- header: toBytes2(o.header),
1038
- leafHashes: o.leafHashes.map(toBytes2),
982
+ header: toBytes(o.header),
983
+ leafHashes: o.leafHashes.map(toBytes),
1039
984
  txCount: intToBigInt(o.txCount),
1040
985
  txIndex: intToBigInt(o.txIndex),
1041
986
  amount: intToBigInt(o.amount),
1042
987
  unlockBurnHeight: intToBigInt(o.unlockBurnHeight)
1043
988
  })),
1044
- stakerUnlockBytes: toBytes2(lockup.stakerUnlockBytes)
989
+ stakerUnlockBytes: toBytes(lockup.stakerUnlockBytes)
1045
990
  }
1046
991
  };
1047
992
  }
@@ -1060,7 +1005,7 @@ function setupBond(client, params) {
1060
1005
  targetRate: intToBigInt(targetRate),
1061
1006
  stxValueRatio: intToBigInt(stxValueRatio),
1062
1007
  minUstxRatio: intToBigInt(minUstxRatio),
1063
- earlyUnlockBytes: toBytes2(earlyUnlockBytes),
1008
+ earlyUnlockBytes: toBytes(earlyUnlockBytes),
1064
1009
  allowlist: allowlist.map((a) => ({
1065
1010
  staker: a.staker,
1066
1011
  maxSats: intToBigInt(a.maxSats)
@@ -1160,15 +1105,26 @@ function claimStakerRewardsForSigner(client, params) {
1160
1105
  function grantSignerKey(client, params) {
1161
1106
  const { signerKey, signerManager, authId, signerSig, ...tx } = params;
1162
1107
  return getPox5Contract(client).call.grantSignerKey({
1163
- signerKey: toBytes2(signerKey),
1108
+ signerKey: toBytes(signerKey),
1164
1109
  signerManager,
1165
1110
  authId: intToBigInt(authId),
1166
- signerSig: toBytes2(signerSig)
1111
+ signerSig: toBytes(signerSig)
1167
1112
  }, tx);
1168
1113
  }
1169
1114
  function revokeSignerGrant(client, params) {
1170
1115
  const { signerManager, signerKey, ...tx } = params;
1171
- return getPox5Contract(client).call.revokeSignerGrant({ signerManager, signerKey: toBytes2(signerKey) }, tx);
1116
+ return getPox5Contract(client).call.revokeSignerGrant({ signerManager, signerKey: toBytes(signerKey) }, tx);
1117
+ }
1118
+ function setBondAdmin(client, params) {
1119
+ const { newAdmin, ...tx } = params;
1120
+ return getPox5Contract(client).call.setBondAdmin({ newAdmin }, tx);
1121
+ }
1122
+ function setPauseAdmin(client, params) {
1123
+ const { newAdmin, ...tx } = params;
1124
+ return getPox5Contract(client).call.setPauseAdmin({ newAdmin }, tx);
1125
+ }
1126
+ function pauseRewards(client, params) {
1127
+ return getPox5Contract(client).call.pauseRewards({}, params ?? {});
1172
1128
  }
1173
1129
  async function getStakerInfo(client, staker) {
1174
1130
  return await getPox5Contract(client).read.getStakerInfo({
@@ -1218,7 +1174,7 @@ async function getSignerInfo(client, signer) {
1218
1174
  function verifySignerKeyGrantOnChain(client, signerManager, signerKey) {
1219
1175
  return getPox5Contract(client).read.verifySignerKeyGrant({
1220
1176
  signerManager,
1221
- signerKey: toBytes2(signerKey)
1177
+ signerKey: toBytes(signerKey)
1222
1178
  });
1223
1179
  }
1224
1180
  function getCurrentRewardCycle(client) {
@@ -1227,49 +1183,806 @@ function getCurrentRewardCycle(client) {
1227
1183
  function getFirstPox5RewardCycle(client) {
1228
1184
  return getPox5Contract(client).read.getFirstPox5RewardCycle({});
1229
1185
  }
1230
- // src/pox5/extension.ts
1231
- async function getStakerState(client, staker) {
1232
- const contract = pox5ContractId(client);
1233
- const results = await multicall(client, {
1234
- allowFailure: false,
1235
- calls: [
1236
- {
1237
- contract,
1238
- functionName: "get-staker-info",
1239
- args: [Cl.principal(staker)]
1240
- },
1241
- {
1242
- contract,
1243
- functionName: "get-bond-membership",
1244
- args: [Cl.principal(staker)]
1245
- },
1246
- {
1247
- contract,
1248
- functionName: "get-staker-custodied-sbtc",
1249
- args: [Cl.principal(staker)]
1250
- },
1251
- { contract, functionName: "current-pox-reward-cycle", args: [] }
1252
- ]
1186
+ function getEarned(client, params) {
1187
+ return getPox5Contract(client).read.getEarned({
1188
+ signer: params.signer,
1189
+ rewardCycle: intToBigInt(params.rewardCycle),
1190
+ bondIndex: params.bondIndex === undefined ? null : intToBigInt(params.bondIndex)
1253
1191
  });
1254
- const [stakerInfo, bondMembership, custodiedSbtc, currentCycle] = results;
1255
- return {
1256
- stakerInfo,
1257
- bondMembership,
1258
- custodiedSbtc,
1259
- currentCycle
1260
- };
1261
1192
  }
1262
- function pox5() {
1263
- return (client) => ({
1264
- pox5: {
1265
- isActive: () => isPox5Active(client),
1266
- getActivation: () => getPox5Activation(client),
1267
- getPoxInfo: () => getPoxInfo(client),
1268
- contractId: () => pox5ContractId(client),
1269
- getStakerState: (staker) => getStakerState(client, staker),
1270
- getStakerInfo: (staker) => getStakerInfo(client, staker),
1271
- getBondMembership: (staker) => getBondMembership(client, staker),
1272
- getProtocolBond: (bondIndex) => getProtocolBond(client, bondIndex),
1193
+ function getEarnedStakerRewards(client, params) {
1194
+ return getPox5Contract(client).read.getEarnedStakerRewards({
1195
+ signer: params.signer,
1196
+ rewardCycle: intToBigInt(params.rewardCycle),
1197
+ bondIndex: params.bondIndex === undefined ? null : intToBigInt(params.bondIndex),
1198
+ staker: params.staker
1199
+ });
1200
+ }
1201
+ function getLastRewardComputeHeight(client) {
1202
+ return getPox5Contract(client).read.getLastRewardComputeHeight({});
1203
+ }
1204
+ function getTotalSharesStakedForCycle(client, rewardCycle, bondIndex) {
1205
+ return getPox5Contract(client).read.getTotalSharesStakedForCycle({
1206
+ rewardCycle: intToBigInt(rewardCycle),
1207
+ bondIndex: bondIndex === undefined ? null : intToBigInt(bondIndex)
1208
+ });
1209
+ }
1210
+
1211
+ // src/pox5/cycles.ts
1212
+ function burnHeightToRewardCycle(burnHeight, params) {
1213
+ if (burnHeight < params.firstBurnchainBlockHeight) {
1214
+ throw new Error(`burnHeight ${burnHeight} precedes first burnchain block ${params.firstBurnchainBlockHeight}`);
1215
+ }
1216
+ return Math.floor((burnHeight - params.firstBurnchainBlockHeight) / params.rewardCycleLength);
1217
+ }
1218
+ function rewardCycleToBurnHeight(cycle, params) {
1219
+ return params.firstBurnchainBlockHeight + cycle * params.rewardCycleLength;
1220
+ }
1221
+ function bondPeriodToRewardCycle(bondIndex, params) {
1222
+ return params.firstBondPeriodCycle + bondIndex * BOND_GAP_CYCLES;
1223
+ }
1224
+ function bondPeriodToBurnHeight(bondIndex, params) {
1225
+ return rewardCycleToBurnHeight(bondPeriodToRewardCycle(bondIndex, params), params);
1226
+ }
1227
+ function bondUnlockCycle(bondIndex, params) {
1228
+ return bondPeriodToRewardCycle(bondIndex, params) + BOND_LENGTH_CYCLES;
1229
+ }
1230
+ function computeBondUnlockHeight(bondIndex, params) {
1231
+ const endCycle = bondPeriodToRewardCycle(bondIndex + BOND_LENGTH_CYCLES / BOND_GAP_CYCLES, params);
1232
+ return rewardCycleToBurnHeight(endCycle, params) - Math.floor(params.rewardCycleLength / 2);
1233
+ }
1234
+ function burnHeightToDistributionIndex(burnHeight, params) {
1235
+ return Math.floor((burnHeight - params.firstBurnchainBlockHeight) / Math.floor(params.rewardCycleLength / 2));
1236
+ }
1237
+ function distributionCycleToBurnHeight(distIndex, params) {
1238
+ return params.firstBurnchainBlockHeight + distIndex * Math.floor(params.rewardCycleLength / 2);
1239
+ }
1240
+ function currentDistributionCycle(burnHeight, params) {
1241
+ return burnHeightToDistributionIndex(burnHeight, params);
1242
+ }
1243
+ function isInPreparePhase(burnHeight, params) {
1244
+ const offset = (burnHeight - params.firstBurnchainBlockHeight) % params.rewardCycleLength;
1245
+ return offset >= params.rewardCycleLength - params.prepareCycleLength;
1246
+ }
1247
+ function bondPhaseAtHeight(bondIndex, burnHeight, params) {
1248
+ const cycle = burnHeightToRewardCycle(burnHeight, params);
1249
+ const start = bondPeriodToRewardCycle(bondIndex, params);
1250
+ const unlock = bondUnlockCycle(bondIndex, params);
1251
+ if (cycle < start - BOND_GAP_CYCLES)
1252
+ return "too-early";
1253
+ if (cycle < start)
1254
+ return "open";
1255
+ if (cycle < unlock)
1256
+ return "locked";
1257
+ return "unlocked";
1258
+ }
1259
+ function bondStatusAtHeight(bondIndex, burnHeight, params) {
1260
+ const cycle = burnHeightToRewardCycle(burnHeight, params);
1261
+ const start = bondPeriodToRewardCycle(bondIndex, params);
1262
+ const unlock = bondUnlockCycle(bondIndex, params);
1263
+ if (cycle < start - BOND_GAP_CYCLES)
1264
+ return "too-early";
1265
+ if (cycle < start) {
1266
+ if (cycle === start - 1 && isInPreparePhase(burnHeight, params)) {
1267
+ return "locked";
1268
+ }
1269
+ return "open";
1270
+ }
1271
+ if (cycle < unlock)
1272
+ return "locked";
1273
+ return "unlocked";
1274
+ }
1275
+
1276
+ // src/pox5/eligibility.ts
1277
+ function finish(reasons) {
1278
+ const unique = [];
1279
+ const seen = new Set;
1280
+ for (const code of reasons) {
1281
+ if (!seen.has(code)) {
1282
+ seen.add(code);
1283
+ unique.push(code);
1284
+ }
1285
+ }
1286
+ if (unique.length === 0)
1287
+ return { ok: true };
1288
+ return { ok: false, reasons: unique };
1289
+ }
1290
+ function toBytes2(input) {
1291
+ return typeof input === "string" ? hexToBytes(input) : input;
1292
+ }
1293
+ function outpointKey(tx, outputIndex) {
1294
+ const hex = typeof tx === "string" ? tx.toLowerCase() : bytesToHex(tx);
1295
+ return `${hex}:${intToBigInt(outputIndex)}`;
1296
+ }
1297
+ async function readCycleClock(client) {
1298
+ const info = await getPoxInfo(client);
1299
+ const burnHeight = info.currentBurnchainBlockHeight;
1300
+ const first = info.firstBurnchainBlockHeight;
1301
+ const raw = await client.request("/v2/pox", { method: "GET" });
1302
+ const pox5 = info.contractVersions.find((v) => v.contractId.endsWith(`.${POX5_CONTRACT_NAME}`));
1303
+ if (typeof burnHeight !== "number" || typeof first !== "number" || typeof raw.reward_cycle_length !== "number" || typeof raw.prepare_cycle_length !== "number" || pox5 == null) {
1304
+ return;
1305
+ }
1306
+ return {
1307
+ burnHeight,
1308
+ params: {
1309
+ firstBurnchainBlockHeight: first,
1310
+ rewardCycleLength: raw.reward_cycle_length,
1311
+ prepareCycleLength: raw.prepare_cycle_length
1312
+ },
1313
+ firstBondPeriodCycle: pox5.firstRewardCycleId
1314
+ };
1315
+ }
1316
+ function inPrepare(clock) {
1317
+ if (!clock)
1318
+ return true;
1319
+ return isInPreparePhase(clock.burnHeight, clock.params);
1320
+ }
1321
+ async function signerReasons(client, signerManager) {
1322
+ const info = await getSignerInfo(client, signerManager);
1323
+ if (info == null)
1324
+ return [Pox5ErrorCode.SignerNotFound];
1325
+ try {
1326
+ const granted = await verifySignerKeyGrantOnChain(client, signerManager, info);
1327
+ if (!granted)
1328
+ return [Pox5ErrorCode.SignerKeyGrantNotFound];
1329
+ } catch {
1330
+ return [Pox5ErrorCode.SignerKeyGrantNotFound];
1331
+ }
1332
+ return [];
1333
+ }
1334
+ function bondOverlaps(membership, newFirstCycle, clock) {
1335
+ if (!membership)
1336
+ return false;
1337
+ const start = bondPeriodToRewardCycle(Number(membership.bondIndex), {
1338
+ ...clock.params,
1339
+ firstBondPeriodCycle: clock.firstBondPeriodCycle
1340
+ });
1341
+ return start + BOND_LENGTH_CYCLES > newFirstCycle;
1342
+ }
1343
+ async function stxFloor(client, staker, amountUstx) {
1344
+ const balance = await getBalance(client, { address: staker });
1345
+ if (balance < amountUstx)
1346
+ return Pox5ErrorCode.InsufficientStx;
1347
+ return;
1348
+ }
1349
+ function principalValue(cv) {
1350
+ if (cv.type === "address" || cv.type === "contract")
1351
+ return cv.value;
1352
+ return;
1353
+ }
1354
+ function minUstxForSats(sats, stxValueRatio, minUstxRatio) {
1355
+ return stxValueRatio * sats / 100n * minUstxRatio / 10000n;
1356
+ }
1357
+ async function eligibleStake(client, params) {
1358
+ const reasons = [];
1359
+ const amountUstx = intToBigInt(params.amountUstx);
1360
+ const numCycles = intToBigInt(params.numCycles);
1361
+ const startBurnHeight = intToBigInt(params.startBurnHeight);
1362
+ const [clock, stakerInfo, membership, signerErrs, floor] = await Promise.all([
1363
+ readCycleClock(client),
1364
+ getStakerInfo(client, params.staker),
1365
+ getBondMembership(client, params.staker),
1366
+ signerReasons(client, params.signerManager),
1367
+ stxFloor(client, params.staker, amountUstx)
1368
+ ]);
1369
+ if (inPrepare(clock))
1370
+ reasons.push(Pox5ErrorCode.StakeInPreparePhase);
1371
+ reasons.push(...signerErrs);
1372
+ if (floor !== undefined)
1373
+ reasons.push(floor);
1374
+ if (numCycles < 1n || numCycles > BigInt(MAX_NUM_CYCLES)) {
1375
+ reasons.push(Pox5ErrorCode.InvalidNumCycles);
1376
+ }
1377
+ if (clock) {
1378
+ const currentCycle = burnHeightToRewardCycle(clock.burnHeight, clock.params);
1379
+ const firstRewardCycle = currentCycle + 1;
1380
+ const specified = burnHeightToRewardCycle(Number(startBurnHeight), clock.params) + 1;
1381
+ if (firstRewardCycle !== specified) {
1382
+ reasons.push(Pox5ErrorCode.InvalidStartBurnHeight);
1383
+ }
1384
+ if (stakerInfo)
1385
+ reasons.push(Pox5ErrorCode.AlreadyStaked);
1386
+ if (bondOverlaps(membership, firstRewardCycle, clock)) {
1387
+ reasons.push(Pox5ErrorCode.AlreadyStaked);
1388
+ }
1389
+ if (membership) {
1390
+ const unlock = await getBondL1UnlockHeight(client, membership.bondIndex);
1391
+ if (BigInt(clock.burnHeight) < unlock) {
1392
+ reasons.push(Pox5ErrorCode.RolloverTooEarly);
1393
+ }
1394
+ }
1395
+ } else if (stakerInfo) {
1396
+ reasons.push(Pox5ErrorCode.AlreadyStaked);
1397
+ }
1398
+ return finish(reasons);
1399
+ }
1400
+ async function eligibleRegisterForBond(client, params) {
1401
+ const reasons = [];
1402
+ const amountUstx = intToBigInt(params.amountUstx);
1403
+ const lockup = params.btcLockup;
1404
+ let sats = 0n;
1405
+ if ("sbtcSats" in lockup) {
1406
+ sats = intToBigInt(lockup.sbtcSats);
1407
+ } else {
1408
+ if (lockup.l1Outputs.length === 0) {
1409
+ reasons.push(Pox5ErrorCode.InvalidLockupAmount);
1410
+ }
1411
+ const seen = new Set;
1412
+ for (const output of lockup.l1Outputs) {
1413
+ sats += intToBigInt(output.amount);
1414
+ const key = outpointKey(output.tx, output.outputIndex);
1415
+ if (seen.has(key))
1416
+ reasons.push(Pox5ErrorCode.DuplicateLockupOutpoint);
1417
+ seen.add(key);
1418
+ }
1419
+ }
1420
+ const [clock, stakerInfo, membership, bond, allowance, signerErrs, floor] = await Promise.all([
1421
+ readCycleClock(client),
1422
+ getStakerInfo(client, params.staker),
1423
+ getBondMembership(client, params.staker),
1424
+ getProtocolBond(client, params.bondIndex),
1425
+ getBondAllowance(client, params.bondIndex, params.staker),
1426
+ signerReasons(client, params.signerManager),
1427
+ stxFloor(client, params.staker, amountUstx)
1428
+ ]);
1429
+ if (inPrepare(clock))
1430
+ reasons.push(Pox5ErrorCode.StakeInPreparePhase);
1431
+ reasons.push(...signerErrs);
1432
+ if (floor !== undefined)
1433
+ reasons.push(floor);
1434
+ if (!bond)
1435
+ reasons.push(Pox5ErrorCode.BondNotFound);
1436
+ if (allowance == null)
1437
+ reasons.push(Pox5ErrorCode.NotAllowlisted);
1438
+ else if (sats > allowance)
1439
+ reasons.push(Pox5ErrorCode.TooMuchSats);
1440
+ if (bond) {
1441
+ const min = minUstxForSats(sats, bond.stxValueRatio, bond.minUstxRatio);
1442
+ if (amountUstx < min)
1443
+ reasons.push(Pox5ErrorCode.InsufficientStx);
1444
+ }
1445
+ if (clock) {
1446
+ const bondStart = bondPeriodToBurnHeight(Number(intToBigInt(params.bondIndex)), {
1447
+ ...clock.params,
1448
+ firstBondPeriodCycle: clock.firstBondPeriodCycle
1449
+ });
1450
+ if (clock.burnHeight >= bondStart) {
1451
+ reasons.push(Pox5ErrorCode.BondAlreadyStarted);
1452
+ }
1453
+ const firstRewardCycle = bondPeriodToRewardCycle(Number(intToBigInt(params.bondIndex)), { ...clock.params, firstBondPeriodCycle: clock.firstBondPeriodCycle });
1454
+ if (stakerInfo) {
1455
+ const unlockCycle = Number(stakerInfo.firstRewardCycle) + Number(stakerInfo.numCycles);
1456
+ if (unlockCycle > firstRewardCycle) {
1457
+ reasons.push(Pox5ErrorCode.AlreadyStaked);
1458
+ }
1459
+ }
1460
+ if (bondOverlaps(membership, firstRewardCycle, clock)) {
1461
+ reasons.push(Pox5ErrorCode.AlreadyRegistered);
1462
+ }
1463
+ if (membership) {
1464
+ const unlock = await getBondL1UnlockHeight(client, membership.bondIndex);
1465
+ if (BigInt(clock.burnHeight) < unlock) {
1466
+ reasons.push(Pox5ErrorCode.RolloverTooEarly);
1467
+ }
1468
+ }
1469
+ }
1470
+ if ("l1Outputs" in lockup && lockup.l1Outputs.length > 0) {
1471
+ const minUnlock = await getBondL1UnlockHeight(client, params.bondIndex);
1472
+ for (const output of lockup.l1Outputs) {
1473
+ const height = intToBigInt(output.unlockBurnHeight);
1474
+ if (height < minUnlock || height >= BITCOIN_LOCKTIME_THRESHOLD) {
1475
+ reasons.push(Pox5ErrorCode.InvalidUnlockHeight);
1476
+ }
1477
+ }
1478
+ }
1479
+ return finish(reasons);
1480
+ }
1481
+ async function eligibleUnstake(client, params) {
1482
+ const reasons = [];
1483
+ const [clock, stakerInfo] = await Promise.all([
1484
+ readCycleClock(client),
1485
+ getStakerInfo(client, params.staker)
1486
+ ]);
1487
+ if (inPrepare(clock))
1488
+ reasons.push(Pox5ErrorCode.UnstakeInPreparePhase);
1489
+ if (!stakerInfo)
1490
+ reasons.push(Pox5ErrorCode.NotStaking);
1491
+ else if (stakerInfo.signer !== params.oldSignerManager) {
1492
+ reasons.push(Pox5ErrorCode.InvalidOldSignerManager);
1493
+ }
1494
+ return finish(reasons);
1495
+ }
1496
+ async function eligibleUnstakeSbtc(client, params) {
1497
+ const reasons = [];
1498
+ const amount = intToBigInt(params.amountSats);
1499
+ const [clock, membership] = await Promise.all([
1500
+ readCycleClock(client),
1501
+ getBondMembership(client, params.staker)
1502
+ ]);
1503
+ if (inPrepare(clock))
1504
+ reasons.push(Pox5ErrorCode.StakeInPreparePhase);
1505
+ if (!membership)
1506
+ reasons.push(Pox5ErrorCode.NotBondParticipant);
1507
+ else {
1508
+ if (membership.signer !== params.signerManager) {
1509
+ reasons.push(Pox5ErrorCode.InvalidOldSignerManager);
1510
+ }
1511
+ if (membership.isL1Lock)
1512
+ reasons.push(Pox5ErrorCode.CannotUnstakeSbtc);
1513
+ if (amount > membership.amountSats) {
1514
+ reasons.push(Pox5ErrorCode.InvalidUnstakeSbtcAmount);
1515
+ }
1516
+ }
1517
+ return finish(reasons);
1518
+ }
1519
+ async function eligibleClaimRewards(client, params) {
1520
+ const reasons = [];
1521
+ const contract = pox5ContractId(client);
1522
+ const paused = await getDataVar(client, {
1523
+ contract,
1524
+ varName: "rewards-paused"
1525
+ });
1526
+ if (paused.type === "true")
1527
+ reasons.push(Pox5ErrorCode.RewardsPaused);
1528
+ const periods = params.bondPeriods ?? [];
1529
+ const earnedParts = await Promise.all([
1530
+ getEarned(client, {
1531
+ signer: params.signer,
1532
+ rewardCycle: params.rewardCycle,
1533
+ bondIndex: params.bondIndex
1534
+ }),
1535
+ ...periods.map((bondIndex) => getEarned(client, {
1536
+ signer: params.signer,
1537
+ rewardCycle: params.rewardCycle,
1538
+ bondIndex
1539
+ }))
1540
+ ]);
1541
+ let total = 0n;
1542
+ for (const part of earnedParts)
1543
+ total += part;
1544
+ if (total === 0n)
1545
+ reasons.push(Pox5ErrorCode.NoClaimableRewards);
1546
+ return finish(reasons);
1547
+ }
1548
+ async function eligibleGrantSignerKey(client, params) {
1549
+ const reasons = [];
1550
+ const used = await getMapEntry(client, {
1551
+ contract: pox5ContractId(client),
1552
+ mapName: "used-signer-key-grants",
1553
+ key: Cl.tuple({
1554
+ "signer-key": Cl.buffer(toBytes2(params.signerKey)),
1555
+ "signer-manager": Cl.principal(params.signerManager),
1556
+ "auth-id": Cl.uint(intToBigInt(params.authId))
1557
+ })
1558
+ });
1559
+ if (used.type === "some")
1560
+ reasons.push(Pox5ErrorCode.SignerKeyGrantUsed);
1561
+ return finish(reasons);
1562
+ }
1563
+ async function eligibleSetBondAdmin(client, params) {
1564
+ const admin = await getDataVar(client, {
1565
+ contract: pox5ContractId(client),
1566
+ varName: "bond-admin"
1567
+ });
1568
+ if (principalValue(admin) !== params.caller) {
1569
+ return finish([Pox5ErrorCode.Unauthorized]);
1570
+ }
1571
+ return { ok: true };
1572
+ }
1573
+ async function eligiblePauseRewards(client, params) {
1574
+ const admin = await getDataVar(client, {
1575
+ contract: pox5ContractId(client),
1576
+ varName: "pause-admin"
1577
+ });
1578
+ if (principalValue(admin) !== params.caller) {
1579
+ return finish([Pox5ErrorCode.Unauthorized]);
1580
+ }
1581
+ return { ok: true };
1582
+ }
1583
+ // src/pox5/script.ts
1584
+ import { sha256 } from "@noble/hashes/sha2.js";
1585
+ function serializeCScriptNum(n) {
1586
+ const big = typeof n === "bigint" ? n : BigInt(n);
1587
+ if (big < 0n)
1588
+ throw new Error("serializeCScriptNum: negative value");
1589
+ if (big >= C_SCRIPT_NUM_MAX) {
1590
+ throw new Error("serializeCScriptNum: n >= 2^39 (contract rejects with ERR_INVALID_UNLOCK_HEIGHT)");
1591
+ }
1592
+ if (big === 0n)
1593
+ return new Uint8Array(0);
1594
+ const out = [];
1595
+ let v = big;
1596
+ while (v > 0n) {
1597
+ out.push(Number(v & 0xffn));
1598
+ v >>= 8n;
1599
+ }
1600
+ if (out[out.length - 1] & 128)
1601
+ out.push(0);
1602
+ return Uint8Array.from(out);
1603
+ }
1604
+ function pushScriptBytes(bytes) {
1605
+ const len = bytes.length;
1606
+ if (len > 65535)
1607
+ throw new Error(`pushScriptBytes: payload too large (${len} > 65535)`);
1608
+ let prefix;
1609
+ if (len < 76)
1610
+ prefix = Uint8Array.of(len);
1611
+ else if (len < 256)
1612
+ prefix = Uint8Array.of(76, len);
1613
+ else
1614
+ prefix = Uint8Array.of(77, len & 255, len >> 8);
1615
+ return concatBytes(prefix, bytes);
1616
+ }
1617
+ function pushCScriptNum(n) {
1618
+ const big = typeof n === "bigint" ? n : BigInt(n);
1619
+ if (big === 0n)
1620
+ return Uint8Array.of(0);
1621
+ if (big >= 1n && big <= 16n)
1622
+ return Uint8Array.of(80 + Number(big));
1623
+ return pushScriptBytes(serializeCScriptNum(big));
1624
+ }
1625
+ function stakerConsensusBuff(stxAddress) {
1626
+ return serializeCVBytes(Cl.principal(stxAddress));
1627
+ }
1628
+ function stakerPreimage(stxAddress) {
1629
+ return sha256(stakerConsensusBuff(stxAddress));
1630
+ }
1631
+ function toBytes3(input) {
1632
+ return typeof input === "string" ? hexToBytes(input) : input;
1633
+ }
1634
+ function buildLockupScript(opts) {
1635
+ const height = BigInt(opts.unlockBurnHeight);
1636
+ if (height <= 0n) {
1637
+ throw new Error("unlockBurnHeight must be > 0 (contract rejects with ERR_INVALID_UNLOCK_HEIGHT)");
1638
+ }
1639
+ if (height >= BITCOIN_LOCKTIME_THRESHOLD) {
1640
+ throw new Error("unlockBurnHeight >= 500,000,000 would be read by Bitcoin as a timestamp (contract rejects it)");
1641
+ }
1642
+ const stakerHash = sha256(stakerPreimage(opts.stxAddress));
1643
+ return concatBytes(Uint8Array.of(99), pushCScriptNum(height), Uint8Array.of(177, 103), hexToBytes("82012088a820"), stakerHash, Uint8Array.of(136), toBytes3(opts.earlyUnlockBytes), Uint8Array.of(104, 105), toBytes3(opts.stakerUnlockBytes));
1644
+ }
1645
+ function buildLockupOutputScript(opts) {
1646
+ return concatBytes(Uint8Array.of(0, 32), sha256(buildLockupScript(opts)));
1647
+ }
1648
+ function buildLockupAddress(opts, network = "mainnet") {
1649
+ const hash = sha256(buildLockupScript(opts));
1650
+ return bech32.encode(BITCOIN_NETWORK_PARAMS[network].hrp, [
1651
+ 0,
1652
+ ...bech32.toWords(hash)
1653
+ ]);
1654
+ }
1655
+ function buildDefaultStakerUnlockBytes(publicKey) {
1656
+ const pubkey = toBytes3(publicKey);
1657
+ if (pubkey.length !== 33)
1658
+ throw new Error(`Expected 33-byte compressed pubkey, got ${pubkey.length}`);
1659
+ const prefix = pubkey[0];
1660
+ if (prefix !== 2 && prefix !== 3) {
1661
+ throw new Error(`Expected compressed pubkey prefix 0x02 or 0x03, got ${prefix}`);
1662
+ }
1663
+ return concatBytes(pushScriptBytes(pubkey), Uint8Array.of(172));
1664
+ }
1665
+ function buildRegisterMetadata(opts) {
1666
+ const unlockHeight = computeBondUnlockHeight(opts.bondIndex, opts.cycle);
1667
+ const unlockBytes = buildDefaultStakerUnlockBytes(opts.bitcoinPublicKey);
1668
+ const lockOpts = {
1669
+ stxAddress: opts.stxAddress,
1670
+ unlockBurnHeight: unlockHeight,
1671
+ stakerUnlockBytes: unlockBytes,
1672
+ earlyUnlockBytes: opts.earlyUnlockBytes
1673
+ };
1674
+ return {
1675
+ lockAddress: buildLockupAddress(lockOpts, opts.network ?? "mainnet"),
1676
+ lockScript: buildLockupScript(lockOpts),
1677
+ outputScript: buildLockupOutputScript(lockOpts),
1678
+ unlockBytes,
1679
+ unlockHeight
1680
+ };
1681
+ }
1682
+ // src/pox5/grants.ts
1683
+ import { secp256k1 } from "@noble/curves/secp256k1.js";
1684
+ function computeSignerGrantHash(opts) {
1685
+ return structuredDataHash({
1686
+ domain: Cl.tuple({
1687
+ name: Cl.stringAscii(POX5_SIGNER_DOMAIN.name),
1688
+ version: Cl.stringAscii(POX5_SIGNER_DOMAIN.version),
1689
+ "chain-id": Cl.uint(opts.chainId)
1690
+ }),
1691
+ message: Cl.tuple({
1692
+ topic: Cl.stringAscii("grant-authorization"),
1693
+ "signer-manager": Cl.principal(opts.signerManager),
1694
+ "auth-id": Cl.uint(opts.authId)
1695
+ })
1696
+ });
1697
+ }
1698
+ async function signSignerGrant(account, opts) {
1699
+ const vrs = await account.sign(computeSignerGrantHash(opts));
1700
+ if (vrs.length !== 65)
1701
+ throw new Error(`Expected 65-byte recoverable signature, got ${vrs.length}`);
1702
+ return bytesToHex(concatBytes(vrs.slice(1), vrs.slice(0, 1)));
1703
+ }
1704
+ function verifySignerGrant(opts) {
1705
+ try {
1706
+ const sig = typeof opts.signature === "string" ? hexToBytes(opts.signature) : opts.signature;
1707
+ if (sig.length !== 65)
1708
+ return false;
1709
+ const pubkey = typeof opts.publicKey === "string" ? hexToBytes(opts.publicKey) : opts.publicKey;
1710
+ const hash = computeSignerGrantHash(opts);
1711
+ const recovered = secp256k1.Signature.fromBytes(sig.slice(0, 64)).addRecoveryBit(sig[64]).recoverPublicKey(hash).toBytes(true);
1712
+ return bytesToHex(recovered) === bytesToHex(pubkey);
1713
+ } catch {
1714
+ return false;
1715
+ }
1716
+ }
1717
+ // src/pox5/lockProof.ts
1718
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1719
+ var MAX_LEAF_HASHES2 = 14;
1720
+ function lockupScriptPubKey(lockScript) {
1721
+ return concatBytes(Uint8Array.of(0, 32), sha2562(lockScript));
1722
+ }
1723
+ function scriptsEqual(a, b) {
1724
+ return bytesToHex(a) === bytesToHex(b);
1725
+ }
1726
+ function spvProofToL1LockupOutput(opts) {
1727
+ const { proof, lockScript, unlockBurnHeight } = opts;
1728
+ const tx = stripWitness(proof.rawTx);
1729
+ const parsed = parseBitcoinTx(proof.rawTx);
1730
+ const expected = lockupScriptPubKey(lockScript);
1731
+ let outputIndex = opts.vout ?? proof.vout;
1732
+ if (outputIndex === undefined) {
1733
+ const matches = [];
1734
+ for (let i = 0;i < parsed.outputs.length; i++) {
1735
+ const spk = parsed.outputs[i]?.scriptPubKey;
1736
+ if (spk && scriptsEqual(spk, expected))
1737
+ matches.push(i);
1738
+ }
1739
+ if (matches.length !== 1) {
1740
+ throw new Error(`spvProofToL1LockupOutput: expected exactly one matching lockup output, found ${matches.length}`);
1741
+ }
1742
+ outputIndex = matches[0];
1743
+ }
1744
+ const output = parsed.outputs[outputIndex];
1745
+ if (!output) {
1746
+ throw new Error(`spvProofToL1LockupOutput: output ${outputIndex} is out of range (${parsed.outputs.length} outputs)`);
1747
+ }
1748
+ if (!scriptsEqual(output.scriptPubKey, expected)) {
1749
+ throw new Error("lockup output script does not match");
1750
+ }
1751
+ const leafHashes = proof.merkle.siblings;
1752
+ if (leafHashes.length > MAX_LEAF_HASHES2) {
1753
+ throw new Error(`spvProofToL1LockupOutput: ${leafHashes.length} merkle siblings; pox-5 accepts at most ${MAX_LEAF_HASHES2}`);
1754
+ }
1755
+ return {
1756
+ height: proof.height,
1757
+ tx,
1758
+ outputIndex,
1759
+ header: proof.header,
1760
+ leafHashes,
1761
+ txCount: proof.merkle.txCount,
1762
+ txIndex: proof.merkle.txIndex,
1763
+ amount: output.value,
1764
+ unlockBurnHeight
1765
+ };
1766
+ }
1767
+ async function buildPox5LockProof(opts) {
1768
+ const proof = await buildTxProof(opts.source, {
1769
+ txid: opts.txid,
1770
+ vout: opts.vout
1771
+ });
1772
+ return spvProofToL1LockupOutput({
1773
+ proof,
1774
+ lockScript: opts.lockScript,
1775
+ unlockBurnHeight: opts.unlockBurnHeight,
1776
+ vout: opts.vout
1777
+ });
1778
+ }
1779
+ // src/pox5/reclaim.ts
1780
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1781
+ import * as btc from "@scure/btc-signer";
1782
+ import { signECDSA } from "@scure/btc-signer/utils.js";
1783
+ var SIGHASH_ALL = 1;
1784
+ var DUST_LIMIT_SATS = 546n;
1785
+ var ELSE_SELECTOR = new Uint8Array(0);
1786
+ var IF_SELECTOR = new Uint8Array([1]);
1787
+ var TX_OPTS = {
1788
+ allowUnknownOutputs: true,
1789
+ disableScriptCheck: true,
1790
+ allowUnknownInputs: true
1791
+ };
1792
+ var REGTEST_NETWORK = { ...btc.TEST_NETWORK, bech32: "bcrt" };
1793
+ function btcNetworkFrom(network) {
1794
+ if (network === "mainnet")
1795
+ return btc.NETWORK;
1796
+ if (network === "testnet")
1797
+ return btc.TEST_NETWORK;
1798
+ return REGTEST_NETWORK;
1799
+ }
1800
+ function toBytes4(value) {
1801
+ return typeof value === "string" ? hexToBytes(value) : value;
1802
+ }
1803
+ function toPrivBytes(value) {
1804
+ return toBytes4(value).slice(0, 32);
1805
+ }
1806
+ function bytesEqual(a, b) {
1807
+ return bytesToHex(a) === bytesToHex(b);
1808
+ }
1809
+ function scriptToWshOutput(lockScript) {
1810
+ return concatBytes(Uint8Array.of(0, 32), sha2563(lockScript));
1811
+ }
1812
+ var SCAFFOLD_PREFIX_LEN = 10;
1813
+ function decodeLockScript(script) {
1814
+ const ops = btc.Script.decode(script);
1815
+ const endifIdx = ops.reduce((found, op, i) => op === "ENDIF" && ops[i + 1] === "VERIFY" ? i : found, -1);
1816
+ const hashOp = ops[8];
1817
+ const shapeOk = endifIdx >= SCAFFOLD_PREFIX_LEN && ops[0] === "IF" && ops[2] === "CHECKLOCKTIMEVERIFY" && ops[3] === "ELSE" && ops[4] === "SIZE" && ops[6] === "EQUALVERIFY" && ops[7] === "SHA256" && hashOp instanceof Uint8Array && hashOp.length === 32 && ops[9] === "EQUALVERIFY";
1818
+ if (!shapeOk) {
1819
+ throw new Error("reclaim: lockScript is not a pox-5 lockup script (expected the OP_IF/OP_ELSE … OP_ENDIF OP_VERIFY scaffold)");
1820
+ }
1821
+ const keysIn = (slice) => slice.filter((op) => op instanceof Uint8Array && op.length === 33);
1822
+ const heightOp = ops[1];
1823
+ const unlockHeight = typeof heightOp === "number" ? heightOp : heightOp instanceof Uint8Array ? Number(btc.ScriptNum().decode(heightOp)) : undefined;
1824
+ return {
1825
+ cosignerPubs: keysIn(ops.slice(SCAFFOLD_PREFIX_LEN, endifIdx)),
1826
+ stakerPubs: keysIn(ops.slice(endifIdx + 2)),
1827
+ unlockHeight
1828
+ };
1829
+ }
1830
+ function buildReclaim(opts) {
1831
+ const network = btcNetworkFrom(opts.network);
1832
+ const lockScript = toBytes4(opts.lockScript);
1833
+ const { unlockHeight: scriptHeight } = decodeLockScript(lockScript);
1834
+ const amount = intToBigInt(opts.utxo.value);
1835
+ const { address } = opts.output;
1836
+ const feeSats = intToBigInt(opts.output.feeSats);
1837
+ if (feeSats < 0n) {
1838
+ throw new Error(`buildReclaim: feeSats (${feeSats}) must be non-negative`);
1839
+ }
1840
+ const outputScript = scriptToWshOutput(lockScript);
1841
+ if (opts.utxo.scriptPubKey && !bytesEqual(opts.utxo.scriptPubKey, outputScript)) {
1842
+ throw new Error("buildReclaim: utxo.scriptPubKey does not match the lockScript — the signature would commit to the wrong output and every reclaim attempt would fail at relay");
1843
+ }
1844
+ const sweepSats = amount - feeSats;
1845
+ if (sweepSats <= 0n) {
1846
+ throw new Error(`buildReclaim: fee (${feeSats}) >= utxo value (${amount})`);
1847
+ }
1848
+ if (sweepSats < DUST_LIMIT_SATS) {
1849
+ throw new Error(`buildReclaim: sweep of ${sweepSats} sats is below the ${DUST_LIMIT_SATS}-sat dust limit — nodes would not relay the tx`);
1850
+ }
1851
+ const earlyExit = opts.path === "early-exit";
1852
+ if (!earlyExit && scriptHeight == null) {
1853
+ throw new Error("buildReclaim: the locktime path needs a lockScript that encodes a CLTV unlock height");
1854
+ }
1855
+ const lockTime = earlyExit ? 0 : scriptHeight;
1856
+ const tx = new btc.Transaction({ ...TX_OPTS, lockTime });
1857
+ tx.addInput({
1858
+ txid: opts.utxo.txid,
1859
+ index: opts.utxo.vout,
1860
+ sequence: earlyExit ? 4294967295 : 4294967294,
1861
+ witnessUtxo: { script: outputScript, amount },
1862
+ witnessScript: lockScript
1863
+ });
1864
+ tx.addOutputAddress(address, sweepSats, network);
1865
+ return tx;
1866
+ }
1867
+ function computeReclaimSighash(tx, opts) {
1868
+ const input = tx.getInput(0);
1869
+ const witnessScript = opts?.witnessScript != null ? toBytes4(opts.witnessScript) : input.witnessScript;
1870
+ const amount = opts?.amountSats != null ? intToBigInt(opts.amountSats) : input.witnessUtxo?.amount;
1871
+ if (!witnessScript || amount == null) {
1872
+ throw new Error("computeReclaimSighash: need witnessScript + amount (pass `opts` for a raw-hex tx)");
1873
+ }
1874
+ return tx.preimageWitnessV0(0, witnessScript, SIGHASH_ALL, amount);
1875
+ }
1876
+ function signReclaim(sighash, privateKey, opts) {
1877
+ const priv = toPrivBytes(privateKey);
1878
+ return concatBytes(signECDSA(sighash, priv, opts?.lowR ?? false), Uint8Array.of(SIGHASH_ALL));
1879
+ }
1880
+ function finalizeReclaim(opts) {
1881
+ const { tx } = opts;
1882
+ const witnessScript = tx.getInput(0).witnessScript;
1883
+ if (!witnessScript)
1884
+ throw new Error("finalizeReclaim: input 0 has no witnessScript");
1885
+ tx.updateInput(0, { finalScriptWitness: reclaimWitness(opts, witnessScript) }, true);
1886
+ if (!tx.isFinal)
1887
+ throw new Error("finalizeReclaim: witness injection failed (tx not final)");
1888
+ return { txHex: tx.hex, txid: tx.id };
1889
+ }
1890
+ function reclaimWitness(opts, witnessScript) {
1891
+ const sigs = opts.tx.getInput(0).partialSig ?? [];
1892
+ const { stakerPubs, cosignerPubs } = decodeLockScript(witnessScript);
1893
+ if (stakerPubs.length !== 1) {
1894
+ throw new Error(`finalizeReclaim: expected exactly one staker public key in the lockup script, found ${stakerPubs.length} — multi-key subscripts are not supported`);
1895
+ }
1896
+ const stakerPub = stakerPubs[0];
1897
+ if (!stakerPub) {
1898
+ throw new Error("finalizeReclaim: expected exactly one staker public key in the lockup script, found 0 — multi-key subscripts are not supported");
1899
+ }
1900
+ const sigFor = (pub) => sigs.find(([p]) => p !== undefined && bytesEqual(p, pub))?.[1];
1901
+ const stakerSig = sigFor(stakerPub);
1902
+ if (!stakerSig)
1903
+ throw new Error("finalizeReclaim: missing staker signature (partialSig)");
1904
+ if (opts.path === "locktime")
1905
+ return [stakerSig, IF_SELECTOR, witnessScript];
1906
+ if (cosignerPubs.length !== 1) {
1907
+ throw new Error(`finalizeReclaim: expected exactly one cosigner public key in the lockup script, found ${cosignerPubs.length} — multi-key subscripts are not supported`);
1908
+ }
1909
+ const cosignerPub = cosignerPubs[0];
1910
+ if (!cosignerPub) {
1911
+ throw new Error("finalizeReclaim: expected exactly one cosigner public key in the lockup script, found 0 — multi-key subscripts are not supported");
1912
+ }
1913
+ const cosignerSig = sigFor(cosignerPub);
1914
+ if (!cosignerSig)
1915
+ throw new Error("finalizeReclaim: missing cosigner signature (partialSig)");
1916
+ return [
1917
+ stakerSig,
1918
+ cosignerSig,
1919
+ stakerPreimage(opts.stxAddress),
1920
+ ELSE_SELECTOR,
1921
+ witnessScript
1922
+ ];
1923
+ }
1924
+ function reclaim(opts) {
1925
+ const tx = buildReclaim(opts);
1926
+ tx.signIdx(toPrivBytes(opts.stakerPrivateKey), 0);
1927
+ if (opts.path === "early-exit") {
1928
+ if (opts.cosignerPrivateKey == null) {
1929
+ throw new Error('reclaim: cosignerPrivateKey is required for path "early-exit"');
1930
+ }
1931
+ if (opts.stxAddress == null) {
1932
+ throw new Error('reclaim: stxAddress is required for path "early-exit" (preimage)');
1933
+ }
1934
+ tx.signIdx(toPrivBytes(opts.cosignerPrivateKey), 0);
1935
+ return finalizeReclaim({
1936
+ path: "early-exit",
1937
+ tx,
1938
+ stxAddress: opts.stxAddress
1939
+ });
1940
+ }
1941
+ return finalizeReclaim({ path: "locktime", tx });
1942
+ }
1943
+ // src/pox5/extension.ts
1944
+ async function getStakerState(client, staker) {
1945
+ const contract = pox5ContractId(client);
1946
+ const results = await multicall(client, {
1947
+ allowFailure: false,
1948
+ calls: [
1949
+ {
1950
+ contract,
1951
+ functionName: "get-staker-info",
1952
+ args: [Cl.principal(staker)]
1953
+ },
1954
+ {
1955
+ contract,
1956
+ functionName: "get-bond-membership",
1957
+ args: [Cl.principal(staker)]
1958
+ },
1959
+ {
1960
+ contract,
1961
+ functionName: "get-staker-custodied-sbtc",
1962
+ args: [Cl.principal(staker)]
1963
+ },
1964
+ { contract, functionName: "current-pox-reward-cycle", args: [] }
1965
+ ]
1966
+ });
1967
+ const [stakerInfo, bondMembership, custodiedSbtc, currentCycle] = results;
1968
+ return {
1969
+ stakerInfo,
1970
+ bondMembership,
1971
+ custodiedSbtc,
1972
+ currentCycle
1973
+ };
1974
+ }
1975
+ function pox5() {
1976
+ return (client) => ({
1977
+ pox5: {
1978
+ isActive: () => isPox5Active(client),
1979
+ getActivation: () => getPox5Activation(client),
1980
+ getPoxInfo: () => getPoxInfo(client),
1981
+ contractId: () => pox5ContractId(client),
1982
+ getStakerState: (staker) => getStakerState(client, staker),
1983
+ getStakerInfo: (staker) => getStakerInfo(client, staker),
1984
+ getBondMembership: (staker) => getBondMembership(client, staker),
1985
+ getProtocolBond: (bondIndex) => getProtocolBond(client, bondIndex),
1273
1986
  getBondAllowance: (bondIndex, staker) => getBondAllowance(client, bondIndex, staker),
1274
1987
  getTotalSbtcStakedForBond: (bondIndex) => getTotalSbtcStakedForBond(client, bondIndex),
1275
1988
  getStakerCustodiedSbtc: (staker) => getStakerCustodiedSbtc(client, staker),
@@ -1279,6 +1992,18 @@ function pox5() {
1279
1992
  verifySignerKeyGrant: (signerManager, signerKey) => verifySignerKeyGrantOnChain(client, signerManager, signerKey),
1280
1993
  getCurrentRewardCycle: () => getCurrentRewardCycle(client),
1281
1994
  getFirstRewardCycle: () => getFirstPox5RewardCycle(client),
1995
+ getEarned: (params) => getEarned(client, params),
1996
+ getEarnedStakerRewards: (params) => getEarnedStakerRewards(client, params),
1997
+ getLastRewardComputeHeight: () => getLastRewardComputeHeight(client),
1998
+ getTotalSharesStakedForCycle: (rewardCycle, bondIndex) => getTotalSharesStakedForCycle(client, rewardCycle, bondIndex),
1999
+ eligibleStake: (params) => eligibleStake(client, params),
2000
+ eligibleRegisterForBond: (params) => eligibleRegisterForBond(client, params),
2001
+ eligibleUnstake: (params) => eligibleUnstake(client, params),
2002
+ eligibleUnstakeSbtc: (params) => eligibleUnstakeSbtc(client, params),
2003
+ eligibleClaimRewards: (params) => eligibleClaimRewards(client, params),
2004
+ eligibleGrantSignerKey: (params) => eligibleGrantSignerKey(client, params),
2005
+ eligibleSetBondAdmin: (params) => eligibleSetBondAdmin(client, params),
2006
+ eligiblePauseRewards: (params) => eligiblePauseRewards(client, params),
1282
2007
  setupBond: (params) => setupBond(client, params),
1283
2008
  registerForBond: (params) => registerForBond(client, params),
1284
2009
  updateBondRegistration: (params) => updateBondRegistration(client, params),
@@ -1291,35 +2016,237 @@ function pox5() {
1291
2016
  claimRewards: (params) => claimRewards(client, params),
1292
2017
  claimStakerRewardsForSigner: (params) => claimStakerRewardsForSigner(client, params),
1293
2018
  grantSignerKey: (params) => grantSignerKey(client, params),
1294
- revokeSignerGrant: (params) => revokeSignerGrant(client, params)
2019
+ revokeSignerGrant: (params) => revokeSignerGrant(client, params),
2020
+ setBondAdmin: (params) => setBondAdmin(client, params),
2021
+ setPauseAdmin: (params) => setPauseAdmin(client, params),
2022
+ pauseRewards: (params) => pauseRewards(client, params),
2023
+ buildLockProof: (opts) => buildPox5LockProof(opts)
1295
2024
  }
1296
2025
  });
1297
2026
  }
2027
+ // src/pox5/btcAddress.ts
2028
+ var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
2029
+ function base58Decode(str) {
2030
+ let num = 0n;
2031
+ for (const char of str) {
2032
+ const idx = BASE58_ALPHABET.indexOf(char);
2033
+ if (idx === -1)
2034
+ throw new Error(`Invalid base58 character: ${char}`);
2035
+ num = num * 58n + BigInt(idx);
2036
+ }
2037
+ const hex = num.toString(16).padStart(2, "0");
2038
+ const padded = hex.length % 2 ? `0${hex}` : hex;
2039
+ const rawBytes = hexToBytes(padded);
2040
+ let leadingZeros = 0;
2041
+ for (const char of str) {
2042
+ if (char === "1")
2043
+ leadingZeros++;
2044
+ else
2045
+ break;
2046
+ }
2047
+ const result = new Uint8Array(leadingZeros + rawBytes.length);
2048
+ result.set(rawBytes, leadingZeros);
2049
+ return result;
2050
+ }
2051
+ function base58CheckEncode(version, payload) {
2052
+ const data = concatBytes(Uint8Array.of(version), payload);
2053
+ const checksum = doubleSha256(data).slice(0, 4);
2054
+ return base58.encode(concatBytes(data, checksum));
2055
+ }
2056
+ function expectedHashLen(version) {
2057
+ if (!Number.isInteger(version) || version < 0 || version > 6) {
2058
+ throw new Error(`Unknown PoX address version: 0x${version.toString(16)}`);
2059
+ }
2060
+ return version <= 4 ? 20 : 32;
2061
+ }
2062
+ function canonicalizeBtcAddress(repr) {
2063
+ const expected = expectedHashLen(repr.version);
2064
+ const { hashbytes } = repr;
2065
+ if (hashbytes.length === expected)
2066
+ return { version: repr.version, hashbytes };
2067
+ if (expected === 20 && hashbytes.length === 32 && hashbytes.slice(20).every((b) => b === 0)) {
2068
+ return { version: repr.version, hashbytes: hashbytes.slice(0, 20) };
2069
+ }
2070
+ throw new Error(`Invalid hashbytes length for PoX version 0x${repr.version.toString(16)}: ${hashbytes.length}`);
2071
+ }
2072
+ function parseBtcAddress(address) {
2073
+ if (address.startsWith("bc1") || address.startsWith("tb1") || address.startsWith("bcrt1")) {
2074
+ return parseSegwitAddress(address);
2075
+ }
2076
+ return parseLegacyAddress(address);
2077
+ }
2078
+ function parseSegwitAddress(address) {
2079
+ let decoded;
2080
+ try {
2081
+ decoded = bech32.decode(address);
2082
+ } catch {
2083
+ decoded = bech32m.decode(address);
2084
+ }
2085
+ const witnessVersion = decoded.words[0];
2086
+ if (witnessVersion === undefined) {
2087
+ throw new Error("Invalid segwit address: missing witness version");
2088
+ }
2089
+ const data = bech32.fromWords(decoded.words.slice(1));
2090
+ const hashbytes = new Uint8Array(data);
2091
+ let version;
2092
+ if (witnessVersion === 0) {
2093
+ if (hashbytes.length === 20) {
2094
+ version = POX_ADDRESS_VERSION.p2wpkh;
2095
+ } else if (hashbytes.length === 32) {
2096
+ version = POX_ADDRESS_VERSION.p2wsh;
2097
+ } else {
2098
+ throw new Error(`Invalid witness v0 program length: ${hashbytes.length}`);
2099
+ }
2100
+ } else if (witnessVersion === 1) {
2101
+ if (hashbytes.length !== 32) {
2102
+ throw new Error(`Invalid witness v1 program length: ${hashbytes.length}`);
2103
+ }
2104
+ version = POX_ADDRESS_VERSION.p2tr;
2105
+ } else {
2106
+ throw new Error(`Unsupported witness version: ${witnessVersion}`);
2107
+ }
2108
+ return { version, hashbytes };
2109
+ }
2110
+ function parseLegacyAddress(address) {
2111
+ const decoded = base58Decode(address);
2112
+ if (decoded.length !== 25) {
2113
+ throw new Error(`Invalid legacy address length: ${decoded.length}`);
2114
+ }
2115
+ const versionByte = decoded[0];
2116
+ if (versionByte === undefined) {
2117
+ throw new Error("Invalid legacy address: missing version byte");
2118
+ }
2119
+ const hashbytes = decoded.slice(1, 21);
2120
+ let version;
2121
+ if (versionByte === 0 || versionByte === 111) {
2122
+ version = POX_ADDRESS_VERSION.p2pkh;
2123
+ } else if (versionByte === 5 || versionByte === 196) {
2124
+ version = POX_ADDRESS_VERSION.p2sh;
2125
+ } else {
2126
+ throw new Error(`Unknown legacy address version byte: 0x${versionByte.toString(16)}`);
2127
+ }
2128
+ return { version, hashbytes };
2129
+ }
2130
+ function stringifyBtcAddress(repr, network) {
2131
+ const { version, hashbytes } = canonicalizeBtcAddress(repr);
2132
+ const params = BITCOIN_NETWORK_PARAMS[network];
2133
+ switch (version) {
2134
+ case POX_ADDRESS_VERSION.p2pkh:
2135
+ return base58CheckEncode(params.p2pkh, hashbytes);
2136
+ case POX_ADDRESS_VERSION.p2sh:
2137
+ case POX_ADDRESS_VERSION.p2sh_p2wpkh:
2138
+ case POX_ADDRESS_VERSION.p2sh_p2wsh:
2139
+ return base58CheckEncode(params.p2sh, hashbytes);
2140
+ case POX_ADDRESS_VERSION.p2wpkh:
2141
+ case POX_ADDRESS_VERSION.p2wsh:
2142
+ return bech32.encode(params.hrp, [0, ...bech32.toWords(hashbytes)]);
2143
+ case POX_ADDRESS_VERSION.p2tr:
2144
+ return bech32m.encode(params.hrp, [1, ...bech32m.toWords(hashbytes)]);
2145
+ default:
2146
+ throw new Error(`Unknown PoX address version: 0x${version.toString(16)}`);
2147
+ }
2148
+ }
2149
+ var BtcAddress = {
2150
+ parse: parseBtcAddress,
2151
+ stringify: stringifyBtcAddress
2152
+ };
2153
+ // src/pox5/signerCalldata.ts
2154
+ function buildSignerCalldata(opts) {
2155
+ const repr = canonicalizeBtcAddress(typeof opts.poxAddress === "string" ? parseBtcAddress(opts.poxAddress) : opts.poxAddress);
2156
+ return serializeCVBytes(Cl.tuple({
2157
+ "pox-addr": Cl.tuple({
2158
+ version: Cl.buffer(Uint8Array.of(repr.version)),
2159
+ hashbytes: Cl.buffer(repr.hashbytes)
2160
+ }),
2161
+ "max-fee": Cl.uint(opts.maxFeeSats)
2162
+ }));
2163
+ }
2164
+ function parseSignerCalldata(calldata) {
2165
+ const cv = deserializeCVBytes(calldata);
2166
+ if (cv.type !== "tuple") {
2167
+ throw new Error("signer calldata is not a Clarity tuple");
2168
+ }
2169
+ const poxAddr = cv.value["pox-addr"];
2170
+ const maxFee = cv.value["max-fee"];
2171
+ if (!poxAddr || poxAddr.type !== "tuple") {
2172
+ throw new Error("signer calldata missing pox-addr tuple");
2173
+ }
2174
+ if (!maxFee || maxFee.type !== "uint") {
2175
+ throw new Error("signer calldata missing max-fee uint");
2176
+ }
2177
+ const versionCv = poxAddr.value.version;
2178
+ const hashCv = poxAddr.value.hashbytes;
2179
+ if (!versionCv || versionCv.type !== "buffer") {
2180
+ throw new Error("signer calldata pox-addr missing version buffer");
2181
+ }
2182
+ if (!hashCv || hashCv.type !== "buffer") {
2183
+ throw new Error("signer calldata pox-addr missing hashbytes buffer");
2184
+ }
2185
+ const versionBytes = hexToBytes(versionCv.value);
2186
+ if (versionBytes.length !== 1) {
2187
+ throw new Error(`signer calldata version must be buff 1, got ${versionBytes.length}`);
2188
+ }
2189
+ const version = versionBytes[0];
2190
+ if (version === undefined) {
2191
+ throw new Error("signer calldata version buffer is empty");
2192
+ }
2193
+ return {
2194
+ poxAddress: canonicalizeBtcAddress({
2195
+ version,
2196
+ hashbytes: hexToBytes(hashCv.value)
2197
+ }),
2198
+ maxFeeSats: maxFee.value
2199
+ };
2200
+ }
1298
2201
  export {
1299
2202
  verifySignerGrant,
2203
+ stringifyBtcAddress,
1300
2204
  stakerPreimage,
1301
2205
  stakerConsensusBuff,
2206
+ spvProofToL1LockupOutput,
1302
2207
  signSignerGrant,
2208
+ signReclaim,
1303
2209
  serializeCScriptNum,
1304
2210
  rewardCycleToBurnHeight,
2211
+ reclaim,
1305
2212
  pushScriptBytes,
1306
2213
  pushCScriptNum,
1307
2214
  pox5ContractId,
1308
2215
  pox5,
2216
+ parseSignerCalldata,
1309
2217
  parsePox5Error,
2218
+ parseBtcAddress,
1310
2219
  isPox5Active,
1311
2220
  isInPreparePhase,
1312
2221
  getPoxInfo,
1313
2222
  getPox5Activation,
2223
+ finalizeReclaim,
2224
+ eligibleUnstakeSbtc,
2225
+ eligibleUnstake,
2226
+ eligibleStake,
2227
+ eligibleSetBondAdmin,
2228
+ eligibleRegisterForBond,
2229
+ eligiblePauseRewards,
2230
+ eligibleGrantSignerKey,
2231
+ eligibleClaimRewards,
2232
+ distributionCycleToBurnHeight,
1314
2233
  describePox5Error,
2234
+ currentDistributionCycle,
1315
2235
  computeSignerGrantHash,
2236
+ computeReclaimSighash,
2237
+ computeBondUnlockHeight,
1316
2238
  burnHeightToRewardCycle,
1317
2239
  burnHeightToDistributionIndex,
2240
+ buildSignerCalldata,
2241
+ buildRegisterMetadata,
2242
+ buildReclaim,
2243
+ buildPox5LockProof,
1318
2244
  buildLockupScript,
1319
2245
  buildLockupOutputScript,
1320
2246
  buildLockupAddress,
1321
2247
  buildDefaultStakerUnlockBytes,
1322
2248
  bondUnlockCycle,
2249
+ bondStatusAtHeight,
1323
2250
  bondPhaseAtHeight,
1324
2251
  bondPeriodToRewardCycle,
1325
2252
  bondPeriodToBurnHeight,
@@ -1334,10 +2261,11 @@ export {
1334
2261
  POX5_ABI,
1335
2262
  MAX_NUM_CYCLES,
1336
2263
  C_SCRIPT_NUM_MAX,
2264
+ BtcAddress,
1337
2265
  BOND_LENGTH_CYCLES,
1338
2266
  BOND_GAP_CYCLES,
1339
2267
  BITCOIN_LOCKTIME_THRESHOLD
1340
2268
  };
1341
2269
 
1342
- //# debugId=A1DC6FC93AED92D864756E2164756E21
2270
+ //# debugId=8137CB55456126D164756E2164756E21
1343
2271
  //# sourceMappingURL=index.js.map