@argonprotocol/mainchain 1.3.7 → 1.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/browser/index.js CHANGED
@@ -9,14 +9,13 @@ import '@polkadot/types/types/registry';
9
9
  export * from '@polkadot/types/lookup';
10
10
  import { Keyring, HttpProvider, WsProvider, ApiPromise } from '@polkadot/api';
11
11
  export { Keyring } from '@polkadot/api';
12
- import { keyExtractSuri, mnemonicToMiniSecret, ed25519DeriveHard, mnemonicGenerate, cryptoWaitReady } from '@polkadot/util-crypto';
12
+ import { mnemonicGenerate, cryptoWaitReady } from '@polkadot/util-crypto';
13
13
  export { decodeAddress, mnemonicGenerate } from '@polkadot/util-crypto';
14
- import * as BigNumber from 'bignumber.js';
15
- import BigNumber__default from 'bignumber.js';
16
- import { u8aToHex, hexToU8a } from '@polkadot/util';
17
- export { hexToU8a, u8aEq, u8aToHex } from '@polkadot/util';
18
- import { printTable, Table } from 'console-table-printer';
14
+ import * as BigNumber2 from 'bignumber.js';
15
+ import BigNumber2__default from 'bignumber.js';
19
16
  import bs58check from 'bs58check';
17
+ import { hexToU8a, u8aToHex } from '@polkadot/util';
18
+ export { hexToU8a, u8aEq, u8aToHex } from '@polkadot/util';
20
19
  export { GenericAddress, GenericBlock, GenericEvent } from '@polkadot/types/generic';
21
20
  export { BTreeMap, Bool, Bytes, Compact, Enum, Null, Option, Range, Result, Struct, Text, Tuple, U256, U8aFixed, Vec, bool, i128, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
22
21
 
@@ -79,33 +78,11 @@ var WageProtector = class _WageProtector {
79
78
  }
80
79
  };
81
80
 
82
- // src/config.ts
83
- var config = {};
84
- function getEnvVar(key) {
85
- if (typeof process !== "undefined" && process.env) {
86
- return process.env[key];
87
- }
88
- return void 0;
89
- }
90
- function setConfig(newConfig) {
91
- config = { ...config, ...newConfig };
92
- }
93
- function getConfig() {
94
- return {
95
- debug: config.debug ?? getEnvVar("DEBUG") === "true",
96
- keysVersion: config.keysVersion ?? (getEnvVar("KEYS_VERSION") ? parseInt(getEnvVar("KEYS_VERSION")) : void 0),
97
- keySeedOrMnemonic: config.keySeedOrMnemonic ?? getEnvVar("KEYS_MNEMONIC"),
98
- subaccountRange: config.subaccountRange ?? getEnvVar("SUBACCOUNT_RANGE") ?? "0-9"
99
- };
100
- }
101
-
102
81
  // src/TxSubmitter.ts
103
82
  function logExtrinsicResult(result) {
104
- if (getConfig().debug) {
105
- const json = result.status.toJSON();
106
- const status = Object.keys(json)[0];
107
- console.debug('Transaction update: "%s"', status, json[status]);
108
- }
83
+ const json = result.status.toJSON();
84
+ const status = Object.keys(json)[0];
85
+ console.debug('Transaction update: "%s"', status, json[status]);
109
86
  }
