@argonprotocol/mainchain 1.3.5 → 1.3.7

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,7 +9,7 @@ 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 { mnemonicGenerate, cryptoWaitReady } from '@polkadot/util-crypto';
12
+ import { keyExtractSuri, mnemonicToMiniSecret, ed25519DeriveHard, mnemonicGenerate, cryptoWaitReady } from '@polkadot/util-crypto';
13
13
  export { decodeAddress, mnemonicGenerate } from '@polkadot/util-crypto';
14
14
  import * as BigNumber from 'bignumber.js';
15
15
  import BigNumber__default from 'bignumber.js';
@@ -94,7 +94,7 @@ function getConfig() {
94
94
  return {
95
95
  debug: config.debug ?? getEnvVar("DEBUG") === "true",
96
96
  keysVersion: config.keysVersion ?? (getEnvVar("KEYS_VERSION") ? parseInt(getEnvVar("KEYS_VERSION")) : void 0),
97
- keysMnemonic: config.keysMnemonic ?? getEnvVar("KEYS_MNEMONIC"),
97
+ keySeedOrMnemonic: config.keySeedOrMnemonic ?? getEnvVar("KEYS_MNEMONIC"),
98
98
  subaccountRange: config.subaccountRange ?? getEnvVar("SUBACCOUNT_RANGE") ?? "0-9"
99
99
  };
100
100
  }
@@ -256,6 +256,15 @@ var TxResult = class {
256
256
  };
257
257
  var { ROUND_FLOOR } = BigNumber;
258
258
  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
+ }
259
268
  function formatArgons(microgons) {
260
269
  if (microgons === void 0 || microgons === null) return "na";
261
270
  const isNegative = microgons < 0;
@@ -399,7 +408,7 @@ var JsonExt = class {
399
408
  }
400
409
  static parse(str) {
401
410
  return JSON.parse(str, (_, v) => {
402
- if (typeof v === "string" && v.match(/^\d+n$/)) {
411
+ if (typeof v === "string" && v.match(/^-?\d+n$/)) {
403
412
  return BigInt(v.slice(0, -1));
404
413
  }
405
414
  if (typeof v === "object" && v !== null && v.type === "Buffer" && Array.isArray(v.data)) {
@@ -637,10 +646,14 @@ BLOCK #${header.number}, ${header.hash.toHuman()}`);
637
646
  };
638
647
 
639
648
  // src/FrameCalculator.ts
640
- var FrameCalculator = class {
649
+ var FrameCalculator = class _FrameCalculator {
641
650
  constructor() {
642
651
  __publicField(this, "miningConfig");
643
652
  __publicField(this, "genesisTick");
653
+ __publicField(this, "tickMillis");
654
+ }
655
+ async load(client) {
656
+ return await this.getConfig(client);
644
657
  }
645
658
  async getForTick(client, tick) {
646
659
  const { ticksBetweenFrames, biddingStartTick } = await this.getConfig(client);
@@ -649,9 +662,10 @@ var FrameCalculator = class {
649
662
  }
650
663
  async getTickRangeForFrame(client, frameId) {
651
664
  const { ticksBetweenFrames, biddingStartTick } = await this.getConfig(client);
652
- const startingTick = biddingStartTick + Math.floor(frameId * ticksBetweenFrames);
653
- const endingTick = startingTick + ticksBetweenFrames - 1;
654
- return [startingTick, endingTick];
665
+ return _FrameCalculator.calculateTickRangeForFrame(frameId, {
666
+ ticksBetweenFrames,
667
+ biddingStartTick
668
+ });
655
669
  }
656
670
  async getForHeader(client, header) {
657
671
  if (header.number.toNumber() === 0) return 0;
@@ -659,18 +673,30 @@ var FrameCalculator = class {
659
673
  if (tick === void 0) return void 0;
660
674
  return this.getForTick(client, tick);
661
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
+ }
662
686
  async getConfig(client) {
663
687
  this.miningConfig ?? (this.miningConfig = await client.query.miningSlot.miningConfig().then((x) => ({
664
688
  ticksBetweenSlots: x.ticksBetweenSlots.toNumber(),
665
689
  slotBiddingStartAfterTicks: x.slotBiddingStartAfterTicks.toNumber()
666
690
  })));
667
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()));
668
693
  const config2 = this.miningConfig;
669
694
  const genesisTick = this.genesisTick;
670
695
  return {
671
696
  ticksBetweenFrames: config2.ticksBetweenSlots,
672
697
  slotBiddingStartAfterTicks: config2.slotBiddingStartAfterTicks,
673
698
  genesisTick,
699
+ tickMillis: this.tickMillis,
674
700
  biddingStartTick: genesisTick + config2.slotBiddingStartAfterTicks
675
701
  };
676
702
  }
@@ -804,7 +830,7 @@ var Accountset = class {
804
830
  __publicField(this, "subAccountsByAddress", {});
805
831
  __publicField(this, "accountRegistry");
806
832
  __publicField(this, "client");
807
- __publicField(this, "sessionKeyMnemonic");
833
+ __publicField(this, "sessionKeySeed");
808
834
  if ("seedAccount" in options) {
809
835
  this.txSubmitterPair = options.seedAccount;
810
836
  this.seedAddress = options.seedAccount.address;
@@ -814,7 +840,7 @@ var Accountset = class {
814
840
  this.txSubmitterPair = options.txSubmitter;
815
841
  this.seedAddress = options.seedAddress;
816
842
  }
817
- this.sessionKeyMnemonic = options.sessionKeyMnemonic;
843
+ this.sessionKeySeed = options.sessionKeySeedOrMnemonic;
818
844
  this.accountRegistry = options.accountRegistry ?? AccountRegistry.factory(options.name);
819
845
  this.client = options.client;
820
846
  const defaultRange = options.subaccountRange ?? getDefaultSubaccountRange();
@@ -901,7 +927,6 @@ var Accountset = class {
901
927
  ];
902
928
  const bidAmountsByFrame = {};
903
929
  if (frameIds.length) {
904
- console.log("Looking up cohorts for frames", frameIds);
905
930
  const cohorts = await api.query.miningSlot.minersByCohort.multi(frameIds);
906
931
  for (let i = 0; i < frameIds.length; i++) {
907
932
  const cohort = cohorts[i];
@@ -1059,12 +1084,12 @@ var Accountset = class {
1059
1084
  keys(keysVersion) {
1060
1085
  const config2 = getConfig();
1061
1086
  let version = keysVersion ?? config2.keysVersion ?? 0;
1062
- const seedMnemonic = this.sessionKeyMnemonic ?? config2.keysMnemonic;
1063
- if (!seedMnemonic) {
1087
+ const seed = this.sessionKeySeed ?? config2.keySeedOrMnemonic;
1088
+ if (!seed) {
1064
1089
  throw new Error("KEYS_MNEMONIC environment variable not set. Cannot derive keys.");
1065
1090
  }
1066
- const blockSealKey = `${seedMnemonic}//block-seal//${version}`;
1067
- const granKey = `${seedMnemonic}//grandpa//${version}`;
1091
+ const blockSealKey = `${seed}//block-seal//${version}`;
1092
+ const granKey = `${seed}//grandpa//${version}`;
1068
1093
  const blockSealAccount = new Keyring().createFromUri(blockSealKey, {
1069
1094
  type: "ed25519"
1070
1095
  });
@@ -1646,29 +1671,35 @@ var VaultMonitor = class {
1646
1671
 
1647
1672
  // src/CohortBidder.ts
1648
1673
  var CohortBidder = class {
1649
- constructor(accountset, cohortStartingFrameId, subaccounts, options) {
1674
+ constructor(accountset, cohortStartingFrameId, subaccounts, options, callbacks) {
1650
1675
  this.accountset = accountset;
1651
1676
  this.cohortStartingFrameId = cohortStartingFrameId;
1652
1677
  this.subaccounts = subaccounts;
1653
1678
  this.options = options;
1679
+ this.callbacks = callbacks;
1654
1680
  __publicField(this, "txFees", 0n);
1681
+ __publicField(this, "bidsAttempted", 0);
1655
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
+ });
1656
1690
  __publicField(this, "unsubscribe");
1657
1691
  __publicField(this, "pendingRequest");
1658
- __publicField(this, "retryTimeout");
1659
1692
  __publicField(this, "isStopped", false);
1660
- __publicField(this, "needsRebid", false);
1661
- __publicField(this, "lastBidTime", 0);
1662
1693
  __publicField(this, "millisPerTick");
1663
1694
  __publicField(this, "minIncrement", 10000n);
1664
1695
  __publicField(this, "nextCohortSize");
1665
- __publicField(this, "lastBidBlockNumber", 0);
1666
- __publicField(this, "myAddresses", /* @__PURE__ */ new Set());
1696
+ __publicField(this, "lastBidTick", 0);
1697
+ __publicField(this, "evaluateInterval");
1667
1698
  this.subaccounts.forEach((x) => {
1668
1699
  this.myAddresses.add(x.address);
1669
1700
  });
1670
1701
  }
1671
- get client() {
1702
+ get clientPromise() {
1672
1703
  return this.accountset.client;
1673
1704
  }
1674
1705
  async start() {
@@ -1680,7 +1711,7 @@ var CohortBidder = class {
1680
1711
  bidDelay: this.options.bidDelay,
1681
1712
  subaccounts: this.subaccounts
1682
1713
  });
1683
- const client = await this.client;
1714
+ const client = await this.clientPromise;
1684
1715
  this.minIncrement = client.consts.miningSlot.bidIncrements.toBigInt();
1685
1716
  this.nextCohortSize = await client.query.miningSlot.nextCohortSize().then((x) => x.toNumber());
1686
1717
  if (this.subaccounts.length > this.nextCohortSize) {
@@ -1690,14 +1721,22 @@ var CohortBidder = class {
1690
1721
  this.subaccounts.length = this.nextCohortSize;
1691
1722
  }
1692
1723
  this.millisPerTick = await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1724
+ let didStart = false;
1693
1725
  this.unsubscribe = await client.queryMulti(
1694
1726
  [
1695
1727
  client.query.miningSlot.bidsForNextSlotCohort,
1696
- client.query.miningSlot.nextFrameId
1728
+ client.query.miningSlot.nextFrameId,
1729
+ client.query.ticks.currentTick,
1730
+ client.query.system.number
1697
1731
  ],
1698
- async ([bids, nextFrameId]) => {
1732
+ async ([rawBids, nextFrameId, currentTick, blockNumber]) => {
1699
1733
  if (nextFrameId.toNumber() === this.cohortStartingFrameId) {
1700
- await this.checkWinningBids(bids);
1734
+ this.updateBidList(rawBids, blockNumber.toNumber(), currentTick.toNumber());
1735
+ if (!didStart) {
1736
+ didStart = true;
1737
+ this.scheduleEvaluation();
1738
+ void this.checkWinningBids();
1739
+ }
1701
1740
  }
1702
1741
  }
1703
1742
  );
@@ -1705,12 +1744,12 @@ var CohortBidder = class {
1705
1744
  async stop() {
1706
1745
  if (this.isStopped) return this.winningBids;
1707
1746
  this.isStopped = true;
1747
+ clearInterval(this.evaluateInterval);
1708
1748
  console.log("Stopping bidder for cohort", this.cohortStartingFrameId);
1709
- clearTimeout(this.retryTimeout);
1710
1749
  if (this.unsubscribe) {
1711
1750
  this.unsubscribe();
1712
1751
  }
1713
- const client = await this.client;
1752
+ const client = await this.clientPromise;
1714
1753
  const [nextFrameId, isBiddingOpen] = await client.queryMulti([
1715
1754
  client.query.miningSlot.nextFrameId,
1716
1755
  client.query.miningSlot.isNextSlotBiddingOpen
@@ -1727,58 +1766,63 @@ var CohortBidder = class {
1727
1766
  });
1728
1767
  }
1729
1768
  void await this.pendingRequest;
1730
- let header = await client.rpc.chain.getHeader();
1731
- let api = await client.at(header.hash);
1732
- while (true) {
1733
- const cohortStartingFrameId = await api.query.miningSlot.nextFrameId();
1734
- if (cohortStartingFrameId.toNumber() === this.cohortStartingFrameId) {
1735
- break;
1736
- }
1737
- header = await client.rpc.chain.getHeader(header.parentHash);
1738
- api = await client.at(header.hash);
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());
1739
1775
  }
1740
- const bids = await api.query.miningSlot.bidsForNextSlotCohort();
1741
- this.updateSeatsWon(bids);
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);
1742
1781
  console.log("Bidder stopped", {
1743
1782
  cohortStartingFrameId: this.cohortStartingFrameId,
1744
- blockNumber: header.number.toNumber(),
1745
- bids: this.winningBids
1783
+ blockNumber,
1784
+ winningBids: this.winningBids
1746
1785
  });
1747
1786
  return this.winningBids;
1748
1787
  }
1749
- async checkWinningBids(bids) {
1788
+ async checkWinningBids() {
1750
1789
  if (this.isStopped) return;
1751
- clearTimeout(this.retryTimeout);
1752
- this.updateSeatsWon(bids);
1753
- const winningBids = this.winningBids.length;
1754
- this.needsRebid = winningBids < this.subaccounts.length;
1755
- const client = await this.client;
1756
- const bestBlock = await client.rpc.chain.getBlockHash();
1757
- const api = await client.at(bestBlock);
1758
- const blockNumber = await api.query.system.number().then((x) => x.toNumber());
1759
- if (this.lastBidBlockNumber >= blockNumber) return;
1760
- if (this.pendingRequest) return;
1761
- const ticksSinceLastBid = Math.floor((Date.now() - this.lastBidTime) / this.millisPerTick);
1762
- if (ticksSinceLastBid < this.options.bidDelay && this.needsRebid) {
1763
- this.retryTimeout = setTimeout(() => void this.checkCurrentSeats(), this.millisPerTick);
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}).`);
1764
1807
  return;
1765
1808
  }
1766
- if (!this.needsRebid) return;
1767
1809
  console.log(
1768
- "Checking bids for cohort",
1769
- this.cohortStartingFrameId,
1770
- this.subaccounts.map((x) => x.index)
1810
+ `Checking bids for cohort ${this.cohortStartingFrameId}, Still trying for seats: ${this.subaccounts.length}`
1771
1811
  );
1772
- const winningAddresses = new Set(bids.map((x) => x.accountId.toHuman()));
1773
- let lowestBid = -this.options.bidIncrement;
1774
- if (bids.length) {
1775
- for (let i = bids.length - 1; i >= 0; i--) {
1776
- if (!this.myAddresses.has(bids[i].accountId.toHuman())) {
1777
- lowestBid = bids.at(i).bid.toBigInt();
1778
- break;
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;
1779
1822
  }
1780
1823
  }
1781
1824
  }
1825
+ lowestBid ?? (lowestBid = -this.options.bidIncrement);
1782
1826
  let nextBid = lowestBid + this.options.bidIncrement;
1783
1827
  if (nextBid < this.options.minBid) {
1784
1828
  nextBid = this.options.minBid;
@@ -1790,39 +1834,59 @@ var CohortBidder = class {
1790
1834
  subaccounts: this.subaccounts,
1791
1835
  bidAmount: nextBid
1792
1836
  });
1793
- let availableBalanceForBids = await api.query.system.account(this.accountset.txSubmitterPair.address).then((x) => x.data.free.toBigInt());
1794
- for (const bid of bids) {
1795
- if (this.myAddresses.has(bid.accountId.toHuman())) {
1796
- availableBalanceForBids += bid.bid.toBigInt();
1797
- }
1798
- }
1837
+ let availableBalanceForBids = await this.accountset.submitterBalance();
1838
+ availableBalanceForBids += myAllocatedBids;
1799
1839
  const tip = this.options.tipPerTransaction ?? 0n;
1800
1840
  const feeEstimate = await fakeTx.feeEstimate(tip);
1801
- const feePlusTip = feeEstimate + tip;
1802
- let budgetForSeats = this.options.maxBudget - feePlusTip;
1841
+ const estimatedFeePlusTip = feeEstimate + tip;
1842
+ let budgetForSeats = this.options.maxBudget - estimatedFeePlusTip;
1803
1843
  if (budgetForSeats > availableBalanceForBids) {
1804
- budgetForSeats = availableBalanceForBids - feePlusTip;
1844
+ budgetForSeats = availableBalanceForBids - estimatedFeePlusTip;
1805
1845
  }
1806
1846
  if (nextBid < lowestBid) {
1807
1847
  console.log(
1808
- `Can't bid ${formatArgons(nextBid)}. Current lowest bid is ${formatArgons(lowestBid)}.`
1848
+ `Next bid within parameters is ${formatArgons(nextBid)}, but it's not enough. Current lowest bid is ${formatArgons(lowestBid)}.`
1809
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
+ });
1810
1858
  return;
1811
1859
  }
1812
1860
  if (nextBid - lowestBid < Number(this.minIncrement)) {
1813
1861
  console.log(
1814
- `Can't make any more bids for ${this.cohortStartingFrameId} with given constraints.`,
1862
+ `Can't make any more bids for ${this.cohortStartingFrameId} with given constraints (next bid below min increment).`,
1815
1863
  {
1816
1864
  lowestCurrentBid: formatArgons(lowestBid),
1817
1865
  nextAttemptedBid: formatArgons(nextBid),
1818
1866
  maxBid: formatArgons(this.options.maxBid)
1819
1867
  }
1820
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
+ });
1821
1877
  return;
1822
1878
  }
1823
1879
  const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(budgetForSeats / nextBid);
1824
1880
  let accountsToUse = [...this.subaccounts];
1825
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
+ });
1826
1890
  accountsToUse.sort((a, b) => {
1827
1891
  const isWinningA = winningAddresses.has(a.address);
1828
1892
  const isWinningB = winningAddresses.has(b.address);
@@ -1834,18 +1898,16 @@ var CohortBidder = class {
1834
1898
  });
1835
1899
  accountsToUse.length = seatsInBudget;
1836
1900
  }
1837
- if (accountsToUse.length > winningBids) {
1838
- this.pendingRequest = this.bid(nextBid, accountsToUse);
1901
+ if (accountsToUse.length > winningBids.length) {
1902
+ this.pendingRequest = this.submitBids(nextBid, accountsToUse);
1839
1903
  }
1840
- this.needsRebid = false;
1841
1904
  }
1842
- async bid(bidPerSeat, subaccounts) {
1843
- const prevLastBidTime = this.lastBidTime;
1905
+ async submitBids(microgonsPerSeat, subaccounts) {
1844
1906
  try {
1845
- this.lastBidTime = Date.now();
1907
+ this.bidsAttempted += subaccounts.length;
1846
1908
  const submitter = await this.accountset.createMiningBidTx({
1847
1909
  subaccounts,
1848
- bidAmount: bidPerSeat
1910
+ bidAmount: microgonsPerSeat
1849
1911
  });
1850
1912
  const tip = this.options.tipPerTransaction ?? 0n;
1851
1913
  const txResult = await submitter.submit({
@@ -1853,50 +1915,109 @@ var CohortBidder = class {
1853
1915
  useLatestNonce: true
1854
1916
  });
1855
1917
  const bidError = await txResult.inBlockPromise.then(() => void 0).catch((x) => x);
1856
- let blockNumber;
1857
- if (txResult.includedInBlock) {
1858
- const client = await this.client;
1859
- const api = await client.at(txResult.includedInBlock);
1860
- blockNumber = await api.query.system.number().then((x) => x.toNumber());
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);
1861
1933
  }
1862
1934
  const successfulBids = txResult.batchInterruptedIndex ?? subaccounts.length;
1863
1935
  this.txFees += txResult.finalFee ?? 0n;
1864
- if (blockNumber !== void 0) {
1865
- this.lastBidBlockNumber = Math.max(blockNumber, this.lastBidBlockNumber);
1866
- }
1867
- console.log("Done creating bids for cohort", {
1936
+ console.log("Result of bids for cohort", {
1868
1937
  successfulBids,
1869
- bidPerSeat,
1870
- blockNumber
1938
+ bidsPlaced: subaccounts.length,
1939
+ bidPerSeat: formatArgons(microgonsPerSeat),
1940
+ bidAtTick
1871
1941
  });
1872
- if (bidError) throw bidError;
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
+ }
1873
1957
  } catch (err) {
1874
- this.lastBidTime = prevLastBidTime;
1875
1958
  console.error(`Error bidding for cohort ${this.cohortStartingFrameId}:`, err);
1876
- clearTimeout(this.retryTimeout);
1877
- this.retryTimeout = setTimeout(() => void this.checkCurrentSeats(), 1e3);
1878
1959
  } finally {
1879
1960
  this.pendingRequest = void 0;
1880
- }
1881
- if (this.needsRebid) {
1882
- this.needsRebid = false;
1883
- await this.checkCurrentSeats();
1961
+ this.scheduleEvaluation();
1884
1962
  }
1885
1963
  }
1886
- updateSeatsWon(next) {
1887
- this.winningBids.length = 0;
1888
- for (const x of next) {
1889
- const bid = x.bid.toBigInt();
1890
- const address = x.accountId.toHuman();
1891
- if (this.myAddresses.has(address)) {
1892
- this.winningBids.push({ address, bid });
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
+ }
1893
2010
  }
2011
+ } catch (err) {
2012
+ console.error("Error processing updated bids list:", err);
1894
2013
  }
1895
2014
  }
1896
- async checkCurrentSeats() {
1897
- const client = await this.client;
1898
- const bids = await client.query.miningSlot.bidsForNextSlotCohort();
1899
- await this.checkWinningBids(bids);
2015
+ safeRecordParamsAdjusted(args) {
2016
+ try {
2017
+ this.callbacks?.onBidParamsAdjusted?.(args);
2018
+ } catch (err) {
2019
+ console.error("Error in onBidParamsAdjusted callback:", err);
2020
+ }
1900
2021
  }
1901
2022
  };
1902
2023
  var EMPTY_TABLE = {
@@ -2268,7 +2389,7 @@ var BitcoinLocks = class _BitcoinLocks {
2268
2389
  const client = await this.client;
2269
2390
  const bitcoinNetwork = await client.query.bitcoinUtxos.bitcoinNetwork();
2270
2391
  return {
2271
- releaseExpirationBlocks: client.consts.bitcoinLocks.lockReleaseCosignDeadlineBlocks.toNumber(),
2392
+ lockReleaseCosignDeadlineFrames: client.consts.bitcoinLocks.lockReleaseCosignDeadlineFrames.toNumber(),
2272
2393
  pendingConfirmationExpirationBlocks: client.consts.bitcoinUtxos.maxPendingConfirmationBlocks.toNumber(),
2273
2394
  tickDurationMillis: await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber()),
2274
2395
  bitcoinNetwork
@@ -2309,19 +2430,18 @@ var BitcoinLocks = class _BitcoinLocks {
2309
2430
  const blockHash = await client.rpc.chain.getBlockHash(atHeight);
2310
2431
  client = await client.at(blockHash);
2311
2432
  }
2312
- const locksPendingRelease = await client.query.bitcoinLocks.locksPendingReleaseByUtxoId();
2313
- for (const [id, request] of locksPendingRelease.entries()) {
2314
- if (id.toNumber() === utxoId) {
2315
- return {
2316
- toScriptPubkey: request.toScriptPubkey.toHex(),
2317
- bitcoinNetworkFee: request.bitcoinNetworkFee.toBigInt(),
2318
- dueBlockHeight: request.cosignDueBlock.toNumber(),
2319
- vaultId: request.vaultId.toNumber(),
2320
- redemptionPrice: request.redemptionPrice.toBigInt()
2321
- };
2322
- }
2433
+ const requestMaybe = await client.query.bitcoinLocks.lockReleaseRequestsByUtxoId(utxoId);
2434
+ if (!requestMaybe.isSome) {
2435
+ return void 0;
2323
2436
  }
2324
- return void 0;
2437
+ const request = requestMaybe.unwrap();
2438
+ return {
2439
+ toScriptPubkey: request.toScriptPubkey.toHex(),
2440
+ bitcoinNetworkFee: request.bitcoinNetworkFee.toBigInt(),
2441
+ dueFrame: request.cosignDueFrame.toNumber(),
2442
+ vaultId: request.vaultId.toNumber(),
2443
+ redemptionPrice: request.redemptionPrice.toBigInt()
2444
+ };
2325
2445
  }
2326
2446
  async submitVaultSignature(args) {
2327
2447
  const { utxoId, vaultSignature, argonKeyring, txProgressCallback } = args;
@@ -2491,7 +2611,8 @@ var BitcoinLocks = class _BitcoinLocks {
2491
2611
  argonKeyring
2492
2612
  );
2493
2613
  const marketPrice = await this.getMarketRate(BigInt(satoshis));
2494
- const securityFee = vault.calculateBitcoinFee(marketPrice);
2614
+ const isVaultOwner = argonKeyring.address === vault.operatorAccountId;
2615
+ const securityFee = isVaultOwner ? 0n : vault.calculateBitcoinFee(marketPrice);
2495
2616
  const { canAfford, availableBalance, txFee } = await submitter.canAfford({
2496
2617
  tip,
2497
2618
  unavailableBalance: securityFee + (args.reducedBalanceBy ?? 0n),
@@ -2504,17 +2625,8 @@ var BitcoinLocks = class _BitcoinLocks {
2504
2625
  }
2505
2626
  return { tx, securityFee, txFee };
2506
2627
  }
2507
- async initializeLock(args) {
2508
- const { argonKeyring, tip = 0n, txProgressCallback } = args;
2628
+ async getBitcoinLockFromTxResult(txResult) {
2509
2629
  const client = await this.client;
2510
- const { tx, securityFee } = await this.createInitializeLockTx(args);
2511
- const submitter = new TxSubmitter(client, tx, argonKeyring);
2512
- const txResult = await submitter.submit({
2513
- waitForBlock: true,
2514
- logResults: true,
2515
- tip,
2516
- txProgressCallback
2517
- });
2518
2630
  const blockHash = await txResult.inBlockPromise;
2519
2631
  const blockHeight = await client.at(blockHash).then((x) => x.query.system.number()).then((x) => x.toNumber());
2520
2632
  const utxoId = await this.getUtxoIdFromEvents(txResult.events) ?? 0;
@@ -2525,7 +2637,26 @@ var BitcoinLocks = class _BitcoinLocks {
2525
2637
  if (!lock) {
2526
2638
  throw new Error(`Lock with ID ${utxoId} not found after initialization`);
2527
2639
  }
2528
- return { lock, createdAtHeight: blockHeight, txResult, securityFee };
2640
+ return { lock, createdAtHeight: blockHeight, txResult };
2641
+ }
2642
+ async initializeLock(args) {
2643
+ const { argonKeyring, tip = 0n, txProgressCallback } = args;
2644
+ const client = await this.client;
2645
+ const { tx, securityFee } = await this.createInitializeLockTx(args);
2646
+ const submitter = new TxSubmitter(client, tx, argonKeyring);
2647
+ const txResult = await submitter.submit({
2648
+ waitForBlock: true,
2649
+ logResults: true,
2650
+ tip,
2651
+ txProgressCallback
2652
+ });
2653
+ const { lock, createdAtHeight } = await this.getBitcoinLockFromTxResult(txResult);
2654
+ return {
2655
+ lock,
2656
+ createdAtHeight,
2657
+ txResult,
2658
+ securityFee
2659
+ };
2529
2660
  }
2530
2661
  async requiredSatoshisForArgonLiquidity(argonAmount) {
2531
2662
  const marketRatePerBitcoin = await this.getMarketRate(SATS_PER_BTC);
@@ -2727,6 +2858,6 @@ async function getClient(host) {
2727
2858
  return await ApiPromise.create({ provider, noInitWarn: true });
2728
2859
  }
2729
2860
 
2730
- 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, setConfig, toFixedNumber, waitForLoad };
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 };
2731
2862
  //# sourceMappingURL=index.js.map
2732
2863
  //# sourceMappingURL=index.js.map