110
87
  var TxSubmitter = class {
111
88
  constructor(client, tx, pair) {
@@ -137,7 +114,7 @@ var TxSubmitter = class {
137
114
  const result = new TxResult(this.client, logResults);
138
115
  result.txProgressCallback = options.txProgressCallback;
139
116
  let toHuman = this.tx.toHuman().method;
140
- let txString = [];
117
+ const txString = [];
141
118
  let api = formatCall(toHuman);
142
119
  const args = [];
143
120
  if (api === "proxy.proxy") {
@@ -201,10 +178,8 @@ var TxResult = class {
201
178
  this.finalizedResolve = resolve;
202
179
  this.finalizedReject = reject;
203
180
  });
204
- this.inBlockPromise.catch(() => {
205
- });
206
- this.finalizedPromise.catch(() => {
207
- });
181
+ this.inBlockPromise.catch(() => null);
182
+ this.finalizedPromise.catch(() => null);
208
183
  }
209
184
  onResult(result) {
210
185
  this.status = result.status;
@@ -254,35 +229,17 @@ var TxResult = class {
254
229
  this.finalizedReject(error);
255
230
  }
256
231
  };
257
- var { ROUND_FLOOR } = BigNumber;
232
+ var { ROUND_FLOOR } = BigNumber2;
258
233
  var MICROGONS_PER_ARGON = 1e6;
259
- function miniSecretFromUri(uri, password) {
260
- const { phrase, path } = keyExtractSuri(uri);
261
- let mini = mnemonicToMiniSecret(phrase, password);
262
- for (const j of path) {
263
- if (!j.isHard) throw new Error("ed25519 soft derivation not supported");
264
- mini = ed25519DeriveHard(mini, j.chainCode);
265
- }
266
- return u8aToHex(mini);
267
- }
268
234
  function formatArgons(microgons) {
269
235
  if (microgons === void 0 || microgons === null) return "na";
270
236
  const isNegative = microgons < 0;
271
- let format = BigNumber__default(microgons.toString()).abs().div(MICROGONS_PER_ARGON).toFormat(2, ROUND_FLOOR);
237
+ let format = BigNumber2__default(microgons.toString()).abs().div(MICROGONS_PER_ARGON).toFormat(2, ROUND_FLOOR);
272
238
  if (format.endsWith(".00")) {
273
239
  format = format.slice(0, -3);
274
240
  }
275
241
  return `${isNegative ? "-" : ""}\u20B3${format}`;
276
242
  }
277
- function formatPercent(x) {
278
- if (!x) return "na";
279
- return `${x.times(100).decimalPlaces(3)}%`;
280
- }
281
- function filterUndefined(obj) {
282
- return Object.fromEntries(
283
- Object.entries(obj).filter(([_, value]) => value !== void 0 && value !== null)
284
- );
285
- }
286
243
  async function gettersToObject(obj) {
287
244
  if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
288
245
  const keys = [];
@@ -308,36 +265,6 @@ async function gettersToObject(obj) {
308
265
  }
309
266
  return result;
310
267
  }
311
- function toFixedNumber(value, decimals) {
312
- const factor = new BigNumber__default(10).pow(decimals);
313
- const bn = new BigNumber__default(value);
314
- const int = bn.times(factor).integerValue(BigNumber__default.ROUND_DOWN);
315
- return BigInt(int.toFixed(0));
316
- }
317
- function convertNumberToFixedU128(value) {
318
- return toFixedNumber(value, 18);
319
- }
320
- function convertFixedU128ToBigNumber(fixedU128) {
321
- const decimalFactor = new BigNumber__default(10).pow(new BigNumber__default(18));
322
- const rawValue = new BigNumber__default(fixedU128.toString());
323
- return rawValue.div(decimalFactor);
324
- }
325
- function convertPermillToBigNumber(permill) {
326
- const decimalFactor = new BigNumber__default(1e6);
327
- const rawValue = new BigNumber__default(permill.toString());
328
- return rawValue.div(decimalFactor);
329
- }
330
- function convertNumberToPermill(value) {
331
- return toFixedNumber(value, 6);
332
- }
333
- function eventDataToJson(event) {
334
- const obj = {};
335
- event.data.forEach((data, index) => {
336
- const name = event.data.names?.[index];
337
- obj[name ?? `${index}`] = data.toJSON();
338
- });
339
- return obj;
340
- }
341
268
  function dispatchErrorToString(client, error) {
342
269
  let message = error.toString();
343
270
  if (error.isModule) {
@@ -386,79 +313,18 @@ function checkForExtrinsicSuccess(events, client) {
386
313
  }
387
314
  });
388
315
  }
389
- var JsonExt = class {
390
- static stringify(obj, space) {
391
- return JSON.stringify(
392
- obj,
393
- (_, v) => {
394
- if (typeof v === "bigint") {
395
- return `${v}n`;
396
- }
397
- if (v instanceof Uint8Array) {
398
- return {
399
- type: "Buffer",
400
- data: Array.from(v)
401
- // Convert Uint8Array to an array of numbers
402
- };
403
- }
404
- return v;
405
- },
406
- space
407
- );
408
- }
409
- static parse(str) {
410
- return JSON.parse(str, (_, v) => {
411
- if (typeof v === "string" && v.match(/^-?\d+n$/)) {
412
- return BigInt(v.slice(0, -1));
413
- }
414
- if (typeof v === "object" && v !== null && v.type === "Buffer" && Array.isArray(v.data)) {
415
- return Uint8Array.from(v.data);
416
- }
417
- return v;
418
- });
419
- }
420
- };
421
- function createNanoEvents() {
422
- return new TypedEmitter();
423
- }
424
- var TypedEmitter = class {
425
- constructor() {
426
- __publicField(this, "events", {});
427
- }
428
- emit(event, ...args) {
429
- for (const cb of this.events[event] || []) {
430
- cb(...args);
431
- }
432
- }
433
- on(event, cb) {
434
- var _a;
435
- ((_a = this.events)[event] || (_a[event] = [])).push(cb);
436
- return () => {
437
- this.events[event] = this.events[event]?.filter((i) => cb !== i);
438
- };
439
- }
440
- };
441
316
 
442
- // src/AccountRegistry.ts
443
- var _AccountRegistry = class _AccountRegistry {
444
- constructor(name) {
445
- __publicField(this, "namedAccounts", /* @__PURE__ */ new Map());
446
- __publicField(this, "me", "me");
447
- if (name) {
448
- this.me = name;
449
- }
450
- }
451
- getName(address) {
452
- return this.namedAccounts.get(address);
453
- }
454
- register(address, name) {
455
- this.namedAccounts.set(address, name);
456
- }
457
- };
458
- __publicField(_AccountRegistry, "factory", (name) => new _AccountRegistry(name));
459
- var AccountRegistry = _AccountRegistry;
317
+ // src/keyringUtils.ts
318
+ function keyringFromSuri(suri, cryptoType = "sr25519") {
319
+ return new Keyring({ type: cryptoType }).createFromUri(suri);
320
+ }
321
+ function createKeyringPair(opts) {
322
+ const { cryptoType } = opts;
323
+ const seed = mnemonicGenerate();
324
+ return keyringFromSuri(seed, cryptoType);
325
+ }
460
326
 
461
- // src/BlockWatch.ts
327
+ // src/header.ts
462
328
  function getTickFromHeader(client, header) {
463
329
  for (const x of header.digest.logs) {
464
330
  if (x.isPreRuntime) {
@@ -481,844 +347,7 @@ function getAuthorFromHeader(client, header) {
481
347
  }
482
348
  return void 0;
483
349
  }
484
- var BlockWatch = class {
485
- constructor(mainchain, options = {}) {
486
- this.mainchain = mainchain;
487
- this.options = options;
488
- __publicField(this, "events", createNanoEvents());
489
- __publicField(this, "locksById", {});
490
- __publicField(this, "unsubscribe");
491
- var _a, _b;
492
- (_a = this.options).shouldLog ?? (_a.shouldLog = true);
493
- (_b = this.options).finalizedBlocks ?? (_b.finalizedBlocks = false);
494
- }
495
- stop() {
496
- if (this.unsubscribe) {
497
- this.unsubscribe();
498
- this.unsubscribe = void 0;
499
- }
500
- }
501
- async start() {
502
- await this.watchBlocks();
503
- }
504
- async watchBlocks() {
505
- const client = await this.mainchain;
506
- const onBlock = async (header) => {
507
- try {
508
- await this.processBlock(header);
509
- } catch (e) {
510
- console.error("Error processing block", e);
511
- }
512
- };
513
- if (this.options.finalizedBlocks) {
514
- this.unsubscribe = await client.rpc.chain.subscribeFinalizedHeads(onBlock);
515
- } else {
516
- this.unsubscribe = await client.rpc.chain.subscribeNewHeads(onBlock);
517
- }
518
- }
519
- async processBlock(header) {
520
- const client = await this.mainchain;
521
- if (this.options.shouldLog) {
522
- console.log(`-------------------------------------
523
- BLOCK #${header.number}, ${header.hash.toHuman()}`);
524
- }
525
- const blockHash = header.hash;
526
- const api = await client.at(blockHash);
527
- const isBlockVote = await api.query.blockSeal.isBlockFromVoteSeal();
528
- if (!isBlockVote) {
529
- console.warn("> Compute reactivated!");
530
- }
531
- const events = await api.query.system.events();
532
- const reloadVaults = /* @__PURE__ */ new Set();
533
- let block = void 0;
534
- for (const { event, phase } of events) {
535
- const data = eventDataToJson(event);
536
- if (data.vaultId) {
537
- const vaultId = data.vaultId;
538
- reloadVaults.add(vaultId);
539
- }
540
- let logEvent = false;
541
- if (event.section === "liquidityPools") {
542
- if (client.events.liquidityPools.BidPoolDistributed.is(event)) {
543
- const { bidPoolBurned, bidPoolDistributed } = event.data;
544
- data.burned = formatArgons(bidPoolBurned.toBigInt());
545
- data.distributed = formatArgons(bidPoolDistributed.toBigInt());
546
- logEvent = true;
547
- } else if (client.events.liquidityPools.NextBidPoolCapitalLocked.is(event)) {
548
- const { totalActivatedCapital } = event.data;
549
- data.totalActivatedCapital = formatArgons(totalActivatedCapital.toBigInt());
550
- logEvent = true;
551
- }
552
- } else if (event.section === "bitcoinLocks") {
553
- if (client.events.bitcoinLocks.BitcoinLockCreated.is(event)) {
554
- const { lockPrice, utxoId, accountId, vaultId } = event.data;
555
- this.locksById[utxoId.toNumber()] = {
556
- vaultId: vaultId.toNumber(),
557
- lockPrice: lockPrice.toBigInt()
558
- };
559
- data.lockPrice = formatArgons(lockPrice.toBigInt());
560
- data.accountId = accountId.toHuman();
561
- reloadVaults.add(vaultId.toNumber());
562
- }
563
- logEvent = true;
564
- } else if (event.section === "mint") {
565
- logEvent = true;
566
- if (client.events.mint.MiningMint.is(event)) {
567
- const { amount } = event.data;
568
- data.amount = formatArgons(amount.toBigInt());
569
- }
570
- } else if (event.section === "miningSlot") {
571
- logEvent = true;
572
- if (client.events.miningSlot.SlotBidderAdded.is(event)) {
573
- data.amount = formatArgons(event.data.bidAmount.toBigInt());
574
- this.events.emit("mining-bid", header, {
575
- amount: event.data.bidAmount.toBigInt(),
576
- accountId: event.data.accountId.toString()
577
- });
578
- } else if (client.events.miningSlot.SlotBidderDropped.is(event)) {
579
- this.events.emit("mining-bid-ousted", header, {
580
- accountId: event.data.accountId.toString(),
581
- preservedArgonotHold: event.data.preservedArgonotHold.toPrimitive()
582
- });
583
- }
584
- } else if (event.section === "bitcoinUtxos") {
585
- logEvent = true;
586
- if (client.events.bitcoinUtxos.UtxoVerified.is(event)) {
587
- const { utxoId } = event.data;
588
- const details = await this.getBitcoinLockDetails(utxoId.toNumber(), blockHash);
589
- this.events.emit("bitcoin-verified", header, {
590
- utxoId: utxoId.toNumber(),
591
- vaultId: details.vaultId,
592
- lockPrice: details.lockPrice
593
- });
594
- data.lockPrice = formatArgons(details.lockPrice);
595
- reloadVaults.add(details.vaultId);
596
- }
597
- } else if (event.section === "system") {
598
- if (client.events.system.ExtrinsicFailed.is(event)) {
599
- const { dispatchError } = event.data;
600
- if (dispatchError.isModule) {
601
- const decoded = api.registry.findMetaError(dispatchError.asModule);
602
- const { name, section } = decoded;
603
- block ?? (block = await client.rpc.chain.getBlock(header.hash));
604
- const extrinsicIndex = phase.asApplyExtrinsic.toNumber();
605
- const ext = block.block.extrinsics[extrinsicIndex];
606
- if (this.options.shouldLog) {
607
- console.log(
608
- `> [Failed Tx] ${section}.${name} -> ${ext.method.section}.${ext.method.method} (nonce=${ext.nonce})`,
609
- ext.toHuman()?.method?.args
610
- );
611
- }
612
- } else {
613
- if (this.options.shouldLog) {
614
- console.log(`x [Failed Tx] ${dispatchError.toJSON()}`);
615
- }
616
- }
617
- }
618
- }
619
- if (this.options.shouldLog && logEvent) {
620
- console.log(`> ${event.section}.${event.method}`, data);
621
- }
622
- this.events.emit("event", header, event);
623
- }
624
- if (reloadVaults.size) this.events.emit("vaults-updated", header, reloadVaults);
625
- const tick = getTickFromHeader(client, header);
626
- const author = getAuthorFromHeader(client, header);
627
- this.events.emit(
628
- "block",
629
- header,
630
- { tick, author },
631
- events.map((x) => x.event)
632
- );
633
- }
634
- async getBitcoinLockDetails(utxoId, blockHash) {
635
- const client = await this.mainchain;
636
- const api = await client.at(blockHash);
637
- if (!this.locksById[utxoId]) {
638
- const lock = await api.query.bitcoinLocks.locksByUtxoId(utxoId);
639
- this.locksById[utxoId] = {
640
- vaultId: lock.value.vaultId.toNumber(),
641
- lockPrice: lock.value.lockPrice.toBigInt()
642
- };
643
- }
644
- return this.locksById[utxoId];
645
- }
646
- };
647
-
648
- // src/FrameCalculator.ts
649
- var FrameCalculator = class _FrameCalculator {
650
- constructor() {
651
- __publicField(this, "miningConfig");
652
- __publicField(this, "genesisTick");
653
- __publicField(this, "tickMillis");
654
- }
655
- async load(client) {
656
- return await this.getConfig(client);
657
- }
658
- async getForTick(client, tick) {
659
- const { ticksBetweenFrames, biddingStartTick } = await this.getConfig(client);
660
- const ticksSinceMiningStart = tick - biddingStartTick;
661
- return Math.floor(ticksSinceMiningStart / ticksBetweenFrames);
662
- }
663
- async getTickRangeForFrame(client, frameId) {
664
- const { ticksBetweenFrames, biddingStartTick } = await this.getConfig(client);
665
- return _FrameCalculator.calculateTickRangeForFrame(frameId, {
666
- ticksBetweenFrames,
667
- biddingStartTick
668
- });
669
- }
670
- async getForHeader(client, header) {
671
- if (header.number.toNumber() === 0) return 0;
672
- const tick = getTickFromHeader(client, header);
673
- if (tick === void 0) return void 0;
674
- return this.getForTick(client, tick);
675
- }
676
- static frameToDateRange(frameId, config2) {
677
- const [start, end] = _FrameCalculator.calculateTickRangeForFrame(frameId, config2);
678
- return [new Date(start * config2.tickMillis), new Date(end * config2.tickMillis)];
679
- }
680
- static calculateTickRangeForFrame(frameId, config2) {
681
- const { ticksBetweenFrames, biddingStartTick } = config2;
682
- const startingTick = biddingStartTick + Math.floor(frameId * ticksBetweenFrames);
683
- const endingTick = startingTick + ticksBetweenFrames - 1;
684
- return [startingTick, endingTick];
685
- }
686
- async getConfig(client) {
687
- this.miningConfig ?? (this.miningConfig = await client.query.miningSlot.miningConfig().then((x) => ({
688
- ticksBetweenSlots: x.ticksBetweenSlots.toNumber(),
689
- slotBiddingStartAfterTicks: x.slotBiddingStartAfterTicks.toNumber()
690
- })));
691
- this.genesisTick ?? (this.genesisTick = await client.query.ticks.genesisTick().then((x) => x.toNumber()));
692
- this.tickMillis ?? (this.tickMillis = await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber()));
693
- const config2 = this.miningConfig;
694
- const genesisTick = this.genesisTick;
695
- return {
696
- ticksBetweenFrames: config2.ticksBetweenSlots,
697
- slotBiddingStartAfterTicks: config2.slotBiddingStartAfterTicks,
698
- genesisTick,
699
- tickMillis: this.tickMillis,
700
- biddingStartTick: genesisTick + config2.slotBiddingStartAfterTicks
701
- };
702
- }
703
- };
704
-
705
- // src/AccountMiners.ts
706
- var AccountMiners = class _AccountMiners {
707
- constructor(accountset, registeredMiners, options = { shouldLog: false }) {
708
- this.accountset = accountset;
709
- this.options = options;
710
- __publicField(this, "events", createNanoEvents());
711
- __publicField(this, "frameCalculator");
712
- __publicField(this, "trackedAccountsByAddress", {});
713
- this.frameCalculator = new FrameCalculator();
714
- for (const miner of registeredMiners) {
715
- this.trackedAccountsByAddress[miner.address] = {
716
- startingFrameId: miner.seat.startingFrameId,
717
- subaccountIndex: miner.subaccountIndex
718
- };
719
- }
720
- }
721
- async watch() {
722
- const blockWatch = new BlockWatch(this.accountset.client, {
723
- shouldLog: this.options.shouldLog
724
- });
725
- blockWatch.events.on("block", this.onBlock.bind(this));
726
- await blockWatch.start();
727
- return blockWatch;
728
- }
729
- async onBlock(header, digests, events) {
730
- var _a;
731
- const { author, tick } = digests;
732
- if (author) {
733
- const voteAuthor = this.trackedAccountsByAddress[author];
734
- if (voteAuthor && this.options.shouldLog) {
735
- console.log("> Our vote author", this.accountset.accountRegistry.getName(author));
736
- }
737
- } else {
738
- console.warn("> No vote author found");
739
- }
740
- const client = await this.accountset.client;
741
- const currentFrameId = await this.frameCalculator.getForTick(client, tick);
742
- let newMiners;
743
- const dataByCohort = { duringFrameId: currentFrameId };
744
- for (const event of events) {
745
- if (client.events.miningSlot.NewMiners.is(event)) {
746
- newMiners = {
747
- frameId: event.data.frameId.toNumber(),
748
- addresses: event.data.newMiners.map((x) => x.accountId.toHuman())
749
- };
750
- }
751
- if (client.events.blockRewards.RewardCreated.is(event)) {
752
- const { rewards } = event.data;
753
- for (const reward of rewards) {
754
- const { argons, ownership } = reward;
755
- const entry = this.trackedAccountsByAddress[author];
756
- if (entry) {
757
- dataByCohort[_a = entry.startingFrameId] ?? (dataByCohort[_a] = {
758
- argonsMinted: 0n,
759
- argonsMined: 0n,
760
- argonotsMined: 0n
761
- });
762
- dataByCohort[entry.startingFrameId].argonotsMined += ownership.toBigInt();
763
- dataByCohort[entry.startingFrameId].argonsMined += argons.toBigInt();
764
- this.events.emit("mined", header, {
765
- author,
766
- argons: argons.toBigInt(),
767
- argonots: ownership.toBigInt(),
768
- forCohortWithStartingFrameId: entry.startingFrameId,
769
- duringFrameId: currentFrameId
770
- });
771
- }
772
- }
773
- }
774
- if (client.events.mint.MiningMint.is(event)) {
775
- const { perMiner } = event.data;
776
- const amountPerMiner = perMiner.toBigInt();
777
- if (amountPerMiner > 0n) {
778
- for (const [address, info] of Object.entries(this.trackedAccountsByAddress)) {
779
- const { startingFrameId } = info;
780
- dataByCohort[startingFrameId] ?? (dataByCohort[startingFrameId] = {
781
- argonsMinted: 0n,
782
- argonsMined: 0n,
783
- argonotsMined: 0n
784
- });
785
- dataByCohort[startingFrameId].argonsMinted += amountPerMiner;
786
- this.events.emit("minted", header, {
787
- accountId: address,
788
- argons: amountPerMiner,
789
- forCohortWithStartingFrameId: startingFrameId,
790
- duringFrameId: currentFrameId
791
- });
792
- }
793
- }
794
- }
795
- }
796
- if (newMiners) {
797
- this.newCohortMiners(newMiners.frameId, newMiners.addresses);
798
- }
799
- return dataByCohort;
800
- }
801
- newCohortMiners(frameId, addresses) {
802
- for (const [address, info] of Object.entries(this.trackedAccountsByAddress)) {
803
- if (info.startingFrameId === frameId - 10) {
804
- delete this.trackedAccountsByAddress[address];
805
- }
806
- }
807
- for (const address of addresses) {
808
- const entry = this.accountset.subAccountsByAddress[address];
809
- if (entry) {
810
- this.trackedAccountsByAddress[address] = {
811
- startingFrameId: frameId,
812
- subaccountIndex: entry.index
813
- };
814
- }
815
- }
816
- }
817
- static async loadAt(accountset, options = {}) {
818
- const seats = await accountset.miningSeats(options.blockHash);
819
- const registered = seats.filter((x) => x.seat !== void 0);
820
- return new _AccountMiners(accountset, registered, {
821
- shouldLog: options.shouldLog ?? false
822
- });
823
- }
824
- };
825
- var Accountset = class {
826
- constructor(options) {
827
- __publicField(this, "txSubmitterPair");
828
- __publicField(this, "isProxy", false);
829
- __publicField(this, "seedAddress");
830
- __publicField(this, "subAccountsByAddress", {});
831
- __publicField(this, "accountRegistry");
832
- __publicField(this, "client");
833
- __publicField(this, "sessionKeySeed");
834
- if ("seedAccount" in options) {
835
- this.txSubmitterPair = options.seedAccount;
836
- this.seedAddress = options.seedAccount.address;
837
- this.isProxy = false;
838
- } else {
839
- this.isProxy = options.isProxy;
840
- this.txSubmitterPair = options.txSubmitter;
841
- this.seedAddress = options.seedAddress;
842
- }
843
- this.sessionKeySeed = options.sessionKeySeedOrMnemonic;
844
- this.accountRegistry = options.accountRegistry ?? AccountRegistry.factory(options.name);
845
- this.client = options.client;
846
- const defaultRange = options.subaccountRange ?? getDefaultSubaccountRange();
847
- this.accountRegistry.register(this.seedAddress, `${this.accountRegistry.me}//seed`);
848
- for (const i of defaultRange) {
849
- const pair = this.txSubmitterPair.derive(`//${i}`);
850
- this.subAccountsByAddress[pair.address] = { pair, index: i };
851
- this.accountRegistry.register(pair.address, `${this.accountRegistry.me}//${i}`);
852
- }
853
- }
854
- get addresses() {
855
- return [this.seedAddress, ...Object.keys(this.subAccountsByAddress)];
856
- }
857
- get namedAccounts() {
858
- return this.accountRegistry.namedAccounts;
859
- }
860
- async submitterBalance(blockHash) {
861
- const client = await this.client;
862
- const api = blockHash ? await client.at(blockHash) : client;
863
- const accountData = await api.query.system.account(this.txSubmitterPair.address);
864
- return accountData.data.free.toBigInt();
865
- }
866
- async balance(blockHash) {
867
- const client = await this.client;
868
- const api = blockHash ? await client.at(blockHash) : client;
869
- const accountData = await api.query.system.account(this.seedAddress);
870
- return accountData.data.free.toBigInt();
871
- }
872
- async totalArgonsAt(blockHash) {
873
- const client = await this.client;
874
- const api = blockHash ? await client.at(blockHash) : client;
875
- const addresses = this.addresses;
876
- const results = await api.query.system.account.multi(addresses);
877
- return results.map((account, i) => {
878
- const address = addresses[i];
879
- return {
880
- address,
881
- amount: account.data.free.toBigInt(),
882
- index: this.subAccountsByAddress[address]?.index ?? Number.NaN
883
- };
884
- });
885
- }
886
- async totalArgonotsAt(blockHash) {
887
- const client = await this.client;
888
- const api = blockHash ? await client.at(blockHash) : client;
889
- const addresses = this.addresses;
890
- const results = await api.query.ownership.account.multi(addresses);
891
- return results.map((account, i) => {
892
- const address = addresses[i];
893
- return {
894
- address,
895
- amount: account.free.toBigInt(),
896
- index: this.subAccountsByAddress[address]?.index ?? Number.NaN
897
- };
898
- });
899
- }
900
- async getAvailableMinerAccounts(maxSeats) {
901
- const miningSeats = await this.miningSeats();
902
- const subaccountRange = [];
903
- for (const seat of miningSeats) {
904
- if (seat.hasWinningBid) {
905
- continue;
906
- }
907
- if (seat.isLastDay || seat.seat === void 0) {
908
- subaccountRange.push({
909
- index: seat.subaccountIndex,
910
- isRebid: seat.seat !== void 0,
911
- address: seat.address
912
- });
913
- if (subaccountRange.length >= maxSeats) {
914
- break;
915
- }
916
- }
917
- }
918
- return subaccountRange;
919
- }
920
- async loadRegisteredMiners(api) {
921
- const addresses = Object.keys(this.subAccountsByAddress);
922
- const rawIndices = await api.query.miningSlot.accountIndexLookup.multi(addresses);
923
- const frameIds = [
924
- ...new Set(
925
- rawIndices.map((x) => x.isNone ? void 0 : x.value[0].toNumber()).filter((x) => x !== void 0)
926
- )
927
- ];
928
- const bidAmountsByFrame = {};
929
- if (frameIds.length) {
930
- const cohorts = await api.query.miningSlot.minersByCohort.multi(frameIds);
931
- for (let i = 0; i < frameIds.length; i++) {
932
- const cohort = cohorts[i];
933
- const frameId = frameIds[i];
934
- bidAmountsByFrame[frameId] = cohort.map((x) => x.bid.toBigInt());
935
- }
936
- }
937
- const addressToMiningIndex = {};
938
- for (let i = 0; i < addresses.length; i++) {
939
- const address = addresses[i];
940
- if (rawIndices[i].isNone) continue;
941
- const [frameIdRaw, indexRaw] = rawIndices[i].value;
942
- const frameId = frameIdRaw.toNumber();
943
- const index = indexRaw.toNumber();
944
- const bidAmount = bidAmountsByFrame[frameId]?.[index];
945
- addressToMiningIndex[address] = {
946
- startingFrameId: frameId,
947
- index,
948
- bidAmount: bidAmount ?? 0n
949
- };
950
- }
951
- const nextFrameId = await api.query.miningSlot.nextFrameId();
952
- return addresses.map((address) => {
953
- const cohort = addressToMiningIndex[address];
954
- let isLastDay = false;
955
- if (cohort !== void 0) {
956
- isLastDay = nextFrameId.toNumber() - cohort.startingFrameId === 10;
957
- }
958
- return {
959
- address,
960
- seat: cohort,
961
- isLastDay,
962
- subaccountIndex: this.subAccountsByAddress[address]?.index ?? Number.NaN
963
- };
964
- });
965
- }
966
- async miningSeats(blockHash) {
967
- const client = await this.client;
968
- const api = blockHash ? await client.at(blockHash) : client;
969
- const miners = await this.loadRegisteredMiners(api);
970
- const nextCohort = await api.query.miningSlot.bidsForNextSlotCohort();
971
- return miners.map((miner) => {
972
- const bid = nextCohort.find((x) => x.accountId.toHuman() === miner.address);
973
- return {
974
- ...miner,
975
- hasWinningBid: !!bid,
976
- bidAmount: bid?.bid.toBigInt() ?? miner.seat?.bidAmount ?? 0n
977
- };
978
- });
979
- }
980
- async bids(blockHash) {
981
- const client = await this.client;
982
- const api = blockHash ? await client.at(blockHash) : client;
983
- const addresses = Object.keys(this.subAccountsByAddress);
984
- const nextCohort = await api.query.miningSlot.bidsForNextSlotCohort();
985
- const registrationsByAddress = Object.fromEntries(
986
- nextCohort.map((x, i) => [x.accountId.toHuman(), { ...x, index: i }])
987
- );
988
- return addresses.map((address) => {
989
- const entry = registrationsByAddress[address];
990
- return {
991
- address,
992
- bidPlace: entry?.index,
993
- bidAmount: entry?.bid?.toBigInt(),
994
- index: this.subAccountsByAddress[address]?.index ?? Number.NaN
995
- };
996
- });
997
- }
998
- async consolidate(subaccounts) {
999
- const client = await this.client;
1000
- const accounts = this.getAccountsInRange(subaccounts);
1001
- const results = [];
1002
- await Promise.allSettled(
1003
- accounts.map(({ pair, index }) => {
1004
- if (!pair) {
1005
- results.push({
1006
- index,
1007
- failedError: new Error(`No keypair for //${index}`)
1008
- });
1009
- return Promise.resolve();
1010
- }
1011
- return new Promise((resolve) => {
1012
- client.tx.utility.batchAll([
1013
- client.tx.balances.transferAll(this.seedAddress, true),
1014
- client.tx.ownership.transferAll(this.seedAddress, true)
1015
- ]).signAndSend(pair, (cb) => {
1016
- logExtrinsicResult(cb);
1017
- if (cb.dispatchError) {
1018
- const error = dispatchErrorToString(client, cb.dispatchError);
1019
- results.push({
1020
- index,
1021
- failedError: new Error(`Error consolidating //${index}: ${error}`)
1022
- });
1023
- resolve();
1024
- }
1025
- if (cb.isInBlock) {
1026
- results.push({ index, inBlock: cb.status.asInBlock.toHex() });
1027
- resolve();
1028
- }
1029
- }).catch((e) => {
1030
- results.push({ index, failedError: e });
1031
- resolve();
1032
- });
1033
- });
1034
- })
1035
- );
1036
- return results;
1037
- }
1038
- status(opts) {
1039
- const { argons, argonots, accountSubset, bids, seats } = opts;
1040
- const accounts = [
1041
- {
1042
- index: "main",
1043
- address: this.seedAddress,
1044
- argons: formatArgons(argons.find((x) => x.address === this.seedAddress)?.amount ?? 0n),
1045
- argonots: formatArgons(argonots.find((x) => x.address === this.seedAddress)?.amount ?? 0n)
1046
- }
1047
- ];
1048
- for (const [address, { index }] of Object.entries(this.subAccountsByAddress)) {
1049
- const argonAmount = argons.find((x) => x.address === address)?.amount ?? 0n;
1050
- const argonotAmount = argonots.find((x) => x.address === address)?.amount ?? 0n;
1051
- const bid = bids.find((x) => x.address === address);
1052
- const seat = seats.find((x) => x.address === address)?.seat;
1053
- const entry = {
1054
- index: ` //${index}`,
1055
- address,
1056
- argons: formatArgons(argonAmount),
1057
- argonots: formatArgons(argonotAmount),
1058
- seat,
1059
- bidPlace: bid?.bidPlace,
1060
- bidAmount: bid?.bidAmount ?? 0n
1061
- };
1062
- if (accountSubset) {
1063
- entry.isWorkingOn = accountSubset.some((x) => x.address === address);
1064
- }
1065
- accounts.push(entry);
1066
- }
1067
- return accounts;
1068
- }
1069
- async registerKeys(url) {
1070
- const client = await getClient(url.replace("ws:", "http:"));
1071
- const keys = this.keys();
1072
- for (const [name, key] of Object.entries(keys)) {
1073
- console.log("Registering key", name, key.publicKey);
1074
- const result = await client.rpc.author.insertKey(name, key.privateKey, key.publicKey);
1075
- const saved = await client.rpc.author.hasKey(key.publicKey, name);
1076
- if (!saved) {
1077
- console.error("Failed to register key", name, key.publicKey);
1078
- throw new Error(`Failed to register ${name} key ${key.publicKey}`);
1079
- }
1080
- console.log(`Registered ${name} key`, result.toHuman());
1081
- }
1082
- await client.disconnect();
1083
- }
1084
- keys(keysVersion) {
1085
- const config2 = getConfig();
1086
- let version = keysVersion ?? config2.keysVersion ?? 0;
1087
- const seed = this.sessionKeySeed ?? config2.keySeedOrMnemonic;
1088
- if (!seed) {
1089
- throw new Error("KEYS_MNEMONIC environment variable not set. Cannot derive keys.");
1090
- }
1091
- const blockSealKey = `${seed}//block-seal//${version}`;
1092
- const granKey = `${seed}//grandpa//${version}`;
1093
- const blockSealAccount = new Keyring().createFromUri(blockSealKey, {
1094
- type: "ed25519"
1095
- });
1096
- const grandpaAccount = new Keyring().createFromUri(granKey, {
1097
- type: "ed25519"
1098
- });
1099
- return {
1100
- seal: {
1101
- privateKey: blockSealKey,
1102
- publicKey: u8aToHex(blockSealAccount.publicKey),
1103
- rawPublicKey: blockSealAccount.publicKey
1104
- },
1105
- gran: {
1106
- privateKey: granKey,
1107
- publicKey: u8aToHex(grandpaAccount.publicKey),
1108
- rawPublicKey: grandpaAccount.publicKey
1109
- }
1110
- };
1111
- }
1112
- async tx(tx) {
1113
- const client = await this.client;
1114
- return new TxSubmitter(client, tx, this.txSubmitterPair);
1115
- }
1116
- /**
1117
- * Create but don't submit a mining bid transaction.
1118
- * @param options
1119
- */
1120
- async createMiningBidTx(options) {
1121
- const client = await this.client;
1122
- const { bidAmount, subaccounts } = options;
1123
- const batch = client.tx.utility.batch(
1124
- subaccounts.map((x) => {
1125
- const keys = this.keys();
1126
- return client.tx.miningSlot.bid(
1127
- bidAmount,
1128
- {
1129
- grandpa: keys.gran.rawPublicKey,
1130
- blockSealAuthority: keys.seal.rawPublicKey
1131
- },
1132
- x.address
1133
- );
1134
- })
1135
- );
1136
- let tx = batch;
1137
- if (this.isProxy) {
1138
- tx = client.tx.proxy.proxy(this.seedAddress, "MiningBid", batch);
1139
- }
1140
- return new TxSubmitter(client, tx, this.txSubmitterPair);
1141
- }
1142
- /**
1143
- * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1144
- */
1145
- async createMiningBids(options) {
1146
- const accounts = this.getAccountsInRange(options.subaccountRange);
1147
- const client = await this.client;
1148
- const submitter = await this.createMiningBidTx({
1149
- ...options,
1150
- subaccounts: accounts
1151
- });
1152
- const { tip = 0n } = options;
1153
- const txFee = await submitter.feeEstimate(tip);
1154
- let minBalance = options.bidAmount * BigInt(accounts.length);
1155
- let totalFees = tip + 1n + txFee;
1156
- const seedBalance = await client.query.system.account(this.seedAddress).then((x) => x.data.free.toBigInt());
1157
- if (!this.isProxy) {
1158
- minBalance += totalFees;
1159
- }
1160
- if (seedBalance < minBalance) {
1161
- throw new Error(
1162
- `Insufficient balance to create mining bids. Seed account has ${formatArgons(
1163
- seedBalance
1164
- )} but needs ${formatArgons(minBalance)}`
1165
- );
1166
- }
1167
- if (this.isProxy) {
1168
- const { canAfford, availableBalance } = await submitter.canAfford({
1169
- tip
1170
- });
1171
- if (!canAfford) {
1172
- throw new Error(
1173
- `Insufficient balance to pay proxy fees. Proxy account has ${formatArgons(
1174
- availableBalance
1175
- )} but needs ${formatArgons(totalFees)}`
1176
- );
1177
- }
1178
- }
1179
- console.log("Creating bids", {
1180
- perSeatBid: options.bidAmount,
1181
- subaccounts: options.subaccountRange,
1182
- txFee
1183
- });
1184
- const txResult = await submitter.submit({
1185
- tip,
1186
- useLatestNonce: true
1187
- });
1188
- const bidError = await txResult.inBlockPromise.then(() => void 0).catch((x) => x);
1189
- return {
1190
- finalFee: txResult.finalFee,
1191
- bidError,
1192
- blockHash: txResult.includedInBlock,
1193
- successfulBids: txResult.batchInterruptedIndex !== void 0 ? txResult.batchInterruptedIndex : accounts.length
1194
- };
1195
- }
1196
- getAccountsInRange(range) {
1197
- const entries = new Set(range ?? getDefaultSubaccountRange());
1198
- return Object.entries(this.subAccountsByAddress).filter(([_, account]) => {
1199
- return entries.has(account.index);
1200
- }).map(([address, { pair, index }]) => ({ pair, index, address }));
1201
- }
1202
- async watchBlocks(shouldLog = false) {
1203
- const accountMiners = await AccountMiners.loadAt(this, { shouldLog });
1204
- await accountMiners.watch();
1205
- return accountMiners;
1206
- }
1207
- };
1208
- function getDefaultSubaccountRange() {
1209
- try {
1210
- const config2 = getConfig();
1211
- return parseSubaccountRange(config2.subaccountRange ?? "0-9");
1212
- } catch {
1213
- console.error(
1214
- "Failed to parse SUBACCOUNT_RANGE configuration. Defaulting to 0-9. Please check the format of the subaccountRange config value."
1215
- );
1216
- return Array.from({ length: 10 }, (_, i) => i);
1217
- }
1218
- }
1219
- function parseSubaccountRange(range) {
1220
- if (!range) {
1221
- return void 0;
1222
- }
1223
- const indices = [];
1224
- for (const entry of range.split(",")) {
1225
- if (entry.includes("-")) {
1226
- const [start, end] = entry.split("-").map((x) => parseInt(x, 10));
1227
- for (let i = start; i <= end; i++) {
1228
- indices.push(i);
1229
- }
1230
- continue;
1231
- }
1232
- const record = parseInt(entry.trim(), 10);
1233
- if (Number.isNaN(record) || !Number.isInteger(record)) {
1234
- throw new Error(`Invalid range entry: ${entry}`);
1235
- }
1236
- if (Number.isInteger(record)) {
1237
- indices.push(record);
1238
- }
1239
- }
1240
- return indices;
1241
- }
1242
- var MiningBids = class {
1243
- constructor(client, shouldLog = true) {
1244
- this.client = client;
1245
- this.shouldLog = shouldLog;
1246
- __publicField(this, "nextCohort", []);
1247
- }
1248
- async maxCohortSize() {
1249
- const client = await this.client;
1250
- return client.query.miningSlot.nextCohortSize().then((x) => x.toNumber());
1251
- }
1252
- async onCohortChange(options) {
1253
- const { onBiddingStart, onBiddingEnd } = options;
1254
- const client = await this.client;
1255
- let openCohortStartingFrameId = 0;
1256
- const unsubscribe = await client.queryMulti(
1257
- [
1258
- client.query.miningSlot.isNextSlotBiddingOpen,
1259
- client.query.miningSlot.nextFrameId
1260
- ],
1261
- async ([isBiddingOpen, rawNextCohortStartingFrameId]) => {
1262
- const nextFrameId = rawNextCohortStartingFrameId.toNumber();
1263
- if (isBiddingOpen.isTrue) {
1264
- if (openCohortStartingFrameId !== 0) {
1265
- await onBiddingEnd?.(openCohortStartingFrameId);
1266
- }
1267
- openCohortStartingFrameId = nextFrameId;
1268
- await onBiddingStart?.(nextFrameId);
1269
- } else {
1270
- await onBiddingEnd?.(nextFrameId);
1271
- openCohortStartingFrameId = 0;
1272
- }
1273
- }
1274
- );
1275
- return { unsubscribe };
1276
- }
1277
- async watch(accountNames, blockHash, printFn) {
1278
- const client = await this.client;
1279
- const api = blockHash ? await client.at(blockHash) : client;
1280
- const unsubscribe = await api.query.miningSlot.bidsForNextSlotCohort(async (next) => {
1281
- this.nextCohort = await Promise.all(next.map((x) => this.toBid(accountNames, x)));
1282
- if (!this.shouldLog) return;
1283
- console.clear();
1284
- const block = await client.query.system.number();
1285
- if (!printFn) {
1286
- console.log("At block", block.toNumber());
1287
- this.print();
1288
- } else {
1289
- printFn(block.toNumber());
1290
- }
1291
- });
1292
- return { unsubscribe };
1293
- }
1294
- async loadAt(accountNames, blockHash) {
1295
- const client = await this.client;
1296
- const api = blockHash ? await client.at(blockHash) : client;
1297
- const nextCohort = await api.query.miningSlot.bidsForNextSlotCohort();
1298
- this.nextCohort = await Promise.all(nextCohort.map((x) => this.toBid(accountNames, x)));
1299
- }
1300
- async toBid(accountNames, bid) {
1301
- return {
1302
- accountId: bid.accountId.toString(),
1303
- isOurs: accountNames.get(bid.accountId.toString()) ?? "n",
1304
- bidAmount: bid.bid.toBigInt()
1305
- };
1306
- }
1307
- print() {
1308
- const bids = this.nextCohort.map((bid) => {
1309
- return {
1310
- account: bid.accountId,
1311
- isOurs: bid.isOurs,
1312
- bidAmount: formatArgons(bid.bidAmount)
1313
- };
1314
- });
1315
- if (bids.length) {
1316
- console.log("\n\nMining Bids:");
1317
- printTable(bids);
1318
- }
1319
- }
1320
- };
1321
- var { ROUND_FLOOR: ROUND_FLOOR2 } = BigNumber;
350
+ var { ROUND_FLOOR: ROUND_FLOOR2 } = BigNumber2;
1322
351
  var Vault = class _Vault {
1323
352
  constructor(id, vault, tickDuration) {
1324
353
  this.tickDuration = tickDuration;
@@ -1343,8 +372,9 @@ var Vault = class _Vault {
1343
372
  }
1344
373
  load(vault) {
1345
374
  this.securitization = vault.securitization.toBigInt();
1346
- this.securitizationRatio = convertFixedU128ToBigNumber(
1347
- vault.securitizationRatio.toBigInt()
375
+ this.securitizationRatio = fromFixedNumber(
376
+ vault.securitizationRatio.toBigInt(),
377
+ FIXED_U128_DECIMALS
1348
378
  ).toNumber();
1349
379
  this.argonsLocked = vault.argonsLocked.toBigInt();
1350
380
  this.argonsPendingActivation = vault.argonsPendingActivation.toBigInt();
@@ -1355,12 +385,14 @@ var Vault = class _Vault {
1355
385
  }
1356
386
  }
1357
387
  this.terms = {
1358
- bitcoinAnnualPercentRate: convertFixedU128ToBigNumber(
1359
- vault.terms.bitcoinAnnualPercentRate.toBigInt()
388
+ bitcoinAnnualPercentRate: fromFixedNumber(
389
+ vault.terms.bitcoinAnnualPercentRate.toBigInt(),
390
+ FIXED_U128_DECIMALS
1360
391
  ),
1361
392
  bitcoinBaseFee: vault.terms.bitcoinBaseFee.toBigInt(),
1362
- liquidityPoolProfitSharing: convertPermillToBigNumber(
1363
- vault.terms.liquidityPoolProfitSharing.toBigInt()
393
+ treasuryProfitSharing: fromFixedNumber(
394
+ vault.terms.treasuryProfitSharing.toBigInt(),
395
+ PERMILL_DECIMALS
1364
396
  )
1365
397
  };
1366
398
  this.operatorAccountId = vault.operatorAccountId.toString();
@@ -1369,12 +401,14 @@ var Vault = class _Vault {
1369
401
  const [tickApply, terms] = vault.pendingTerms.value;
1370
402
  this.pendingTermsChangeTick = tickApply.toNumber();
1371
403
  this.pendingTerms = {
1372
- bitcoinAnnualPercentRate: convertFixedU128ToBigNumber(
1373
- terms.bitcoinAnnualPercentRate.toBigInt()
404
+ bitcoinAnnualPercentRate: fromFixedNumber(
405
+ terms.bitcoinAnnualPercentRate.toBigInt(),
406
+ FIXED_U128_DECIMALS
1374
407
  ),
1375
408
  bitcoinBaseFee: terms.bitcoinBaseFee.toBigInt(),
1376
- liquidityPoolProfitSharing: convertPermillToBigNumber(
1377
- vault.terms.liquidityPoolProfitSharing.toBigInt()
409
+ treasuryProfitSharing: fromFixedNumber(
410
+ vault.terms.treasuryProfitSharing.toBigInt(),
411
+ PERMILL_DECIMALS
1378
412
  )
1379
413
  };
1380
414
  }
@@ -1388,31 +422,31 @@ var Vault = class _Vault {
1388
422
  return [...this.argonsScheduledForRelease.values()].reduce((acc, val) => acc + val, 0n);
1389
423
  }
1390
424
  securitizationRatioBN() {
1391
- return new BigNumber__default(this.securitizationRatio);
425
+ return new BigNumber2__default(this.securitizationRatio);
1392
426
  }
1393
427
  recoverySecuritization() {
1394
- const reserved = new BigNumber__default(1).div(this.securitizationRatioBN());
428
+ const reserved = new BigNumber2__default(1).div(this.securitizationRatioBN());
1395
429
  return this.securitization - BigInt(reserved.multipliedBy(this.securitization.toString()).toFixed(0, ROUND_FLOOR2));
1396
430
  }
1397
431
  minimumSecuritization() {
1398
432
  return BigInt(
1399
- this.securitizationRatioBN().multipliedBy(this.argonsLocked.toString()).decimalPlaces(0, BigNumber__default.ROUND_CEIL).toString()
433
+ this.securitizationRatioBN().multipliedBy(this.argonsLocked.toString()).decimalPlaces(0, BigNumber2__default.ROUND_CEIL).toString()
1400
434
  );
1401
435
  }
1402
436
  activatedSecuritization() {
1403
437
  const activated = this.argonsLocked - this.argonsPendingActivation;
1404
- const maxRatio = BigNumber__default(Math.min(this.securitizationRatio, 2));
438
+ const maxRatio = BigNumber2__default(Math.min(this.securitizationRatio, 2));
1405
439
  return BigInt(maxRatio.multipliedBy(activated.toString()).toFixed(0, ROUND_FLOOR2));
1406
440
  }
1407
441
  /**
1408
- * Returns the amount of Argons available to match per liquidity pool
442
+ * Returns the amount of Argons available to match per treasury pool
1409
443
  */
1410
444
  activatedSecuritizationPerSlot() {
1411
445
  const activated = this.activatedSecuritization();
1412
446
  return activated / 10n;
1413
447
  }
1414
448
  calculateBitcoinFee(amount) {
1415
- const fee = this.terms.bitcoinAnnualPercentRate.multipliedBy(Number(amount)).integerValue(BigNumber__default.ROUND_CEIL);
449
+ const fee = this.terms.bitcoinAnnualPercentRate.multipliedBy(Number(amount)).integerValue(BigNumber2__default.ROUND_CEIL);
1416
450
  return BigInt(fee.toString()) + this.terms.bitcoinBaseFee;
1417
451
  }
1418
452
  static async get(client, vaultId, tickDurationMillis) {
@@ -1423,7 +457,7 @@ var Vault = class _Vault {
1423
457
  const tickDuration = tickDurationMillis ?? await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1424
458
  return new _Vault(vaultId, rawVault.unwrap(), tickDuration);
1425
459
  }
1426
- static async create(client, keypair, args, config2 = {}) {
460
+ static async create(client, keypair, args, config = {}) {
1427
461
  const {
1428
462
  securitization,
1429
463
  securitizationRatio,
@@ -1444,18 +478,18 @@ var Vault = class _Vault {
1444
478
  xpubBytes = bytes;
1445
479
  }
1446
480
  }
1447
- let vaultParams = {
481
+ const vaultParams = {
1448
482
  terms: {
1449
483
  // convert to fixed u128
1450
- bitcoinAnnualPercentRate: toFixedNumber(annualPercentRate, 18),
484
+ bitcoinAnnualPercentRate: toFixedNumber(annualPercentRate, FIXED_U128_DECIMALS),
1451
485
  bitcoinBaseFee: BigInt(baseFee),
1452
- liquidityPoolProfitSharing: toFixedNumber(args.liquidityPoolProfitSharing, 6)
486
+ treasuryProfitSharing: toFixedNumber(args.treasuryProfitSharing, PERMILL_DECIMALS)
1453
487
  },
1454
- securitizationRatio: toFixedNumber(securitizationRatio, 18),
488
+ securitizationRatio: toFixedNumber(securitizationRatio, FIXED_U128_DECIMALS),
1455
489
  securitization: BigInt(securitization),
1456
490
  bitcoinXpubkey: xpubBytes
1457
491
  };
1458
- let tx = new TxSubmitter(client, client.tx.vaults.create(vaultParams), keypair);
492
+ const tx = new TxSubmitter(client, client.tx.vaults.create(vaultParams), keypair);
1459
493
  if (doNotExceedBalance) {
1460
494
  const finalTip = tip ?? 0n;
1461
495
  let txFee = await tx.feeEstimate(finalTip);
@@ -1492,881 +526,63 @@ var Vault = class _Vault {
1492
526
  if (rawVault.isNone) {
1493
527
  throw new Error("Vault creation failed, vault not found");
1494
528
  }
1495
- const tickDuration = config2.tickDurationMillis ?? await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
529
+ const tickDuration = config.tickDurationMillis ?? await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1496
530
  const vault = new _Vault(vaultId, rawVault.unwrap(), tickDuration);
1497
531
  return { vault, txResult: result };
1498
532
  }
1499
533
  };
1500
- var VaultMonitor = class {
1501
- constructor(accountset, alerts = {}, options = {}) {
1502
- this.accountset = accountset;
1503
- this.alerts = alerts;
1504
- this.options = options;
1505
- __publicField(this, "events", createNanoEvents());
1506
- __publicField(this, "vaultsById", {});
1507
- __publicField(this, "blockWatch");
1508
- __publicField(this, "mainchain");
1509
- __publicField(this, "activatedCapitalByVault", {});
1510
- __publicField(this, "lastPrintedBids");
1511
- __publicField(this, "miningBids");
1512
- __publicField(this, "tickDuration", 0);
1513
- __publicField(this, "vaultOnlyWatchMode", false);
1514
- __publicField(this, "shouldLog", true);
1515
- this.mainchain = accountset.client;
1516
- if (options.vaultOnlyWatchMode !== void 0) {
1517
- this.vaultOnlyWatchMode = options.vaultOnlyWatchMode;
1518
- }
1519
- if (options.shouldLog !== void 0) {
1520
- this.shouldLog = options.shouldLog;
1521
- }
1522
- this.miningBids = new MiningBids(this.mainchain, this.shouldLog);
1523
- this.blockWatch = new BlockWatch(this.mainchain, {
1524
- shouldLog: this.shouldLog
1525
- });
1526
- this.blockWatch.events.on(
1527
- "vaults-updated",
1528
- (header, vaultIds) => this.onVaultsUpdated(header.hash, vaultIds)
1529
- );
1530
- this.blockWatch.events.on("mining-bid", async (header, _bid) => {
1531
- await this.miningBids.loadAt(this.accountset.namedAccounts, header.hash);
1532
- this.printBids(header.hash);
1533
- });
1534
- this.blockWatch.events.on("mining-bid-ousted", async (header) => {
1535
- await this.miningBids.loadAt(this.accountset.namedAccounts, header.hash);
1536
- this.printBids(header.hash);
1537
- });
1538
- }
1539
- stop() {
1540
- this.blockWatch.stop();
1541
- }
1542
- async monitor(justPrint = false) {
1543
- const client = await this.mainchain;
1544
- this.tickDuration = (await client.query.ticks.genesisTicker()).tickDurationMillis.toNumber();
1545
- const blockHeader = await client.rpc.chain.getHeader();
1546
- const blockHash = new Uint8Array(blockHeader.hash);
1547
- console.log(
1548
- `${justPrint ? "Run" : "Started"} at block ${blockHeader.number} - ${blockHeader.hash.toHuman()}`
1549
- );
1550
- await this.miningBids.loadAt(this.accountset.namedAccounts, blockHash);
1551
- const vaults = await client.query.vaults.vaultsById.entries();
1552
- for (const [storageKey, rawVault] of vaults) {
1553
- const vaultId = storageKey.args[0].toNumber();
1554
- this.updateVault(vaultId, rawVault);
1555
- }
1556
- await client.query.liquidityPools.capitalRaising((x) => {
1557
- var _a;
1558
- this.activatedCapitalByVault = {};
1559
- for (const entry of x) {
1560
- const vaultId = entry.vaultId.toNumber();
1561
- this.activatedCapitalByVault[vaultId] = entry.activatedCapital.toBigInt();
1562
- }
1563
- for (const [vaultId, vault] of Object.entries(this.vaultsById)) {
1564
- const id = Number(vaultId);
1565
- (_a = this.activatedCapitalByVault)[id] ?? (_a[id] = 0n);
1566
- this.checkMiningBondAlerts(id, vault);
1567
- }
1568
- });
1569
- this.printVaults();
1570
- if (!this.vaultOnlyWatchMode && this.shouldLog) {
1571
- this.miningBids.print();
1572
- }
1573
- if (!justPrint) await this.blockWatch.start();
1574
- }
1575
- printVaults() {
1576
- if (!this.shouldLog) return;
1577
- const vaults = [];
1578
- for (const [vaultId, vault] of Object.entries(this.vaultsById)) {
1579
- vaults.push({
1580
- id: vaultId,
1581
- btcSpace: `${formatArgons(vault.availableBitcoinSpace())} (${formatArgons(vault.argonsPendingActivation)} pending)`,
1582
- btcDeal: `${formatArgons(vault.terms.bitcoinBaseFee)} + ${formatPercent(vault.terms.bitcoinAnnualPercentRate)}`,
1583
- securitization: `${formatArgons(vault.securitization)} at ${vault.securitizationRatio}x`,
1584
- securActivated: `${formatArgons(vault.activatedSecuritizationPerSlot())}/slot`,
1585
- liquidPoolDeal: `${formatPercent(vault.terms.liquidityPoolProfitSharing)} sharing`,
1586
- operator: `${this.accountset.namedAccounts.has(vault.operatorAccountId) ? ` (${this.accountset.namedAccounts.get(vault.operatorAccountId)})` : vault.operatorAccountId}`,
1587
- state: vault.isClosed ? "closed" : vault.openedDate < /* @__PURE__ */ new Date() ? "open" : "pending"
1588
- });
1589
- }
1590
- if (vaults.length) {
1591
- if (this.vaultOnlyWatchMode) {
1592
- console.clear();
1593
- }
1594
- console.log("\n\nVaults:");
1595
- printTable(vaults);
1596
- }
1597
- }
1598
- async recheckAfterActive(vaultId) {
1599
- const activationDate = this.vaultsById[vaultId].openedDate;
1600
- if (this.shouldLog) {
1601
- console.log(`Waiting for vault ${vaultId} to activate ${activationDate}`);
1602
- }
1603
- await new Promise((resolve) => setTimeout(resolve, activationDate.getTime() - Date.now()));
1604
- const client = await this.mainchain;
1605
- let isReady = false;
1606
- while (!isReady) {
1607
- const rawVault = await client.query.vaults.vaultsById(vaultId);
1608
- if (!rawVault.isSome) return;
1609
- const vault = new Vault(vaultId, rawVault.value, this.tickDuration);
1610
- this.vaultsById[vaultId] = vault;
1611
- if (vault.isClosed) return;
1612
- if (vault.openedDate < /* @__PURE__ */ new Date()) {
1613
- isReady = true;
1614
- break;
1615
- }
1616
- await new Promise((resolve) => setTimeout(resolve, 100));
1617
- }
1618
- this.checkAlerts(vaultId, this.vaultsById[vaultId]);
1619
- }
1620
- async onVaultsUpdated(blockHash, vaultIds) {
1621
- await this.reloadVaultsAt([...vaultIds], blockHash).catch((err) => {
1622
- console.error(`Failed to reload vault ${[...vaultIds]} at block ${blockHash}:`, err);
1623
- });
1624
- this.printVaults();
1625
- }
1626
- async reloadVaultsAt(vaultIds, blockHash) {
1627
- const client = await this.mainchain;
1628
- const api = await client.at(blockHash);
1629
- const vaults = await api.query.vaults.vaultsById.multi(vaultIds);
1630
- for (let i = 0; i < vaultIds.length; i += 1) {
1631
- this.updateVault(vaultIds[i], vaults[i]);
1632
- }
1633
- }
1634
- updateVault(vaultId, rawVault) {
1635
- if (rawVault.isNone) return;
1636
- const vault = new Vault(vaultId, rawVault.value, this.tickDuration);
1637
- this.vaultsById[vaultId] = vault;
1638
- if (vault.openedDate > /* @__PURE__ */ new Date()) {
1639
- void this.recheckAfterActive(vaultId);
1640
- } else {
1641
- this.checkAlerts(vaultId, vault);
1642
- }
1643
- }
1644
- checkAlerts(vaultId, vault) {
1645
- if (this.alerts.bitcoinSpaceAvailable !== void 0) {
1646
- const availableBitcoinSpace = vault.availableBitcoinSpace();
1647
- if (availableBitcoinSpace >= this.alerts.bitcoinSpaceAvailable) {
1648
- console.warn(
1649
- `Vault ${vaultId} has available bitcoins above ${formatArgons(this.alerts.bitcoinSpaceAvailable)}`
1650
- );
1651
- this.events.emit("bitcoin-space-above", vaultId, availableBitcoinSpace);
1652
- }
1653
- }
1654
- }
1655
- checkMiningBondAlerts(vaultId, vault) {
1656
- if (this.alerts.liquidityPoolSpaceAvailable === void 0) return;
1657
- const activatedSecuritization = vault.activatedSecuritizationPerSlot();
1658
- const capitalization = this.activatedCapitalByVault[vaultId] ?? 0n;
1659
- const available = activatedSecuritization - capitalization;
1660
- if (available >= this.alerts.liquidityPoolSpaceAvailable) {
1661
- this.events.emit("liquidity-pool-space-above", vaultId, available);
1662
- }
1663
- }
1664
- printBids(blockHash) {
1665
- if (!this.shouldLog) return;
1666
- if (this.lastPrintedBids === blockHash) return;
1667
- this.miningBids.print();
1668
- this.lastPrintedBids = blockHash;
1669
- }
1670
- };
1671
-
1672
- // src/CohortBidder.ts
1673
- var CohortBidder = class {
1674
- constructor(accountset, cohortStartingFrameId, subaccounts, options, callbacks) {
1675
- this.accountset = accountset;
1676
- this.cohortStartingFrameId = cohortStartingFrameId;
1677
- this.subaccounts = subaccounts;
1678
- this.options = options;
1679
- this.callbacks = callbacks;
1680
- __publicField(this, "txFees", 0n);
1681
- __publicField(this, "bidsAttempted", 0);
1682
- __publicField(this, "winningBids", []);
1683
- __publicField(this, "myAddresses", /* @__PURE__ */ new Set());
1684
- __publicField(this, "currentBids", {
1685
- bids: [],
1686
- mostRecentBidTick: 0,
1687
- atTick: 0,
1688
- atBlockNumber: 0
1689
- });
1690
- __publicField(this, "unsubscribe");
1691
- __publicField(this, "pendingRequest");
1692
- __publicField(this, "isStopped", false);
1693
- __publicField(this, "millisPerTick");
1694
- __publicField(this, "minIncrement", 10000n);
1695
- __publicField(this, "nextCohortSize");
1696
- __publicField(this, "lastBidTick", 0);
1697
- __publicField(this, "evaluateInterval");
1698
- this.subaccounts.forEach((x) => {
1699
- this.myAddresses.add(x.address);
1700
- });
1701
- }
1702
- get clientPromise() {
1703
- return this.accountset.client;
1704
- }
1705
- async start() {
1706
- console.log(`Starting cohort ${this.cohortStartingFrameId} bidder`, {
1707
- maxBid: formatArgons(this.options.maxBid),
1708
- minBid: formatArgons(this.options.minBid),
1709
- bidIncrement: formatArgons(this.options.bidIncrement),
1710
- maxBudget: formatArgons(this.options.maxBudget),
1711
- bidDelay: this.options.bidDelay,
1712
- subaccounts: this.subaccounts
1713
- });
1714
- const client = await this.clientPromise;
1715
- this.minIncrement = client.consts.miningSlot.bidIncrements.toBigInt();
1716
- this.nextCohortSize = await client.query.miningSlot.nextCohortSize().then((x) => x.toNumber());
1717
- if (this.subaccounts.length > this.nextCohortSize) {
1718
- console.info(
1719
- `Cohort size ${this.nextCohortSize} is less than provided subaccounts ${this.subaccounts.length}.`
1720
- );
1721
- this.subaccounts.length = this.nextCohortSize;
1722
- }
1723
- this.millisPerTick = await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1724
- let didStart = false;
1725
- this.unsubscribe = await client.queryMulti(
1726
- [
1727
- client.query.miningSlot.bidsForNextSlotCohort,
1728
- client.query.miningSlot.nextFrameId,
1729
- client.query.ticks.currentTick,
1730
- client.query.system.number
1731
- ],
1732
- async ([rawBids, nextFrameId, currentTick, blockNumber]) => {
1733
- if (nextFrameId.toNumber() === this.cohortStartingFrameId) {
1734
- this.updateBidList(rawBids, blockNumber.toNumber(), currentTick.toNumber());
1735
- if (!didStart) {
1736
- didStart = true;
1737
- this.scheduleEvaluation();
1738
- void this.checkWinningBids();
1739
- }
1740
- }
1741
- }
1742
- );
1743
- }
1744
- async stop() {
1745
- if (this.isStopped) return this.winningBids;
1746
- this.isStopped = true;
1747
- clearInterval(this.evaluateInterval);
1748
- console.log("Stopping bidder for cohort", this.cohortStartingFrameId);
1749
- if (this.unsubscribe) {
1750
- this.unsubscribe();
1751
- }
1752
- const client = await this.clientPromise;
1753
- const [nextFrameId, isBiddingOpen] = await client.queryMulti([
1754
- client.query.miningSlot.nextFrameId,
1755
- client.query.miningSlot.isNextSlotBiddingOpen
1756
- ]);
1757
- if (nextFrameId.toNumber() === this.cohortStartingFrameId && isBiddingOpen.isTrue) {
1758
- console.log("Bidding is still open, waiting for it to close");
1759
- await new Promise(async (resolve) => {
1760
- const unsub = await client.query.miningSlot.isNextSlotBiddingOpen((isOpen) => {
1761
- if (isOpen.isFalse) {
1762
- unsub();
1763
- resolve();
1764
- }
1765
- });
1766
- });
1767
- }
1768
- void await this.pendingRequest;
1769
- const currentFrameId = await client.query.miningSlot.nextFrameId();
1770
- let blockNumber;
1771
- if (currentFrameId.toNumber() > this.cohortStartingFrameId) {
1772
- blockNumber = await client.query.miningSlot.frameStartBlockNumbers().then((x) => x[0]?.toNumber()) - 1;
1773
- } else {
1774
- blockNumber = await client.query.system.number().then((x) => x.toNumber());
1775
- }
1776
- const blockHash = await client.rpc.chain.getBlockHash(blockNumber);
1777
- const api = await client.at(blockHash);
1778
- const rawBids = await api.query.miningSlot.bidsForNextSlotCohort();
1779
- const currentTick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1780
- this.updateBidList(rawBids, blockNumber, currentTick);
1781
- console.log("Bidder stopped", {
1782
- cohortStartingFrameId: this.cohortStartingFrameId,
1783
- blockNumber,
1784
- winningBids: this.winningBids
1785
- });
1786
- return this.winningBids;
1787
- }
1788
- async checkWinningBids() {
1789
- if (this.isStopped) return;
1790
- if (this.pendingRequest) {
1791
- console.log("Current bid is still in progress, skipping this check");
1792
- return;
1793
- }
1794
- if (this.currentBids.mostRecentBidTick < this.lastBidTick) {
1795
- console.log(`Waiting for bids more recent than our last attempt.`, {
1796
- ownAttemptedBidTick: this.lastBidTick,
1797
- liveBidsTick: this.currentBids.mostRecentBidTick
1798
- });
1799
- return;
1800
- }
1801
- const bids = [...this.currentBids.bids];
1802
- const bidsAtTick = this.currentBids.atTick;
1803
- const blockNumber = this.currentBids.atBlockNumber;
1804
- const winningBids = bids.filter((x) => this.myAddresses.has(x.address));
1805
- if (winningBids.length >= this.subaccounts.length) {
1806
- console.log(`No updates needed. Winning all remaining seats (${winningBids.length}).`);
1807
- return;
1808
- }
1809
- console.log(
1810
- `Checking bids for cohort ${this.cohortStartingFrameId}, Still trying for seats: ${this.subaccounts.length}`
1811
- );
1812
- const winningAddresses = new Set(winningBids.map((x) => x.address));
1813
- let lowestBid;
1814
- let myAllocatedBids = 0n;
1815
- for (const bid of bids) {
1816
- lowestBid ?? (lowestBid = bid.bidMicrogons);
1817
- if (this.myAddresses.has(bid.address)) {
1818
- myAllocatedBids += bid.bidMicrogons;
1819
- } else {
1820
- if (bid.bidMicrogons < lowestBid) {
1821
- lowestBid = bid.bidMicrogons;
1822
- }
1823
- }
1824
- }
1825
- lowestBid ?? (lowestBid = -this.options.bidIncrement);
1826
- let nextBid = lowestBid + this.options.bidIncrement;
1827
- if (nextBid < this.options.minBid) {
1828
- nextBid = this.options.minBid;
1829
- }
1830
- if (nextBid > this.options.maxBid) {
1831
- nextBid = this.options.maxBid;
1832
- }
1833
- const fakeTx = await this.accountset.createMiningBidTx({
1834
- subaccounts: this.subaccounts,
1835
- bidAmount: nextBid
1836
- });
1837
- let availableBalanceForBids = await this.accountset.submitterBalance();
1838
- availableBalanceForBids += myAllocatedBids;
1839
- const tip = this.options.tipPerTransaction ?? 0n;
1840
- const feeEstimate = await fakeTx.feeEstimate(tip);
1841
- const estimatedFeePlusTip = feeEstimate + tip;
1842
- let budgetForSeats = this.options.maxBudget - estimatedFeePlusTip;
1843
- if (budgetForSeats > availableBalanceForBids) {
1844
- budgetForSeats = availableBalanceForBids - estimatedFeePlusTip;
1845
- }
1846
- if (nextBid < lowestBid) {
1847
- console.log(
1848
- `Next bid within parameters is ${formatArgons(nextBid)}, but it's not enough. Current lowest bid is ${formatArgons(lowestBid)}.`
1849
- );
1850
- this.safeRecordParamsAdjusted({
1851
- tick: bidsAtTick,
1852
- blockNumber,
1853
- maxSeats: 0,
1854
- winningBidCount: winningBids.length,
1855
- reason: "max-bid-too-low",
1856
- availableBalanceForBids
1857
- });
1858
- return;
1859
- }
1860
- if (nextBid - lowestBid < Number(this.minIncrement)) {
1861
- console.log(
1862
- `Can't make any more bids for ${this.cohortStartingFrameId} with given constraints (next bid below min increment).`,
1863
- {
1864
- lowestCurrentBid: formatArgons(lowestBid),
1865
- nextAttemptedBid: formatArgons(nextBid),
1866
- maxBid: formatArgons(this.options.maxBid)
1867
- }
1868
- );
1869
- this.safeRecordParamsAdjusted({
1870
- tick: bidsAtTick,
1871
- blockNumber,
1872
- maxSeats: 0,
1873
- winningBidCount: winningBids.length,
1874
- reason: "max-bid-too-low",
1875
- availableBalanceForBids
1876
- });
1877
- return;
1878
- }
1879
- const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(budgetForSeats / nextBid);
1880
- let accountsToUse = [...this.subaccounts];
1881
- if (accountsToUse.length > seatsInBudget) {
1882
- this.safeRecordParamsAdjusted({
1883
- tick: bidsAtTick,
1884
- blockNumber,
1885
- maxSeats: this.subaccounts.length,
1886
- winningBidCount: winningBids.length,
1887
- reason: availableBalanceForBids - estimatedFeePlusTip < nextBid * BigInt(seatsInBudget) ? "insufficient-balance" : "max-budget-too-low",
1888
- availableBalanceForBids
1889
- });
1890
- accountsToUse.sort((a, b) => {
1891
- const isWinningA = winningAddresses.has(a.address);
1892
- const isWinningB = winningAddresses.has(b.address);
1893
- if (isWinningA && !isWinningB) return -1;
1894
- if (!isWinningA && isWinningB) return 1;
1895
- if (a.isRebid && !b.isRebid) return -1;
1896
- if (!a.isRebid && b.isRebid) return 1;
1897
- return a.index - b.index;
1898
- });
1899
- accountsToUse.length = seatsInBudget;
1900
- }
1901
- if (accountsToUse.length > winningBids.length) {
1902
- this.pendingRequest = this.submitBids(nextBid, accountsToUse);
1903
- }
1904
- }
1905
- async submitBids(microgonsPerSeat, subaccounts) {
1906
- try {
1907
- this.bidsAttempted += subaccounts.length;
1908
- const submitter = await this.accountset.createMiningBidTx({
1909
- subaccounts,
1910
- bidAmount: microgonsPerSeat
1911
- });
1912
- const tip = this.options.tipPerTransaction ?? 0n;
1913
- const txResult = await submitter.submit({
1914
- tip,
1915
- useLatestNonce: true
1916
- });
1917
- const bidError = await txResult.inBlockPromise.then(() => void 0).catch((x) => x);
1918
- const client = await this.clientPromise;
1919
- let api = txResult.includedInBlock ? await client.at(txResult.includedInBlock) : client;
1920
- this.lastBidTick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1921
- const blockNumber = await api.query.system.number().then((x) => x.toNumber());
1922
- const bidAtTick = this.lastBidTick;
1923
- try {
1924
- this.callbacks?.onBidsSubmitted?.({
1925
- tick: bidAtTick,
1926
- blockNumber,
1927
- microgonsPerSeat,
1928
- txFeePlusTip: txResult.finalFee ?? 0n,
1929
- submittedCount: subaccounts.length
1930
- });
1931
- } catch (error) {
1932
- console.error("Error in onBidsSubmitted callback:", error);
1933
- }
1934
- const successfulBids = txResult.batchInterruptedIndex ?? subaccounts.length;
1935
- this.txFees += txResult.finalFee ?? 0n;
1936
- console.log("Result of bids for cohort", {
1937
- successfulBids,
1938
- bidsPlaced: subaccounts.length,
1939
- bidPerSeat: formatArgons(microgonsPerSeat),
1940
- bidAtTick
1941
- });
1942
- if (bidError) {
1943
- try {
1944
- this.callbacks?.onBidsRejected?.({
1945
- tick: bidAtTick,
1946
- blockNumber,
1947
- microgonsPerSeat,
1948
- submittedCount: subaccounts.length,
1949
- rejectedCount: subaccounts.length - successfulBids,
1950
- bidError
1951
- });
1952
- } catch (error) {
1953
- console.error("Error in onBidsRejected callback:", error);
1954
- }
1955
- throw bidError;
1956
- }
1957
- } catch (err) {
1958
- console.error(`Error bidding for cohort ${this.cohortStartingFrameId}:`, err);
1959
- } finally {
1960
- this.pendingRequest = void 0;
1961
- this.scheduleEvaluation();
1962
- }
1963
- }
1964
- scheduleEvaluation() {
1965
- if (this.isStopped) return;
1966
- const millisPerTick = this.millisPerTick;
1967
- const delayTicks = Math.max(this.options.bidDelay, 1);
1968
- const delay = delayTicks * millisPerTick;
1969
- if (this.evaluateInterval) clearInterval(this.evaluateInterval);
1970
- console.log(`Scheduling next evaluation in ${delay}ms`);
1971
- this.evaluateInterval = setInterval(() => this.checkWinningBids().catch(console.error), delay);
1972
- }
1973
- updateBidList(rawBids, blockNumber, tick) {
1974
- try {
1975
- let mostRecentBidTick = 0;
1976
- let hasDiffs = this.currentBids.bids.length !== rawBids.length;
1977
- const bids = [];
1978
- for (let i = 0; i < rawBids.length; i += 1) {
1979
- const rawBid = rawBids[i];
1980
- const bidAtTick = rawBid.bidAtTick.toNumber();
1981
- if (bidAtTick > mostRecentBidTick) {
1982
- mostRecentBidTick = bidAtTick;
1983
- }
1984
- const address = rawBid.accountId.toHuman();
1985
- const bidMicrogons = rawBid.bid.toBigInt();
1986
- if (!hasDiffs) {
1987
- const existing = this.currentBids.bids[i];
1988
- hasDiffs = existing?.address !== address || existing?.bidMicrogons !== bidMicrogons;
1989
- }
1990
- bids.push({
1991
- address,
1992
- bidMicrogons,
1993
- bidAtTick
1994
- });
1995
- }
1996
- if (blockNumber > this.currentBids.atBlockNumber && hasDiffs) {
1997
- this.currentBids.bids = bids;
1998
- this.currentBids.mostRecentBidTick = mostRecentBidTick;
1999
- this.currentBids.atTick = tick;
2000
- this.currentBids.atBlockNumber = blockNumber;
2001
- this.winningBids = bids.filter((x) => this.myAddresses.has(x.address));
2002
- console.log("Now winning bids:", this.winningBids.length);
2003
- if (this.callbacks?.onBidsUpdated) {
2004
- this.callbacks.onBidsUpdated({
2005
- bids: this.winningBids,
2006
- atBlockNumber: blockNumber,
2007
- tick: mostRecentBidTick
2008
- });
2009
- }
2010
- }
2011
- } catch (err) {
2012
- console.error("Error processing updated bids list:", err);
2013
- }
2014
- }
2015
- safeRecordParamsAdjusted(args) {
2016
- try {
2017
- this.callbacks?.onBidParamsAdjusted?.(args);
2018
- } catch (err) {
2019
- console.error("Error in onBidParamsAdjusted callback:", err);
2020
- }
2021
- }
2022
- };
2023
- var EMPTY_TABLE = {
2024
- headerBottom: { left: " ", mid: " ", other: "\u2500", right: " " },
2025
- headerTop: { left: " ", mid: " ", other: " ", right: " " },
2026
- rowSeparator: { left: " ", mid: " ", other: " ", right: " " },
2027
- tableBottom: { left: " ", mid: " ", other: " ", right: " " },
2028
- vertical: " "
2029
- };
2030
- var BidPool = class {
2031
- constructor(client, keypair, accountRegistry = AccountRegistry.factory()) {
2032
- this.client = client;
2033
- this.keypair = keypair;
2034
- this.accountRegistry = accountRegistry;
2035
- __publicField(this, "bidPoolAmount", 0n);
2036
- __publicField(this, "nextFrameId", 1);
2037
- __publicField(this, "poolVaultCapitalByFrame", {});
2038
- __publicField(this, "vaultSecuritization", []);
2039
- __publicField(this, "printTimeout");
2040
- __publicField(this, "blockWatch");
2041
- __publicField(this, "vaultsById", {});
2042
- __publicField(this, "tickDuration");
2043
- __publicField(this, "lastDistributedFrameId");
2044
- __publicField(this, "FrameSubscriptions", {});
2045
- this.blockWatch = new BlockWatch(client, { shouldLog: false });
2046
- }
2047
- async onVaultsUpdated(blockHash, vaultIdSet) {
2048
- const client = await this.client;
2049
- this.tickDuration ?? (this.tickDuration = (await client.query.ticks.genesisTicker()).tickDurationMillis.toNumber());
2050
- const api = await client.at(blockHash);
2051
- const vaultIds = [...vaultIdSet];
2052
- const rawVaults = await api.query.vaults.vaultsById.multi(vaultIds);
2053
- for (let i = 0; i < vaultIds.length; i += 1) {
2054
- const rawVault = rawVaults[i];
2055
- if (rawVault.isNone) continue;
2056
- const vaultId = vaultIds[i];
2057
- this.vaultsById[vaultId] = new Vault(vaultId, rawVault.unwrap(), this.tickDuration);
2058
- }
2059
- const vaults = Object.entries(this.vaultsById);
2060
- const newSecuritization = [];
2061
- for (const [vaultId, vault] of vaults) {
2062
- const amount = vault.activatedSecuritizationPerSlot();
2063
- newSecuritization.push({
2064
- vaultId: Number(vaultId),
2065
- bitcoinSpace: vault.availableBitcoinSpace(),
2066
- activatedSecuritization: amount,
2067
- vaultSharingPercent: vault.terms.liquidityPoolProfitSharing
2068
- });
2069
- }
2070
- newSecuritization.sort((a, b) => {
2071
- const diff2 = b.activatedSecuritization - a.activatedSecuritization;
2072
- if (diff2 !== 0n) return Number(diff2);
2073
- return a.vaultId - b.vaultId;
2074
- });
2075
- this.vaultSecuritization = newSecuritization;
2076
- this.printDebounce();
2077
- }
2078
- async getBidPool() {
2079
- const client = await this.client;
2080
- const balanceBytes = await client.rpc.state.call("MiningSlotApi_bid_pool", "");
2081
- const balance = client.createType("U128", balanceBytes);
2082
- return balance.toBigInt();
2083
- }
2084
- async loadAt(blockHash) {
2085
- const client = await this.client;
2086
- blockHash ?? (blockHash = new Uint8Array((await client.rpc.chain.getHeader()).hash));
2087
- const api = await client.at(blockHash);
2088
- const rawVaultIds = await api.query.vaults.vaultsById.keys();
2089
- const vaultIds = rawVaultIds.map((x) => x.args[0].toNumber());
2090
- this.bidPoolAmount = await this.getBidPool();
2091
- this.nextFrameId = (await api.query.miningSlot.nextFrameId()).toNumber();
2092
- const contributors = await api.query.liquidityPools.vaultPoolsByFrame.entries();
2093
- for (const [frameId, funds] of contributors) {
2094
- const FrameIdNumber = frameId.args[0].toNumber();
2095
- this.loadFrameData(FrameIdNumber, funds);
2096
- }
2097
- for (const entrant of await api.query.liquidityPools.capitalActive()) {
2098
- this.setVaultFrameData(entrant.frameId.toNumber(), entrant.vaultId.toNumber(), {
2099
- activatedCapital: entrant.activatedCapital.toBigInt()
2100
- });
2101
- }
2102
- for (const entrant of await api.query.liquidityPools.capitalRaising()) {
2103
- this.setVaultFrameData(entrant.frameId.toNumber(), entrant.vaultId.toNumber(), {
2104
- activatedCapital: entrant.activatedCapital.toBigInt()
2105
- });
2106
- }
2107
- await this.onVaultsUpdated(blockHash, new Set(vaultIds));
2108
- this.print();
2109
- }
2110
- async watch() {
2111
- await this.loadAt();
2112
- await this.blockWatch.start();
2113
- this.blockWatch.events.on("vaults-updated", (b, v) => this.onVaultsUpdated(b.hash, v));
2114
- const api = await this.client;
2115
- this.blockWatch.events.on("event", async (_, event) => {
2116
- if (api.events.liquidityPools.BidPoolDistributed.is(event)) {
2117
- const { frameId: rawFrameId } = event.data;
2118
- this.lastDistributedFrameId = rawFrameId.toNumber();
2119
- this.bidPoolAmount = await this.getBidPool();
2120
- this.FrameSubscriptions[rawFrameId.toNumber()]?.();
2121
- const entrant = await api.query.liquidityPools.vaultPoolsByFrame(rawFrameId);
2122
- this.loadFrameData(rawFrameId.toNumber(), entrant);
2123
- this.printDebounce();
2124
- }
2125
- if (api.events.liquidityPools.NextBidPoolCapitalLocked.is(event)) {
2126
- const { frameId } = event.data;
2127
- for (let inc = 0; inc < 2; inc++) {
2128
- const id = frameId.toNumber() + inc;
2129
- if (!this.FrameSubscriptions[id]) {
2130
- this.FrameSubscriptions[id] = await api.query.liquidityPools.vaultPoolsByFrame(
2131
- id,
2132
- async (entrant) => {
2133
- this.loadFrameData(id, entrant);
2134
- this.printDebounce();
2135
- }
2136
- );
2137
- }
2138
- }
2139
- }
2140
- });
2141
- const unsubscribe = await api.queryMulti(
2142
- [
2143
- api.query.miningSlot.bidsForNextSlotCohort,
2144
- api.query.miningSlot.nextFrameId,
2145
- api.query.liquidityPools.capitalActive,
2146
- api.query.liquidityPools.capitalRaising
2147
- ],
2148
- async ([_bids, nextFrameId, openVaultBidPoolCapital, nextPoolCapital]) => {
2149
- this.bidPoolAmount = await this.getBidPool();
2150
- this.nextFrameId = nextFrameId.toNumber();
2151
- for (const entrant of [...openVaultBidPoolCapital, ...nextPoolCapital]) {
2152
- this.setVaultFrameData(entrant.frameId.toNumber(), entrant.vaultId.toNumber(), {
2153
- activatedCapital: entrant.activatedCapital.toBigInt()
2154
- });
2155
- }
2156
- this.printDebounce();
2157
- }
2158
- );
2159
- return { unsubscribe };
2160
- }
2161
- async bondArgons(vaultId, amount, options) {
2162
- const client = await this.client;
2163
- const tx = client.tx.liquidityPools.bondArgons(vaultId, amount);
2164
- const txSubmitter = new TxSubmitter(client, tx, this.keypair);
2165
- const affordability = await txSubmitter.canAfford({
2166
- tip: options?.tip,
2167
- unavailableBalance: amount
2168
- });
2169
- if (!affordability.canAfford) {
2170
- console.warn("Insufficient balance to bond argons to liquidity pool", {
2171
- ...affordability,
2172
- argonsNeeded: amount
2173
- });
2174
- throw new Error("Insufficient balance to bond argons to liquidity pool");
2175
- }
2176
- const result = await txSubmitter.submit({
2177
- tip: options?.tip,
2178
- useLatestNonce: true
2179
- });
2180
- await result.inBlockPromise;
2181
- return result;
2182
- }
2183
- printDebounce() {
2184
- if (this.printTimeout) {
2185
- clearTimeout(this.printTimeout);
2186
- }
2187
- this.printTimeout = setTimeout(() => {
2188
- this.print();
2189
- }, 100);
2190
- }
2191
- getOperatorName(vaultId) {
2192
- const vault = this.vaultsById[vaultId];
2193
- return this.accountRegistry.getName(vault.operatorAccountId) ?? vault.operatorAccountId;
2194
- }
2195
- print() {
2196
- console.clear();
2197
- const lastDistributedFrameId = this.lastDistributedFrameId;
2198
- const distributedFrame = this.poolVaultCapitalByFrame[this.lastDistributedFrameId ?? -1] ?? {};
2199
- if (Object.keys(distributedFrame).length > 0) {
2200
- console.log(`
2201
-
2202
- Distributed (Frame ${lastDistributedFrameId})`);
2203
- const rows = [];
2204
- let maxWidth2 = 0;
2205
- for (const [key, entry] of Object.entries(distributedFrame)) {
2206
- const { table, width } = this.createBondCapitalTable(
2207
- entry.earnings ?? 0n,
2208
- entry.contributors ?? [],
2209
- `Earnings (shared = ${formatPercent(entry.vaultSharingPercent)})`
2210
- );
2211
- if (width > maxWidth2) {
2212
- maxWidth2 = width;
2213
- }
2214
- rows.push({
2215
- Vault: key,
2216
- Who: this.getOperatorName(Number(key)),
2217
- Balances: table
2218
- });
2219
- }
2220
- new Table({
2221
- columns: [
2222
- { name: "Vault", alignment: "left" },
2223
- { name: "Who", alignment: "left" },
2224
- {
2225
- name: "Balances",
2226
- title: "Contributor Balances",
2227
- alignment: "center",
2228
- minLen: maxWidth2
2229
- }
2230
- ],
2231
- rows
2232
- }).printTable();
2233
- }
2234
- console.log(
2235
- `
2236
-
2237
- Active Bid Pool: ${formatArgons(this.bidPoolAmount)} (Frame ${this.nextFrameId})`
2238
- );
2239
- const Frame = this.poolVaultCapitalByFrame[this.nextFrameId];
2240
- if (Object.keys(Frame ?? {}).length > 0) {
2241
- const rows = [];
2242
- let maxWidth2 = 0;
2243
- for (const [key, entry] of Object.entries(Frame)) {
2244
- const { table, width } = this.createBondCapitalTable(
2245
- entry.activatedCapital,
2246
- entry.contributors ?? []
2247
- );
2248
- if (width > maxWidth2) {
2249
- maxWidth2 = width;
2250
- }
2251
- rows.push({
2252
- Vault: key,
2253
- Who: this.getOperatorName(Number(key)),
2254
- "Pool Capital": table
2255
- });
2256
- }
2257
- new Table({
2258
- columns: [
2259
- { name: "Vault", alignment: "left" },
2260
- { name: "Who", alignment: "left" },
2261
- { name: "Pool Capital", alignment: "left", minLen: maxWidth2 }
2262
- ],
2263
- rows
2264
- }).printTable();
2265
- }
2266
- const raisingFunds = this.poolVaultCapitalByFrame[this.nextFrameId + 1] ?? [];
2267
- let maxWidth = 0;
2268
- const nextCapital = [];
2269
- for (const x of this.vaultSecuritization) {
2270
- const entry = raisingFunds[x.vaultId] ?? {};
2271
- const { table, width } = this.createBondCapitalTable(
2272
- x.activatedSecuritization,
2273
- entry.contributors ?? []
2274
- );
2275
- if (width > maxWidth) {
2276
- maxWidth = width;
2277
- }
2278
- nextCapital.push({
2279
- Vault: x.vaultId,
2280
- Owner: this.getOperatorName(x.vaultId),
2281
- "Bitcoin Space": formatArgons(x.bitcoinSpace),
2282
- "Activated Securitization": `${formatArgons(x.activatedSecuritization)} / slot`,
2283
- "Liquidity Pool": `${formatPercent(x.vaultSharingPercent)} profit sharing${table}`
2284
- });
2285
- }
2286
- if (nextCapital.length) {
2287
- console.log(`
2288
-
2289
- Raising Funds (Frame ${this.nextFrameId + 1}):`);
2290
- new Table({
2291
- columns: [
2292
- { name: "Vault", alignment: "left" },
2293
- { name: "Owner", alignment: "left" },
2294
- { name: "Bitcoin Space", alignment: "right" },
2295
- { name: "Activated Securitization", alignment: "right" },
2296
- { name: "Liquidity Pool", alignment: "left", minLen: maxWidth }
2297
- ],
2298
- rows: nextCapital
2299
- }).printTable();
2300
- }
2301
- }
2302
- setVaultFrameData(frameId, vaultId, data) {
2303
- var _a, _b;
2304
- this.poolVaultCapitalByFrame ?? (this.poolVaultCapitalByFrame = {});
2305
- (_a = this.poolVaultCapitalByFrame)[frameId] ?? (_a[frameId] = {});
2306
- (_b = this.poolVaultCapitalByFrame[frameId])[vaultId] ?? (_b[vaultId] = {
2307
- activatedCapital: data.activatedCapital ?? data.contributors?.reduce((a, b) => a + b.amount, 0n) ?? 0n
2308
- });
2309
- Object.assign(this.poolVaultCapitalByFrame[frameId][vaultId], filterUndefined(data));
2310
- }
2311
- createBondCapitalTable(total, contributors, title = "Total") {
2312
- const table = new Table({
2313
- style: EMPTY_TABLE,
2314
- columns: [
2315
- { name: "who", title, minLen: 10, alignment: "right" },
2316
- {
2317
- name: "amount",
2318
- title: formatArgons(total),
2319
- minLen: 7,
2320
- alignment: "left"
2321
- }
2322
- ]
2323
- });
2324
- for (const x of contributors) {
2325
- table.addRow({
2326
- who: this.accountRegistry.getName(x.address) ?? x.address,
2327
- amount: formatArgons(x.amount)
2328
- });
2329
- }
2330
- const str = table.render();
2331
- const width = str.indexOf("\n");
2332
- return { table: str, width };
2333
- }
2334
- loadFrameData(frameId, vaultFunds) {
2335
- for (const [vaultId, fund] of vaultFunds) {
2336
- const vaultIdNumber = vaultId.toNumber();
2337
- const contributors = fund.contributorBalances.map(([a, b]) => ({
2338
- address: a.toHuman(),
2339
- amount: b.toBigInt()
2340
- }));
2341
- if (fund.distributedProfits.isSome) {
2342
- if (frameId > (this.lastDistributedFrameId ?? 0)) {
2343
- this.lastDistributedFrameId = frameId;
2344
- }
2345
- }
2346
- this.setVaultFrameData(frameId, vaultIdNumber, {
2347
- earnings: fund.distributedProfits.isSome ? fund.distributedProfits.unwrap().toBigInt() : void 0,
2348
- vaultSharingPercent: convertPermillToBigNumber(fund.vaultSharingPercent.toBigInt()),
2349
- contributors
2350
- });
2351
- }
2352
- }
2353
- };
534
+ function toFixedNumber(value, decimals) {
535
+ const factor = new BigNumber2__default(10).pow(decimals);
536
+ const bn = new BigNumber2__default(value);
537
+ const int = bn.times(factor).integerValue(BigNumber2__default.ROUND_DOWN);
538
+ return BigInt(int.toFixed(0));
539
+ }
540
+ function fromFixedNumber(value, decimals = FIXED_U128_DECIMALS) {
541
+ const factor = new BigNumber2__default(10).pow(decimals);
542
+ const bn = new BigNumber2__default(value.toString());
543
+ return bn.div(factor);
544
+ }
545
+ var FIXED_U128_DECIMALS = 18;
546
+ var PERMILL_DECIMALS = 6;
2354
547
  var SATS_PER_BTC = 100000000n;
2355
- var BitcoinLocks = class _BitcoinLocks {
548
+ var BitcoinLocks = class {
2356
549
  constructor(client) {
2357
550
  this.client = client;
2358
551
  }
2359
552
  async getUtxoIdFromEvents(events) {
2360
- const client = await this.client;
2361
553
  for (const event of events) {
2362
- if (client.events.bitcoinLocks.BitcoinLockCreated.is(event)) {
554
+ if (this.client.events.bitcoinLocks.BitcoinLockCreated.is(event)) {
2363
555
  return event.data.utxoId.toNumber();
2364
556
  }
2365
557
  }
2366
558
  return void 0;
2367
559
  }
2368
- async getMarketRate(satoshis) {
2369
- const client = await this.client;
560
+ async getMarketRate(priceIndex, satoshis) {
561
+ return priceIndex.getBtcMicrogonPrice(satoshis);
562
+ }
563
+ async getRedemptionRate(priceIndex, details) {
564
+ const { satoshis, peggedPrice } = details;
565
+ const satsPerArgon = Number(SATS_PER_BTC) / MICROGONS_PER_ARGON;
566
+ let price = Number(priceIndex.btcUsdPrice);
567
+ price = price / satsPerArgon * Number(satoshis);
568
+ if (peggedPrice !== void 0 && peggedPrice < price) {
569
+ price = Number(peggedPrice);
570
+ }
571
+ const r = Number(priceIndex.rValue);
572
+ let multiplier;
573
+ if (r >= 1) {
574
+ multiplier = 1;
575
+ } else if (r >= 0.9) {
576
+ multiplier = 20 * (r * r) - 38 * r + 19;
577
+ } else if (r >= 0.01) {
578
+ multiplier = (0.5618 * r + 0.3944) / r;
579
+ } else {
580
+ multiplier = 1 / r * (0.576 * r + 0.4);
581
+ }
582
+ return BigInt(Math.floor(price * multiplier));
583
+ }
584
+ async getMarketRateApi(satoshis) {
585
+ const client = this.client;
2370
586
  const sats = client.createType("U64", satoshis.toString());
2371
587
  const marketRate = await client.rpc.state.call("BitcoinApis_market_rate", sats.toHex(true));
2372
588
  const rate = client.createType("Option<U128>", marketRate);
@@ -2375,8 +591,8 @@ var BitcoinLocks = class _BitcoinLocks {
2375
591
  }
2376
592
  return rate.value.toBigInt();
2377
593
  }
2378
- async getRedemptionRate(satoshis) {
2379
- const client = await this.client;
594
+ async getRedemptionRateApi(satoshis) {
595
+ const client = this.client;
2380
596
  const sats = client.createType("U64", satoshis.toString());
2381
597
  const marketRate = await client.rpc.state.call("BitcoinApis_redemption_rate", sats.toHex(true));
2382
598
  const rate = client.createType("Option<U128>", marketRate);
@@ -2386,7 +602,7 @@ var BitcoinLocks = class _BitcoinLocks {
2386
602
  return rate.value.toBigInt();
2387
603
  }
2388
604
  async getConfig() {
2389
- const client = await this.client;
605
+ const client = this.client;
2390
606
  const bitcoinNetwork = await client.query.bitcoinUtxos.bitcoinNetwork();
2391
607
  return {
2392
608
  lockReleaseCosignDeadlineFrames: client.consts.bitcoinLocks.lockReleaseCosignDeadlineFrames.toNumber(),
@@ -2396,24 +612,19 @@ var BitcoinLocks = class _BitcoinLocks {
2396
612
  };
2397
613
  }
2398
614
  async getBitcoinConfirmedBlockHeight() {
2399
- const client = await this.client;
2400
- return await client.query.bitcoinUtxos.confirmedBitcoinBlockTip().then((x) => x.value?.blockHeight.toNumber() ?? 0);
615
+ return await this.client.query.bitcoinUtxos.confirmedBitcoinBlockTip().then((x) => x.value?.blockHeight.toNumber() ?? 0);
2401
616
  }
2402
617
  /**
2403
618
  * Gets the UTXO reference by ID.
2404
619
  * @param utxoId - The UTXO ID to look up.
2405
- * @param atHeight - Optional block height to query the UTXO reference at a specific point in time.
620
+ * @param clientAtHeight - Optional client at the block height to query the UTXO reference at a specific point in time.
2406
621
  * @return An object containing the transaction ID and output index, or undefined if not found.
2407
622
  * @return.txid - The Bitcoin transaction ID of the UTXO.
2408
623
  * @return.vout - The output index of the UTXO in the transaction.
2409
624
  * @return.bitcoinTxid - The Bitcoin transaction ID of the UTXO formatted in little endian
2410
625
  */
2411
- async getUtxoRef(utxoId, atHeight) {
2412
- let client = await this.client;
2413
- if (atHeight !== void 0) {
2414
- const blockHash = await client.rpc.chain.getBlockHash(atHeight);
2415
- client = await client.at(blockHash);
2416
- }
626
+ async getUtxoRef(utxoId, clientAtHeight) {
627
+ const client = clientAtHeight ?? this.client;
2417
628
  const refRaw = await client.query.bitcoinUtxos.utxoIdToRef(utxoId);
2418
629
  if (!refRaw) {
2419
630
  return;
@@ -2424,12 +635,8 @@ var BitcoinLocks = class _BitcoinLocks {
2424
635
  const vout = ref.outputIndex.toNumber();
2425
636
  return { txid, vout, bitcoinTxid };
2426
637
  }
2427
- async getReleaseRequest(utxoId, atHeight) {
2428
- let client = await this.client;
2429
- if (atHeight !== void 0) {
2430
- const blockHash = await client.rpc.chain.getBlockHash(atHeight);
2431
- client = await client.at(blockHash);
2432
- }
638
+ async getReleaseRequest(utxoId, clientAtHeight) {
639
+ const client = clientAtHeight ?? this.client;
2433
640
  const requestMaybe = await client.query.bitcoinLocks.lockReleaseRequestsByUtxoId(utxoId);
2434
641
  if (!requestMaybe.isSome) {
2435
642
  return void 0;
@@ -2445,7 +652,7 @@ var BitcoinLocks = class _BitcoinLocks {
2445
652
  }
2446
653
  async submitVaultSignature(args) {
2447
654
  const { utxoId, vaultSignature, argonKeyring, txProgressCallback } = args;
2448
- const client = await this.client;
655
+ const client = this.client;
2449
656
  if (!vaultSignature || vaultSignature.byteLength < 70 || vaultSignature.byteLength > 73) {
2450
657
  throw new Error(
2451
658
  `Invalid vault signature length: ${vaultSignature.byteLength}. Must be 70-73 bytes.`
@@ -2457,8 +664,7 @@ var BitcoinLocks = class _BitcoinLocks {
2457
664
  return await submitter.submit({ txProgressCallback });
2458
665
  }
2459
666
  async getBitcoinLock(utxoId) {
2460
- const client = await this.client;
2461
- const utxoRaw = await client.query.bitcoinLocks.locksByUtxoId(utxoId);
667
+ const utxoRaw = await this.client.query.bitcoinLocks.locksByUtxoId(utxoId);
2462
668
  if (!utxoRaw.isSome) {
2463
669
  return;
2464
670
  }
@@ -2467,7 +673,8 @@ var BitcoinLocks = class _BitcoinLocks {
2467
673
  const wscriptHash = utxo.utxoScriptPubkey.asP2wsh.wscriptHash.toHex().replace("0x", "");
2468
674
  const p2wshScriptHashHex = `0x${p2shBytesPrefix}${wscriptHash}`;
2469
675
  const vaultId = utxo.vaultId.toNumber();
2470
- const lockPrice = utxo.lockPrice.toBigInt();
676
+ const peggedPrice = utxo.peggedPrice.toBigInt();
677
+ const liquidityPromised = utxo.liquidityPromised.toBigInt();
2471
678
  const ownerAccount = utxo.ownerAccount.toHuman();
2472
679
  const satoshis = utxo.satoshis.toBigInt();
2473
680
  const vaultPubkey = utxo.vaultPubkey.toHex();
@@ -2479,6 +686,7 @@ var BitcoinLocks = class _BitcoinLocks {
2479
686
  cosignHdIndex: cosign_hd_index.toNumber(),
2480
687
  claimHdIndex: claim_hd_index.toNumber()
2481
688
  };
689
+ const securityFees = utxo.securityFees.toBigInt();
2482
690
  const vaultClaimHeight = utxo.vaultClaimHeight.toNumber();
2483
691
  const openClaimHeight = utxo.openClaimHeight.toNumber();
2484
692
  const createdAtHeight = utxo.createdAtHeight.toNumber();
@@ -2491,7 +699,8 @@ var BitcoinLocks = class _BitcoinLocks {
2491
699
  utxoId,
2492
700
  p2wshScriptHashHex,
2493
701
  vaultId,
2494
- lockPrice,
702
+ peggedPrice,
703
+ liquidityPromised,
2495
704
  ownerAccount,
2496
705
  satoshis,
2497
706
  vaultPubkey,
@@ -2501,6 +710,7 @@ var BitcoinLocks = class _BitcoinLocks {
2501
710
  vaultClaimHeight,
2502
711
  openClaimHeight,
2503
712
  createdAtHeight,
713
+ securityFees,
2504
714
  isVerified,
2505
715
  isRejectedNeedsRelease,
2506
716
  fundHoldExtensionsByBitcoinExpirationHeight
@@ -2512,7 +722,7 @@ var BitcoinLocks = class _BitcoinLocks {
2512
722
  * @param waitForSignatureMillis - Optional timeout in milliseconds to wait for the signature. If -1, waits indefinitely.
2513
723
  */
2514
724
  async findVaultCosignSignature(utxoId, waitForSignatureMillis) {
2515
- const client = await this.client;
725
+ const client = this.client;
2516
726
  const releaseHeight = await client.query.bitcoinLocks.lockReleaseCosignHeightById(utxoId);
2517
727
  if (releaseHeight.isSome) {
2518
728
  const releaseHeightValue = releaseHeight.unwrap().toNumber();
@@ -2547,7 +757,7 @@ var BitcoinLocks = class _BitcoinLocks {
2547
757
  });
2548
758
  }
2549
759
  async blockHashAtHeight(atHeight) {
2550
- const client = await this.client;
760
+ const client = this.client;
2551
761
  for (let i = 0; i < 10; i++) {
2552
762
  const currentHeight = await client.query.system.number().then((x) => x.toNumber());
2553
763
  if (atHeight > currentHeight) {
@@ -2568,7 +778,7 @@ var BitcoinLocks = class _BitcoinLocks {
2568
778
  return void 0;
2569
779
  }
2570
780
  async getVaultCosignSignature(utxoId, atHeight) {
2571
- const client = await this.client;
781
+ const client = this.client;
2572
782
  const blockHash = await this.blockHashAtHeight(atHeight);
2573
783
  if (!blockHash) {
2574
784
  console.warn(`Block hash not found for height ${atHeight}`);
@@ -2586,8 +796,7 @@ var BitcoinLocks = class _BitcoinLocks {
2586
796
  return void 0;
2587
797
  }
2588
798
  async findPendingMints(utxoId) {
2589
- const client = await this.client;
2590
- const pendingMint = await client.query.mint.pendingMintUtxos();
799
+ const pendingMint = await this.client.query.mint.pendingMintUtxos();
2591
800
  const mintsPending = [];
2592
801
  for (const [utxoIdRaw, _accountId, mintAmountRaw] of pendingMint) {
2593
802
  if (utxoIdRaw.toNumber() === utxoId) {
@@ -2597,8 +806,8 @@ var BitcoinLocks = class _BitcoinLocks {
2597
806
  return mintsPending;
2598
807
  }
2599
808
  async createInitializeLockTx(args) {
2600
- const { vault, argonKeyring, satoshis, tip = 0n, ownerBitcoinPubkey } = args;
2601
- const client = await this.client;
809
+ const { vault, priceIndex, argonKeyring, satoshis, tip = 0n, ownerBitcoinPubkey } = args;
810
+ const client = this.client;
2602
811
  if (ownerBitcoinPubkey.length !== 33) {
2603
812
  throw new Error(
2604
813
  `Invalid Bitcoin key length: ${ownerBitcoinPubkey.length}. Must be a compressed pukey (33 bytes).`
@@ -2610,7 +819,7 @@ var BitcoinLocks = class _BitcoinLocks {
2610
819
  client.tx.bitcoinLocks.initialize(vault.vaultId, satoshis, ownerBitcoinPubkey),
2611
820
  argonKeyring
2612
821
  );
2613
- const marketPrice = await this.getMarketRate(BigInt(satoshis));
822
+ const marketPrice = await this.getMarketRate(priceIndex, satoshis);
2614
823
  const isVaultOwner = argonKeyring.address === vault.operatorAccountId;
2615
824
  const securityFee = isVaultOwner ? 0n : vault.calculateBitcoinFee(marketPrice);
2616
825
  const { canAfford, availableBalance, txFee } = await submitter.canAfford({
@@ -2626,7 +835,7 @@ var BitcoinLocks = class _BitcoinLocks {
2626
835
  return { tx, securityFee, txFee };
2627
836
  }
2628
837
  async getBitcoinLockFromTxResult(txResult) {
2629
- const client = await this.client;
838
+ const client = this.client;
2630
839
  const blockHash = await txResult.inBlockPromise;
2631
840
  const blockHeight = await client.at(blockHash).then((x) => x.query.system.number()).then((x) => x.toNumber());
2632
841
  const utxoId = await this.getUtxoIdFromEvents(txResult.events) ?? 0;
@@ -2641,7 +850,7 @@ var BitcoinLocks = class _BitcoinLocks {
2641
850
  }
2642
851
  async initializeLock(args) {
2643
852
  const { argonKeyring, tip = 0n, txProgressCallback } = args;
2644
- const client = await this.client;
853
+ const client = this.client;
2645
854
  const { tx, securityFee } = await this.createInitializeLockTx(args);
2646
855
  const submitter = new TxSubmitter(client, tx, argonKeyring);
2647
856
  const txResult = await submitter.submit({
@@ -2658,14 +867,15 @@ var BitcoinLocks = class _BitcoinLocks {
2658
867
  securityFee
2659
868
  };
2660
869
  }
2661
- async requiredSatoshisForArgonLiquidity(argonAmount) {
2662
- const marketRatePerBitcoin = await this.getMarketRate(SATS_PER_BTC);
870
+ async requiredSatoshisForArgonLiquidity(priceIndex, argonAmount) {
871
+ const marketRatePerBitcoin = priceIndex.getBtcMicrogonPrice(SATS_PER_BTC);
2663
872
  return argonAmount * SATS_PER_BTC / marketRatePerBitcoin;
2664
873
  }
2665
874
  async requestRelease(args) {
2666
- const client = await this.client;
875
+ const client = this.client;
2667
876
  const {
2668
877
  lock,
878
+ priceIndex,
2669
879
  releaseRequest: { bitcoinNetworkFee, toScriptPubkey },
2670
880
  argonKeyring,
2671
881
  tip,
@@ -2679,10 +889,7 @@ var BitcoinLocks = class _BitcoinLocks {
2679
889
  client.tx.bitcoinLocks.requestRelease(lock.utxoId, toScriptPubkey, bitcoinNetworkFee),
2680
890
  argonKeyring
2681
891
  );
2682
- let redemptionPrice = await this.getRedemptionRate(lock.satoshis);
2683
- if (redemptionPrice > lock.lockPrice) {
2684
- redemptionPrice = lock.lockPrice;
2685
- }
892
+ const redemptionPrice = await this.getRedemptionRate(priceIndex, lock);
2686
893
  const canAfford = await submitter.canAfford({
2687
894
  tip,
2688
895
  unavailableBalance: BigInt(redemptionPrice)
@@ -2705,21 +912,16 @@ var BitcoinLocks = class _BitcoinLocks {
2705
912
  blockHeight
2706
913
  };
2707
914
  }
2708
- async releasePrice(satoshis, lockPrice) {
2709
- await this.client;
2710
- const redemptionRate = await this.getRedemptionRate(satoshis);
2711
- if (redemptionRate > lockPrice) {
2712
- return redemptionRate;
2713
- }
2714
- return lockPrice;
915
+ async releasePrice(priceIndex, lock) {
916
+ return await this.getRedemptionRate(priceIndex, lock);
2715
917
  }
2716
- async getRatchetPrice(lock, vault) {
2717
- const { createdAtHeight, vaultClaimHeight, lockPrice, satoshis } = lock;
2718
- const client = await this.client;
2719
- const marketRate = await this.getMarketRate(BigInt(satoshis));
918
+ async getRatchetPrice(lock, priceIndex, vault) {
919
+ const { createdAtHeight, vaultClaimHeight, peggedPrice, satoshis } = lock;
920
+ const client = this.client;
921
+ const marketRate = await this.getMarketRate(priceIndex, BigInt(satoshis));
2720
922
  let ratchetingFee = vault.terms.bitcoinBaseFee;
2721
923
  let burnAmount = 0n;
2722
- if (marketRate > lockPrice) {
924
+ if (marketRate > peggedPrice) {
2723
925
  const lockFee = vault.calculateBitcoinFee(marketRate);
2724
926
  const currentBitcoinHeight = await client.query.bitcoinUtxos.confirmedBitcoinBlockTip().then((x) => x.unwrap().blockHeight.toNumber());
2725
927
  const blockLength = vaultClaimHeight - createdAtHeight;
@@ -2727,7 +929,7 @@ var BitcoinLocks = class _BitcoinLocks {
2727
929
  const remainingDuration = 1 - elapsed;
2728
930
  ratchetingFee = BigInt(remainingDuration * Number(lockFee));
2729
931
  } else {
2730
- burnAmount = await this.releasePrice(lock.satoshis, lockPrice);
932
+ burnAmount = await this.releasePrice(priceIndex, lock);
2731
933
  }
2732
934
  return {
2733
935
  ratchetingFee,
@@ -2736,9 +938,9 @@ var BitcoinLocks = class _BitcoinLocks {
2736
938
  };
2737
939
  }
2738
940
  async ratchet(args) {
2739
- const { lock, argonKeyring, tip = 0n, vault, txProgressCallback } = args;
2740
- const client = await this.client;
2741
- const ratchetPrice = await this.getRatchetPrice(lock, vault);
941
+ const { lock, priceIndex, argonKeyring, tip = 0n, vault, txProgressCallback } = args;
942
+ const client = this.client;
943
+ const ratchetPrice = await this.getRatchetPrice(lock, priceIndex, vault);
2742
944
  const txSubmitter = new TxSubmitter(
2743
945
  client,
2744
946
  client.tx.bitcoinLocks.ratchet(lock.utxoId),
@@ -2770,94 +972,99 @@ var BitcoinLocks = class _BitcoinLocks {
2770
972
  const api = await client.at(blockHash);
2771
973
  const blockHeight = await api.query.system.number().then((x) => x.toNumber());
2772
974
  const bitcoinBlockHeight = await api.query.bitcoinUtxos.confirmedBitcoinBlockTip().then((x) => x.unwrap().blockHeight.toNumber());
2773
- const { amountBurned, newLockPrice, originalLockPrice } = ratchetEvent.data;
2774
- let mintAmount = newLockPrice.toBigInt();
2775
- if (newLockPrice > originalLockPrice) {
2776
- mintAmount -= originalLockPrice.toBigInt();
975
+ const {
976
+ amountBurned,
977
+ liquidityPromised: liquidityPromisedRaw,
978
+ newPeggedPrice,
979
+ originalPeggedPrice
980
+ } = ratchetEvent.data;
981
+ const liquidityPromised = liquidityPromisedRaw.toBigInt();
982
+ let mintAmount = liquidityPromised;
983
+ if (liquidityPromised > originalPeggedPrice.toBigInt()) {
984
+ mintAmount -= originalPeggedPrice.toBigInt();
2777
985
  }
2778
986
  return {
2779
987
  txFee: submission.finalFee ?? 0n,
2780
988
  securityFee: ratchetPrice.ratchetingFee,
2781
989
  pendingMint: mintAmount,
2782
- newLockPrice: newLockPrice.toBigInt(),
990
+ liquidityPromised,
991
+ newPeggedPrice: newPeggedPrice.toBigInt(),
2783
992
  burned: amountBurned.toBigInt(),
2784
993
  blockHeight,
2785
994
  bitcoinBlockHeight
2786
995
  };
2787
996
  }
2788
- static async waitForSpace(accountset, options) {
2789
- const { argonAmount, bitcoinXpub, maxLockFee, tip = 0n } = options;
2790
- const vaults = new VaultMonitor(accountset, {
2791
- bitcoinSpaceAvailable: argonAmount
2792
- });
2793
- const bitcoinXpubBuffer = hexToU8a(bitcoinXpub);
2794
- return new Promise(async (resolve, reject) => {
2795
- vaults.events.on("bitcoin-space-above", async (vaultId, amount) => {
2796
- const vault = vaults.vaultsById[vaultId];
2797
- const fee = vault.calculateBitcoinFee(amount);
2798
- console.log(
2799
- `Vault ${vaultId} has ${formatArgons(amount)} argons available for bitcoin. Lock fee is ${formatArgons(fee)}`
2800
- );
2801
- if (maxLockFee !== void 0 && fee > maxLockFee) {
2802
- console.log(
2803
- `Skipping vault ${vaultId} due to high lock fee: ${formatArgons(maxLockFee)}`
2804
- );
2805
- return;
2806
- }
2807
- try {
2808
- const bitcoinLock = new _BitcoinLocks(accountset.client);
2809
- let satoshis = await bitcoinLock.requiredSatoshisForArgonLiquidity(amount);
2810
- satoshis -= options.satoshiWiggleRoomForDynamicPrice ?? 500n;
2811
- const { txResult, lock, securityFee } = await bitcoinLock.initializeLock({
2812
- vault,
2813
- satoshis,
2814
- argonKeyring: accountset.txSubmitterPair,
2815
- ownerBitcoinPubkey: bitcoinXpubBuffer,
2816
- tip
2817
- });
2818
- resolve({
2819
- satoshis,
2820
- argons: argonAmount,
2821
- vaultId,
2822
- securityFee,
2823
- txFee: txResult.finalFee,
2824
- finalizedPromise: txResult.finalizedPromise,
2825
- utxoId: lock.utxoId
2826
- });
2827
- } catch (err) {
2828
- console.error("Error submitting bitcoin lock tx:", err);
2829
- reject(err);
2830
- } finally {
2831
- vaults.stop();
2832
- }
2833
- });
2834
- await vaults.monitor();
2835
- });
997
+ };
998
+ var PriceIndex = class {
999
+ constructor() {
1000
+ __publicField(this, "btcUsdPrice");
1001
+ __publicField(this, "argonotUsdPrice");
1002
+ __publicField(this, "argonUsdPrice");
1003
+ __publicField(this, "argonUsdTargetPrice");
1004
+ __publicField(this, "argonTimeWeightedAverageLiquidity");
1005
+ __publicField(this, "lastUpdatedTick");
1006
+ }
1007
+ async load(client) {
1008
+ const current = await client.query.priceIndex.current();
1009
+ if (!current.isSome) {
1010
+ this.argonUsdPrice = void 0;
1011
+ this.argonotUsdPrice = void 0;
1012
+ this.btcUsdPrice = void 0;
1013
+ this.argonUsdTargetPrice = void 0;
1014
+ this.argonTimeWeightedAverageLiquidity = void 0;
1015
+ this.lastUpdatedTick = void 0;
1016
+ return this;
1017
+ }
1018
+ const value = current.unwrap();
1019
+ this.btcUsdPrice = fromFixedNumber(value.btcUsdPrice.toBigInt(), FIXED_U128_DECIMALS);
1020
+ this.argonotUsdPrice = fromFixedNumber(value.argonotUsdPrice.toBigInt(), FIXED_U128_DECIMALS);
1021
+ this.argonUsdPrice = fromFixedNumber(value.argonUsdPrice.toBigInt(), FIXED_U128_DECIMALS);
1022
+ this.argonUsdTargetPrice = fromFixedNumber(
1023
+ value.argonUsdTargetPrice.toBigInt(),
1024
+ FIXED_U128_DECIMALS
1025
+ );
1026
+ this.argonTimeWeightedAverageLiquidity = fromFixedNumber(
1027
+ value.argonTimeWeightedAverageLiquidity.toBigInt(),
1028
+ FIXED_U128_DECIMALS
1029
+ );
1030
+ this.lastUpdatedTick = value.tick.toNumber();
1031
+ return this;
1032
+ }
1033
+ getBtcMicrogonPrice(satoshis) {
1034
+ if (this.btcUsdPrice === void 0 || this.argonUsdPrice === void 0) {
1035
+ throw new Error("PriceIndex not loaded");
1036
+ }
1037
+ const satoshiCents = this.btcUsdPrice.multipliedBy(satoshis).dividedBy(SATS_PER_BTC);
1038
+ const microgons = satoshiCents.multipliedBy(MICROGONS_PER_ARGON).dividedBy(this.argonUsdPrice);
1039
+ return BigInt(microgons.integerValue(BigNumber2__default.ROUND_DOWN).toString());
1040
+ }
1041
+ get rValue() {
1042
+ if (this.argonUsdTargetPrice === void 0 || this.argonUsdPrice === void 0) {
1043
+ throw new Error("PriceIndex not loaded");
1044
+ }
1045
+ return this.argonUsdPrice.div(this.argonUsdTargetPrice);
1046
+ }
1047
+ get argonCpi() {
1048
+ if (this.argonUsdTargetPrice === void 0 || this.argonUsdPrice === void 0) {
1049
+ throw new Error("PriceIndex not loaded");
1050
+ }
1051
+ const ratio = this.argonUsdTargetPrice.div(this.argonUsdPrice);
1052
+ return ratio.minus(1);
2836
1053
  }
2837
1054
  };
2838
-
2839
- // src/keyringUtils.ts
2840
- function keyringFromSuri(suri, cryptoType = "sr25519") {
2841
- return new Keyring({ type: cryptoType }).createFromUri(suri);
2842
- }
2843
- function createKeyringPair(opts) {
2844
- const { cryptoType } = opts;
2845
- const seed = mnemonicGenerate();
2846
- return keyringFromSuri(seed, cryptoType);
2847
- }
2848
1055
  async function waitForLoad() {
2849
1056
  await cryptoWaitReady();
2850
1057
  }
2851
- async function getClient(host) {
1058
+ async function getClient(host, options) {
2852
1059
  let provider;
2853
1060
  if (host.startsWith("http")) {
2854
1061
  provider = new HttpProvider(host);
2855
1062
  } else {
2856
1063
  provider = new WsProvider(host);
2857
1064
  }
2858
- return await ApiPromise.create({ provider, noInitWarn: true });
1065
+ return await ApiPromise.create({ provider, noInitWarn: true, ...options ?? {} });
2859
1066
  }
2860
1067
 
2861
- export { AccountMiners, AccountRegistry, Accountset, BidPool, BitcoinLocks, BlockWatch, CohortBidder, ExtrinsicError2 as ExtrinsicError, FrameCalculator, JsonExt, MICROGONS_PER_ARGON, MiningBids, SATS_PER_BTC, TxResult, TxSubmitter, TypedEmitter, Vault, VaultMonitor, WageProtector, checkForExtrinsicSuccess, convertFixedU128ToBigNumber, convertNumberToFixedU128, convertNumberToPermill, convertPermillToBigNumber, createKeyringPair, createNanoEvents, dispatchErrorToExtrinsicError, dispatchErrorToString, eventDataToJson, filterUndefined, formatArgons, formatPercent, getAuthorFromHeader, getClient, getConfig, getTickFromHeader, gettersToObject, keyringFromSuri, miniSecretFromUri, setConfig, toFixedNumber, waitForLoad };
1068
+ export { BitcoinLocks, ExtrinsicError2 as ExtrinsicError, FIXED_U128_DECIMALS, MICROGONS_PER_ARGON, PERMILL_DECIMALS, PriceIndex, SATS_PER_BTC, TxResult, TxSubmitter, Vault, WageProtector, checkForExtrinsicSuccess, createKeyringPair, dispatchErrorToExtrinsicError, dispatchErrorToString, formatArgons, fromFixedNumber, getAuthorFromHeader, getClient, getTickFromHeader, gettersToObject, keyringFromSuri, toFixedNumber, waitForLoad };
2862
1069
  //# sourceMappingURL=index.js.map
2863
1070
  //# sourceMappingURL=index.js.map