@argonprotocol/mainchain 1.1.0-rc.6 → 1.1.0-rc.8

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.
@@ -60,8 +60,10 @@ __export(index_exports, {
60
60
  BitcoinLocks: () => BitcoinLocks,
61
61
  BlockWatch: () => BlockWatch,
62
62
  CohortBidder: () => CohortBidder,
63
+ ExtrinsicError: () => ExtrinsicError2,
63
64
  JsonExt: () => JsonExt,
64
65
  Keyring: () => import_api.Keyring,
66
+ MICROGONS_PER_ARGON: () => MICROGONS_PER_ARGON,
65
67
  MiningBids: () => MiningBids,
66
68
  MiningRotations: () => MiningRotations,
67
69
  TxSubmitter: () => TxSubmitter,
@@ -73,6 +75,7 @@ __export(index_exports, {
73
75
  convertPermillToBigNumber: () => convertPermillToBigNumber,
74
76
  createKeyringPair: () => createKeyringPair,
75
77
  decodeAddress: () => import_util_crypto.decodeAddress,
78
+ dispatchErrorToExtrinsicError: () => dispatchErrorToExtrinsicError,
76
79
  dispatchErrorToString: () => dispatchErrorToString,
77
80
  eventDataToJson: () => eventDataToJson,
78
81
  filterUndefined: () => filterUndefined,
@@ -171,119 +174,6 @@ var WageProtector = class _WageProtector {
171
174
  }
172
175
  };
173
176
 
174
- // src/utils.ts
175
- var BN = __toESM(require("bignumber.js"), 1);
176
- var { ROUND_FLOOR } = BN;
177
- function formatArgons(x) {
178
- const isNegative = x < 0;
179
- let format = (0, BN.default)(x.toString()).abs().div(1e6).toFormat(2, ROUND_FLOOR);
180
- if (format.endsWith(".00")) {
181
- format = format.slice(0, -3);
182
- }
183
- return `${isNegative ? "-" : ""}\u20B3${format}`;
184
- }
185
- function formatPercent(x) {
186
- if (!x) return "na";
187
- return `${x.times(100).decimalPlaces(3)}%`;
188
- }
189
- function filterUndefined(obj) {
190
- return Object.fromEntries(
191
- Object.entries(obj).filter(
192
- ([_, value]) => value !== void 0 && value !== null
193
- )
194
- );
195
- }
196
- async function gettersToObject(obj) {
197
- if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
198
- const keys = [];
199
- for (const key in obj) {
200
- keys.push(key);
201
- }
202
- if (Symbol.iterator in obj) {
203
- const iterableToArray = [];
204
- for (const item of obj) {
205
- iterableToArray.push(await gettersToObject(item));
206
- }
207
- return iterableToArray;
208
- }
209
- const result = {};
210
- for (const key of keys) {
211
- const descriptor = Object.getOwnPropertyDescriptor(obj, key);
212
- if (descriptor && typeof descriptor.value === "function") {
213
- continue;
214
- }
215
- const value = descriptor && descriptor.get ? descriptor.get.call(obj) : obj[key];
216
- if (typeof value === "function") continue;
217
- result[key] = await gettersToObject(value);
218
- }
219
- return result;
220
- }
221
- function convertFixedU128ToBigNumber(fixedU128) {
222
- const decimalFactor = new BN.default(10).pow(new BN.default(18));
223
- const rawValue = new BN.default(fixedU128.toString());
224
- return rawValue.div(decimalFactor);
225
- }
226
- function convertPermillToBigNumber(permill) {
227
- const decimalFactor = new BN.default(1e6);
228
- const rawValue = new BN.default(permill.toString());
229
- return rawValue.div(decimalFactor);
230
- }
231
- function eventDataToJson(event) {
232
- const obj = {};
233
- event.data.forEach((data, index) => {
234
- const name = event.data.names?.[index];
235
- obj[name ?? `${index}`] = data.toJSON();
236
- });
237
- return obj;
238
- }
239
- function dispatchErrorToString(client, error) {
240
- let message = error.toString();
241
- if (error.isModule) {
242
- const decoded = client.registry.findMetaError(error.asModule);
243
- const { docs, name, section } = decoded;
244
- message = `${section}.${name}: ${docs.join(" ")}`;
245
- }
246
- return message;
247
- }
248
- function checkForExtrinsicSuccess(events, client) {
249
- return new Promise((resolve, reject) => {
250
- for (const { event } of events) {
251
- if (client.events.system.ExtrinsicSuccess.is(event)) {
252
- resolve();
253
- } else if (client.events.system.ExtrinsicFailed.is(event)) {
254
- const [dispatchError] = event.data;
255
- let errorInfo = dispatchError.toString();
256
- if (dispatchError.isModule) {
257
- const decoded = client.registry.findMetaError(dispatchError.asModule);
258
- errorInfo = `${decoded.section}.${decoded.name}`;
259
- }
260
- reject(
261
- new Error(
262
- `${event.section}.${event.method}:: ExtrinsicFailed:: ${errorInfo}`
263
- )
264
- );
265
- }
266
- }
267
- });
268
- }
269
- var JsonExt = class {
270
- static stringify(obj, space) {
271
- return JSON.stringify(
272
- obj,
273
- (_, v) => typeof v === "bigint" ? `${v}n` : v,
274
- space
275
- );
276
- }
277
- static parse(str) {
278
- return JSON.parse(str, (_, v) => {
279
- if (typeof v === "string" && v.endsWith("n")) {
280
- return BigInt(v.slice(0, -1));
281
- }
282
- return v;
283
- });
284
- }
285
- };
286
-
287
177
  // src/TxSubmitter.ts
288
178
  function logExtrinsicResult(result) {
289
179
  if (process.env.DEBUG) {
@@ -415,13 +305,12 @@ var TxResult = class {
415
305
  }
416
306
  }
417
307
  if (encounteredError) {
418
- const error = dispatchErrorToString(this.client, encounteredError);
419
- if (batchErrorIndex) {
420
- this.reject(
421
- new Error(`Error in batch#${batchErrorIndex}: ${error.toString()}`)
422
- );
423
- }
424
- this.reject(new Error(`Transaction failed: ${error}`));
308
+ const error = dispatchErrorToExtrinsicError(
309
+ this.client,
310
+ encounteredError,
311
+ batchErrorIndex
312
+ );
313
+ this.reject(error);
425
314
  } else {
426
315
  this.inBlockResolve(status.asInBlock.toU8a());
427
316
  }
@@ -436,6 +325,147 @@ var TxResult = class {
436
325
  }
437
326
  };
438
327
 
328
+ // src/utils.ts
329
+ var BN = __toESM(require("bignumber.js"), 1);
330
+ var { ROUND_FLOOR } = BN;
331
+ var MICROGONS_PER_ARGON = 1e6;
332
+ function formatArgons(x) {
333
+ if (x === void 0 || x === null) return "na";
334
+ const isNegative = x < 0;
335
+ let format = (0, BN.default)(x.toString()).abs().div(MICROGONS_PER_ARGON).toFormat(2, ROUND_FLOOR);
336
+ if (format.endsWith(".00")) {
337
+ format = format.slice(0, -3);
338
+ }
339
+ return `${isNegative ? "-" : ""}\u20B3${format}`;
340
+ }
341
+ function formatPercent(x) {
342
+ if (!x) return "na";
343
+ return `${x.times(100).decimalPlaces(3)}%`;
344
+ }
345
+ function filterUndefined(obj) {
346
+ return Object.fromEntries(
347
+ Object.entries(obj).filter(
348
+ ([_, value]) => value !== void 0 && value !== null
349
+ )
350
+ );
351
+ }
352
+ async function gettersToObject(obj) {
353
+ if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
354
+ const keys = [];
355
+ for (const key in obj) {
356
+ keys.push(key);
357
+ }
358
+ if (Symbol.iterator in obj) {
359
+ const iterableToArray = [];
360
+ for (const item of obj) {
361
+ iterableToArray.push(await gettersToObject(item));
362
+ }
363
+ return iterableToArray;
364
+ }
365
+ const result = {};
366
+ for (const key of keys) {
367
+ const descriptor = Object.getOwnPropertyDescriptor(obj, key);
368
+ if (descriptor && typeof descriptor.value === "function") {
369
+ continue;
370
+ }
371
+ const value = descriptor && descriptor.get ? descriptor.get.call(obj) : obj[key];
372
+ if (typeof value === "function") continue;
373
+ result[key] = await gettersToObject(value);
374
+ }
375
+ return result;
376
+ }
377
+ function convertFixedU128ToBigNumber(fixedU128) {
378
+ const decimalFactor = new BN.default(10).pow(new BN.default(18));
379
+ const rawValue = new BN.default(fixedU128.toString());
380
+ return rawValue.div(decimalFactor);
381
+ }
382
+ function convertPermillToBigNumber(permill) {
383
+ const decimalFactor = new BN.default(1e6);
384
+ const rawValue = new BN.default(permill.toString());
385
+ return rawValue.div(decimalFactor);
386
+ }
387
+ function eventDataToJson(event) {
388
+ const obj = {};
389
+ event.data.forEach((data, index) => {
390
+ const name = event.data.names?.[index];
391
+ obj[name ?? `${index}`] = data.toJSON();
392
+ });
393
+ return obj;
394
+ }
395
+ function dispatchErrorToString(client, error) {
396
+ let message = error.toString();
397
+ if (error.isModule) {
398
+ const decoded = client.registry.findMetaError(error.asModule);
399
+ const { docs, name, section } = decoded;
400
+ message = `${section}.${name}: ${docs.join(" ")}`;
401
+ }
402
+ return message;
403
+ }
404
+ var ExtrinsicError2 = class extends Error {
405
+ constructor(errorCode, details, batchInterruptedIndex) {
406
+ super(errorCode);
407
+ this.errorCode = errorCode;
408
+ this.details = details;
409
+ this.batchInterruptedIndex = batchInterruptedIndex;
410
+ }
411
+ toString() {
412
+ if (this.batchInterruptedIndex !== void 0) {
413
+ return `${this.errorCode} ${this.details ?? ""} (Batch interrupted at index ${this.batchInterruptedIndex})`;
414
+ }
415
+ return `${this.errorCode} ${this.details ?? ""}`;
416
+ }
417
+ };
418
+ function dispatchErrorToExtrinsicError(client, error, batchInterruptedIndex) {
419
+ if (error.isModule) {
420
+ const decoded = client.registry.findMetaError(error.asModule);
421
+ const { docs, name, section } = decoded;
422
+ return new ExtrinsicError2(
423
+ `${section}.${name}`,
424
+ docs.join(" "),
425
+ batchInterruptedIndex
426
+ );
427
+ }
428
+ return new ExtrinsicError2(error.toString(), void 0, batchInterruptedIndex);
429
+ }
430
+ function checkForExtrinsicSuccess(events, client) {
431
+ return new Promise((resolve, reject) => {
432
+ for (const { event } of events) {
433
+ if (client.events.system.ExtrinsicSuccess.is(event)) {
434
+ resolve();
435
+ } else if (client.events.system.ExtrinsicFailed.is(event)) {
436
+ const [dispatchError] = event.data;
437
+ let errorInfo = dispatchError.toString();
438
+ if (dispatchError.isModule) {
439
+ const decoded = client.registry.findMetaError(dispatchError.asModule);
440
+ errorInfo = `${decoded.section}.${decoded.name}`;
441
+ }
442
+ reject(
443
+ new Error(
444
+ `${event.section}.${event.method}:: ExtrinsicFailed:: ${errorInfo}`
445
+ )
446
+ );
447
+ }
448
+ }
449
+ });
450
+ }
451
+ var JsonExt = class {
452
+ static stringify(obj, space) {
453
+ return JSON.stringify(
454
+ obj,
455
+ (_, v) => typeof v === "bigint" ? `${v}n` : v,
456
+ space
457
+ );
458
+ }
459
+ static parse(str) {
460
+ return JSON.parse(str, (_, v) => {
461
+ if (typeof v === "string" && v.endsWith("n")) {
462
+ return BigInt(v.slice(0, -1));
463
+ }
464
+ return v;
465
+ });
466
+ }
467
+ };
468
+
439
469
  // src/AccountRegistry.ts
440
470
  var AccountRegistry = class _AccountRegistry {
441
471
  namedAccounts = /* @__PURE__ */ new Map();
@@ -668,7 +698,7 @@ var MiningRotations = class {
668
698
  const slot1StartTick = this.genesisTick + this.miningConfig.slotBiddingStartAfterTicks + ticksBetweenSlots;
669
699
  if (tick < slot1StartTick) return 0;
670
700
  const ticksSinceSlot1 = tick - slot1StartTick;
671
- return Math.floor(ticksSinceSlot1 / ticksBetweenSlots);
701
+ return Math.floor(ticksSinceSlot1 / ticksBetweenSlots) + 1;
672
702
  }
673
703
  async getForHeader(client, header) {
674
704
  if (header.number.toNumber() === 0) return 0;
@@ -848,6 +878,14 @@ var Accountset = class {
848
878
  );
849
879
  }
850
880
  }
881
+ async submitterBalance(blockHash) {
882
+ const client = await this.client;
883
+ const api = blockHash ? await client.at(blockHash) : client;
884
+ const accountData = await api.query.system.account(
885
+ this.txSubmitterPair.address
886
+ );
887
+ return accountData.data.free.toBigInt();
888
+ }
851
889
  async balance(blockHash) {
852
890
  const client = await this.client;
853
891
  const api = blockHash ? await client.at(blockHash) : client;
@@ -1110,18 +1148,18 @@ var Accountset = class {
1110
1148
  return new TxSubmitter(client, tx, this.txSubmitterPair);
1111
1149
  }
1112
1150
  /**
1113
- * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1151
+ * Create but don't submit a mining bid transaction.
1152
+ * @param options
1114
1153
  */
1115
- async createMiningBids(options) {
1116
- const accounts = this.getAccountsInRange(options.subaccountRange);
1154
+ async createMiningBidTx(options) {
1117
1155
  const client = await this.client;
1118
- let tip = options.tip ?? 0n;
1156
+ const { bidAmount, subaccounts, sendRewardsToSeed } = options;
1119
1157
  const batch = client.tx.utility.batch(
1120
- accounts.map((x) => {
1158
+ subaccounts.map((x) => {
1121
1159
  const keys = this.keys();
1122
- const rewards = options.sendRewardsToSeed ? { Account: this.seedAddress } : { Owner: null };
1160
+ const rewards = sendRewardsToSeed ? { Account: this.seedAddress } : { Owner: null };
1123
1161
  return client.tx.miningSlot.bid(
1124
- options.bidAmount,
1162
+ bidAmount,
1125
1163
  rewards,
1126
1164
  {
1127
1165
  grandpa: keys.gran.rawPublicKey,
@@ -1135,7 +1173,19 @@ var Accountset = class {
1135
1173
  if (this.isProxy) {
1136
1174
  tx = client.tx.proxy.proxy(this.seedAddress, "MiningBid", batch);
1137
1175
  }
1138
- const submitter = new TxSubmitter(client, tx, this.txSubmitterPair);
1176
+ return new TxSubmitter(client, tx, this.txSubmitterPair);
1177
+ }
1178
+ /**
1179
+ * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1180
+ */
1181
+ async createMiningBids(options) {
1182
+ const accounts = this.getAccountsInRange(options.subaccountRange);
1183
+ const client = await this.client;
1184
+ const submitter = await this.createMiningBidTx({
1185
+ ...options,
1186
+ subaccounts: accounts
1187
+ });
1188
+ const { tip = 0n } = options;
1139
1189
  const txFee = await submitter.feeEstimate(tip);
1140
1190
  let minBalance = options.bidAmount * BigInt(accounts.length);
1141
1191
  let totalFees = tip + 1n + txFee;
@@ -1579,27 +1629,24 @@ var VaultMonitor = class {
1579
1629
  }
1580
1630
  };
1581
1631
 
1582
- // src/CohortBidder.ts
1583
- var CohortBidder = class _CohortBidder {
1584
- constructor(accountset, cohortId, subaccounts, options) {
1585
- this.accountset = accountset;
1632
+ // src/CohortBidderHistory.ts
1633
+ var CohortBidderHistory = class _CohortBidderHistory {
1634
+ constructor(cohortId, subaccounts) {
1586
1635
  this.cohortId = cohortId;
1587
1636
  this.subaccounts = subaccounts;
1588
- this.options = options;
1637
+ this.maxSeatsInPlay = this.subaccounts.length;
1589
1638
  this.subaccounts.forEach((x) => {
1590
- this.allAddresses.add(x.address);
1639
+ this.myAddresses.add(x.address);
1591
1640
  });
1592
1641
  }
1593
- get client() {
1594
- return this.accountset.client;
1595
- }
1642
+ bidHistory = [];
1596
1643
  stats = {
1597
1644
  // number of seats won
1598
- seats: 0,
1645
+ seatsWon: 0,
1599
1646
  // sum of argons bid in successful bids
1600
1647
  totalArgonsBid: 0n,
1601
1648
  // total number of bids placed (includes 1 per seat)
1602
- bids: 0,
1649
+ bidsAttempted: 0,
1603
1650
  // fees including the tip
1604
1651
  fees: 0n,
1605
1652
  // Max bid per seat
@@ -1611,16 +1658,157 @@ var CohortBidder = class _CohortBidder {
1611
1658
  // The cohort expected argons per block
1612
1659
  cohortArgonsPerBlock: 0n,
1613
1660
  // The last block that bids are synced to
1614
- lastBlock: 0
1661
+ lastBlockNumber: 0
1615
1662
  };
1663
+ lastBids = [];
1664
+ myAddresses = /* @__PURE__ */ new Set();
1665
+ maxSeatsInPlay = 0;
1666
+ async init(client) {
1667
+ if (!this.stats.argonotsPerSeat) {
1668
+ const startingStats = await _CohortBidderHistory.getStartingData(client);
1669
+ Object.assign(this.stats, startingStats);
1670
+ }
1671
+ }
1672
+ maybeReducingSeats(maxSeats, reason, historyEntry) {
1673
+ if (this.maxSeatsInPlay > maxSeats) {
1674
+ historyEntry.maxSeatsReductionReason = reason;
1675
+ }
1676
+ this.maxSeatsInPlay = maxSeats;
1677
+ historyEntry.maxSeatsInPlay = maxSeats;
1678
+ }
1679
+ trackChange(next, blockNumber, tick, isLastEntry = false) {
1680
+ let winningBids = 0;
1681
+ let totalArgonsBid = 0n;
1682
+ const nextEntrants = [];
1683
+ for (const x of next) {
1684
+ const bid = x.bid.toBigInt();
1685
+ const address = x.accountId.toHuman();
1686
+ nextEntrants.push({ address, bid });
1687
+ if (this.myAddresses.has(address)) {
1688
+ winningBids++;
1689
+ totalArgonsBid += bid;
1690
+ }
1691
+ }
1692
+ this.stats.seatsWon = winningBids;
1693
+ this.stats.totalArgonsBid = totalArgonsBid;
1694
+ this.stats.lastBlockNumber = Math.max(
1695
+ blockNumber,
1696
+ this.stats.lastBlockNumber
1697
+ );
1698
+ const historyEntry = {
1699
+ cohortId: this.cohortId,
1700
+ blockNumber,
1701
+ tick,
1702
+ bidChanges: [],
1703
+ winningSeats: winningBids,
1704
+ maxSeatsInPlay: this.maxSeatsInPlay
1705
+ };
1706
+ const hasDiffs = JsonExt.stringify(nextEntrants) !== JsonExt.stringify(this.lastBids);
1707
+ if (!isLastEntry || hasDiffs) {
1708
+ this.bidHistory.unshift(historyEntry);
1709
+ }
1710
+ if (hasDiffs) {
1711
+ nextEntrants.forEach(({ address, bid }, i) => {
1712
+ const prevBidIndex = this.lastBids.findIndex(
1713
+ (y) => y.address === address
1714
+ );
1715
+ const entry = {
1716
+ address,
1717
+ bidAmount: bid,
1718
+ bidPosition: i,
1719
+ prevPosition: prevBidIndex === -1 ? null : prevBidIndex
1720
+ };
1721
+ if (prevBidIndex !== -1) {
1722
+ const prevBidAmount = this.lastBids[prevBidIndex].bid;
1723
+ if (prevBidAmount !== bid) {
1724
+ entry.prevBidAmount = prevBidAmount;
1725
+ }
1726
+ }
1727
+ historyEntry.bidChanges.push(entry);
1728
+ });
1729
+ this.lastBids.forEach(({ address, bid }, i) => {
1730
+ const nextBid = nextEntrants.some((y) => y.address === address);
1731
+ if (!nextBid) {
1732
+ historyEntry.bidChanges.push({
1733
+ address,
1734
+ bidAmount: bid,
1735
+ bidPosition: null,
1736
+ prevPosition: i
1737
+ });
1738
+ }
1739
+ });
1740
+ this.lastBids = nextEntrants;
1741
+ }
1742
+ return historyEntry;
1743
+ }
1744
+ onBidResult(historyEntry, param) {
1745
+ const {
1746
+ txFeePlusTip,
1747
+ bidPerSeat,
1748
+ bidsAttempted,
1749
+ successfulBids,
1750
+ blockNumber,
1751
+ bidError
1752
+ } = param;
1753
+ this.stats.fees += txFeePlusTip;
1754
+ this.stats.bidsAttempted += bidsAttempted;
1755
+ if (bidPerSeat > this.stats.maxBidPerSeat) {
1756
+ this.stats.maxBidPerSeat = bidPerSeat;
1757
+ }
1758
+ if (blockNumber !== void 0) {
1759
+ this.stats.lastBlockNumber = Math.max(
1760
+ blockNumber,
1761
+ this.stats.lastBlockNumber
1762
+ );
1763
+ }
1764
+ historyEntry.myBidsPlaced.failureReason = bidError;
1765
+ historyEntry.myBidsPlaced.successfulBids = successfulBids;
1766
+ historyEntry.myBidsPlaced.txFeePlusTip = txFeePlusTip;
1767
+ }
1768
+ static async getStartingData(api) {
1769
+ const argonotPrice = await api.query.priceIndex.current();
1770
+ let argonotUsdPrice = 0;
1771
+ if (argonotPrice.isSome) {
1772
+ argonotUsdPrice = convertFixedU128ToBigNumber(
1773
+ argonotPrice.unwrap().argonotUsdPrice.toBigInt()
1774
+ ).toNumber();
1775
+ }
1776
+ const argonotsPerSeat = await api.query.miningSlot.argonotsPerMiningSeat().then((x) => x.toBigInt());
1777
+ const cohortArgonsPerBlock = await api.query.blockRewards.argonsPerBlock().then((x) => x.toBigInt());
1778
+ return { argonotsPerSeat, argonotUsdPrice, cohortArgonsPerBlock };
1779
+ }
1780
+ };
1781
+
1782
+ // src/CohortBidder.ts
1783
+ var CohortBidder = class {
1784
+ constructor(accountset, cohortId, subaccounts, options) {
1785
+ this.accountset = accountset;
1786
+ this.cohortId = cohortId;
1787
+ this.subaccounts = subaccounts;
1788
+ this.options = options;
1789
+ this.history = new CohortBidderHistory(cohortId, subaccounts);
1790
+ this.subaccounts.forEach((x) => {
1791
+ this.myAddresses.add(x.address);
1792
+ });
1793
+ }
1794
+ get client() {
1795
+ return this.accountset.client;
1796
+ }
1797
+ get stats() {
1798
+ return this.history.stats;
1799
+ }
1800
+ get bidHistory() {
1801
+ return this.history.bidHistory;
1802
+ }
1616
1803
  unsubscribe;
1617
1804
  pendingRequest;
1618
1805
  retryTimeout;
1619
1806
  isStopped = false;
1620
1807
  needsRebid = false;
1621
1808
  lastBidTime = 0;
1809
+ history;
1622
1810
  millisPerTick;
1623
- allAddresses = /* @__PURE__ */ new Set();
1811
+ myAddresses = /* @__PURE__ */ new Set();
1624
1812
  async stop() {
1625
1813
  if (this.isStopped) return this.stats;
1626
1814
  this.isStopped = true;
@@ -1630,70 +1818,59 @@ var CohortBidder = class _CohortBidder {
1630
1818
  this.unsubscribe();
1631
1819
  }
1632
1820
  const client = await this.client;
1633
- const [nextCohort, nextCohortId, blockNumber] = await new Promise(async (resolve) => {
1634
- const unsub = await client.queryMulti(
1635
- [
1636
- client.query.miningSlot.nextSlotCohort,
1637
- client.query.miningSlot.nextCohortId,
1638
- client.query.miningSlot.isNextSlotBiddingOpen,
1639
- client.query.system.number
1640
- ],
1641
- ([nextCohort2, nextCohortId2, isBiddingStillOpen, blockNumber2]) => {
1642
- if (nextCohortId2.toNumber() !== this.cohortId || isBiddingStillOpen.isFalse) {
1643
- unsub();
1644
- resolve([nextCohort2, nextCohortId2, blockNumber2]);
1821
+ const [nextCohortId, isBiddingOpen] = await client.queryMulti([
1822
+ client.query.miningSlot.nextCohortId,
1823
+ client.query.miningSlot.isNextSlotBiddingOpen
1824
+ ]);
1825
+ if (nextCohortId.toNumber() === this.cohortId && isBiddingOpen.isTrue) {
1826
+ console.log("Bidding is still open, waiting for it to close");
1827
+ await new Promise(async (resolve) => {
1828
+ const unsub = await client.query.miningSlot.isNextSlotBiddingOpen(
1829
+ (isOpen) => {
1830
+ if (isOpen.isFalse) {
1831
+ unsub();
1832
+ resolve();
1833
+ }
1645
1834
  }
1646
- }
1647
- );
1648
- });
1649
- void await this.pendingRequest;
1650
- if (nextCohortId.toNumber() === this.cohortId) {
1651
- console.log("Bidder updating stats with bid queue");
1652
- this.updateStats(nextCohort);
1653
- } else {
1654
- const bestBlock = await client.rpc.chain.getBlockHash();
1655
- const api = await client.at(bestBlock);
1656
- const wonIndices = await api.query.miningSlot.accountIndexLookup.multi([...this.allAddresses]).then((x) => x.filter((x2) => x2.isSome).map((x2) => x2.value));
1657
- const wonSeats = await api.query.miningSlot.activeMinersByIndex.multi(wonIndices).then(
1658
- (x) => x.filter(
1659
- (x2) => x2.isSome && x2.value.cohortId.toNumber() === this.cohortId
1660
- ).map((x2) => x2.value)
1661
- );
1662
- console.log("Bidder updating stats with finalized cohort");
1663
- this.updateStats(wonSeats);
1835
+ );
1836
+ });
1664
1837
  }
1665
- this.stats.lastBlock = Math.max(
1666
- blockNumber.toNumber(),
1667
- this.stats.lastBlock
1668
- );
1838
+ void await this.pendingRequest;
1839
+ let header = await client.rpc.chain.getHeader();
1840
+ while (true) {
1841
+ const api2 = await client.at(header.hash);
1842
+ const cohortId = await api2.query.miningSlot.nextCohortId();
1843
+ if (cohortId.toNumber() === this.cohortId) {
1844
+ break;
1845
+ }
1846
+ header = await client.rpc.chain.getHeader(header.parentHash);
1847
+ }
1848
+ const api = await client.at(header.hash);
1849
+ const tick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1850
+ const cohort = await api.query.miningSlot.nextSlotCohort();
1851
+ this.history.trackChange(cohort, header.number.toNumber(), tick, true);
1852
+ console.log("Bidder stopped", {
1853
+ cohortId: this.cohortId,
1854
+ blockNumber: header.number.toNumber(),
1855
+ tick,
1856
+ cohort: cohort.map((x) => ({
1857
+ address: x.accountId.toHuman(),
1858
+ bid: x.bid.toBigInt()
1859
+ }))
1860
+ });
1669
1861
  return this.stats;
1670
1862
  }
1671
- static async getStartingData(api) {
1672
- const argonotPrice = await api.query.priceIndex.current();
1673
- let argonotUsdPrice = 0;
1674
- if (argonotPrice.isSome) {
1675
- argonotUsdPrice = convertFixedU128ToBigNumber(
1676
- argonotPrice.unwrap().argonotUsdPrice.toBigInt()
1677
- ).toNumber();
1678
- }
1679
- const argonotsPerSeat = await api.query.miningSlot.argonotsPerMiningSeat().then((x) => x.toBigInt());
1680
- const cohortArgonsPerBlock = await api.query.blockRewards.argonsPerBlock().then((x) => x.toBigInt());
1681
- return { argonotsPerSeat, argonotUsdPrice, cohortArgonsPerBlock };
1682
- }
1683
1863
  async start() {
1684
1864
  console.log(`Starting cohort ${this.cohortId} bidder`, {
1685
1865
  maxBid: formatArgons(this.options.maxBid),
1686
1866
  minBid: formatArgons(this.options.minBid),
1687
1867
  bidIncrement: formatArgons(this.options.bidIncrement),
1688
- maxBalance: formatArgons(this.options.maxBalance),
1868
+ maxBudget: formatArgons(this.options.maxBudget),
1689
1869
  bidDelay: this.options.bidDelay,
1690
1870
  subaccounts: this.subaccounts
1691
1871
  });
1692
1872
  const client = await this.client;
1693
- if (!this.stats.argonotsPerSeat) {
1694
- const startingStats = await _CohortBidder.getStartingData(client);
1695
- Object.assign(this.stats, startingStats);
1696
- }
1873
+ await this.history.init(client);
1697
1874
  this.millisPerTick ??= await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1698
1875
  this.unsubscribe = await client.queryMulti(
1699
1876
  [
@@ -1707,24 +1884,27 @@ var CohortBidder = class _CohortBidder {
1707
1884
  }
1708
1885
  );
1709
1886
  }
1710
- updateStats(next) {
1711
- let seats = 0;
1712
- let totalArgonsBid = 0n;
1713
- for (const x of next) {
1714
- if (this.allAddresses.has(x.accountId.toHuman())) {
1715
- seats++;
1716
- totalArgonsBid += x.bid.toBigInt();
1717
- }
1718
- }
1719
- this.stats.seats = seats;
1720
- this.stats.totalArgonsBid = totalArgonsBid;
1721
- }
1722
1887
  async checkSeats(next) {
1723
- if (this.isStopped || this.pendingRequest) return;
1888
+ if (this.isStopped) return;
1889
+ clearTimeout(this.retryTimeout);
1890
+ const client = await this.client;
1891
+ const bestBlock = await client.rpc.chain.getBlockHash();
1892
+ const api = await client.at(bestBlock);
1893
+ const blockNumber = await api.query.system.number().then((x) => x.toNumber());
1894
+ if (this.bidHistory[0]?.blockNumber >= blockNumber) {
1895
+ return;
1896
+ }
1897
+ const tick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1898
+ const historyEntry = this.history.trackChange(next, blockNumber, tick);
1899
+ if (this.pendingRequest) return;
1724
1900
  const ticksSinceLastBid = Math.floor(
1725
1901
  (Date.now() - this.lastBidTime) / this.millisPerTick
1726
1902
  );
1727
1903
  if (ticksSinceLastBid < this.options.bidDelay) {
1904
+ this.retryTimeout = setTimeout(
1905
+ () => void this.checkCurrentSeats(),
1906
+ this.millisPerTick
1907
+ );
1728
1908
  return;
1729
1909
  }
1730
1910
  console.log(
@@ -1732,12 +1912,19 @@ var CohortBidder = class _CohortBidder {
1732
1912
  this.cohortId,
1733
1913
  this.subaccounts.map((x) => x.index)
1734
1914
  );
1735
- this.updateStats(next);
1736
- this.needsRebid = this.subaccounts.some(
1737
- (x) => !next.some((y) => y.accountId.toHuman() === x.address)
1738
- );
1915
+ const winningBids = historyEntry.winningSeats;
1916
+ this.needsRebid = winningBids < this.subaccounts.length;
1739
1917
  if (!this.needsRebid) return;
1740
- const lowestBid = next.at(-1)?.bid.toBigInt() ?? -this.options.bidIncrement;
1918
+ const winningAddresses = new Set(next.map((x) => x.accountId.toHuman()));
1919
+ let lowestBid = -this.options.bidIncrement;
1920
+ if (next.length) {
1921
+ for (let i = next.length - 1; i >= 0; i--) {
1922
+ if (!this.myAddresses.has(next[i].accountId.toHuman())) {
1923
+ lowestBid = next.at(i).bid.toBigInt();
1924
+ break;
1925
+ }
1926
+ }
1927
+ }
1741
1928
  const MIN_INCREMENT = 10000n;
1742
1929
  let nextBid = lowestBid + this.options.bidIncrement;
1743
1930
  if (nextBid < this.options.minBid) {
@@ -1745,83 +1932,119 @@ var CohortBidder = class _CohortBidder {
1745
1932
  }
1746
1933
  if (nextBid > this.options.maxBid) {
1747
1934
  nextBid = this.options.maxBid;
1748
- if (nextBid - lowestBid < MIN_INCREMENT) {
1749
- console.log(
1750
- `Can't make any more bids for ${this.cohortId} with given constraints.`,
1751
- {
1752
- lowestCurrentBid: formatArgons(lowestBid),
1753
- nextAttemptedBid: formatArgons(nextBid),
1754
- maxBid: formatArgons(this.options.maxBid)
1755
- }
1756
- );
1757
- return;
1935
+ }
1936
+ const fakeTx = await this.accountset.createMiningBidTx({
1937
+ subaccounts: this.subaccounts,
1938
+ bidAmount: nextBid,
1939
+ sendRewardsToSeed: true
1940
+ });
1941
+ let availableBalanceForBids = await api.query.system.account(this.accountset.txSubmitterPair.address).then((x) => x.data.free.toBigInt());
1942
+ for (const bid of next) {
1943
+ if (this.myAddresses.has(bid.accountId.toHuman())) {
1944
+ availableBalanceForBids += bid.bid.toBigInt();
1758
1945
  }
1759
1946
  }
1947
+ const tip = this.options.tipPerTransaction ?? 0n;
1948
+ const feeEstimate = await fakeTx.feeEstimate(tip);
1949
+ const feePlusTip = feeEstimate + tip;
1950
+ let budgetForSeats = this.options.maxBudget - feePlusTip;
1951
+ if (budgetForSeats > availableBalanceForBids) {
1952
+ budgetForSeats = availableBalanceForBids - feePlusTip;
1953
+ }
1760
1954
  if (nextBid < lowestBid) {
1761
1955
  console.log(
1762
1956
  `Can't bid ${formatArgons(nextBid)}. Current lowest bid is ${formatArgons(
1763
1957
  lowestBid
1764
1958
  )}.`
1765
1959
  );
1960
+ this.history.maybeReducingSeats(
1961
+ winningBids,
1962
+ "MaxBidTooLow" /* MaxBidTooLow */,
1963
+ historyEntry
1964
+ );
1766
1965
  return;
1767
1966
  }
1768
- const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(this.options.maxBalance / nextBid);
1769
- if (seatsInBudget <= 0) {
1967
+ if (nextBid - lowestBid < MIN_INCREMENT) {
1770
1968
  console.log(
1771
- `Can't afford any seats at ${formatArgons(nextBid)}. Would exceed our max balance of ${formatArgons(this.options.maxBalance)}.`
1969
+ `Can't make any more bids for ${this.cohortId} with given constraints.`,
1970
+ {
1971
+ lowestCurrentBid: formatArgons(lowestBid),
1972
+ nextAttemptedBid: formatArgons(nextBid),
1973
+ maxBid: formatArgons(this.options.maxBid)
1974
+ }
1975
+ );
1976
+ this.history.maybeReducingSeats(
1977
+ winningBids,
1978
+ "MaxBidTooLow" /* MaxBidTooLow */,
1979
+ historyEntry
1772
1980
  );
1773
1981
  return;
1774
1982
  }
1775
- if (this.subaccounts.length > seatsInBudget) {
1776
- const toKeep = [];
1777
- for (const account of this.subaccounts) {
1778
- if (toKeep.length >= seatsInBudget) break;
1779
- if (account.isRebid) {
1780
- toKeep.push(account);
1781
- }
1782
- }
1783
- for (const account of this.subaccounts) {
1784
- if (toKeep.length >= seatsInBudget) break;
1785
- if (!account.isRebid) {
1786
- toKeep.push(account);
1787
- }
1788
- }
1789
- const removedIndices = this.subaccounts.filter((x) => !toKeep.some((y) => y.index === x.index)).map((x) => x.index);
1790
- this.subaccounts = toKeep;
1791
- console.log("Had to remove some subaccounts to fit in budget:", {
1792
- removedIndices,
1793
- seatsInBudget,
1794
- budget: formatArgons(this.options.maxBalance)
1983
+ const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(budgetForSeats / nextBid);
1984
+ let accountsToUse = [...this.subaccounts];
1985
+ if (accountsToUse.length > seatsInBudget) {
1986
+ const reason = availableBalanceForBids - feePlusTip < nextBid * BigInt(seatsInBudget) ? "InsufficientFunds" /* InsufficientFunds */ : "MaxBudgetTooLow" /* MaxBudgetTooLow */;
1987
+ this.history.maybeReducingSeats(seatsInBudget, reason, historyEntry);
1988
+ accountsToUse.sort((a, b) => {
1989
+ const isWinningA = winningAddresses.has(a.address);
1990
+ const isWinningB = winningAddresses.has(b.address);
1991
+ if (isWinningA && !isWinningB) return -1;
1992
+ if (!isWinningA && isWinningB) return 1;
1993
+ if (a.isRebid && !b.isRebid) return -1;
1994
+ if (!a.isRebid && b.isRebid) return 1;
1995
+ return a.index - b.index;
1795
1996
  });
1997
+ accountsToUse.length = seatsInBudget;
1998
+ }
1999
+ if (accountsToUse.length > winningBids) {
2000
+ historyEntry.myBidsPlaced = {
2001
+ bids: accountsToUse.length,
2002
+ bidPerSeat: nextBid,
2003
+ txFeePlusTip: feePlusTip,
2004
+ successfulBids: 0
2005
+ };
2006
+ this.pendingRequest = this.bid(nextBid, accountsToUse, historyEntry);
2007
+ } else if (historyEntry.bidChanges.length === 0) {
2008
+ this.history.bidHistory.shift();
1796
2009
  }
1797
- this.pendingRequest = this.bid(
1798
- nextBid,
1799
- this.subaccounts.map((x) => x.index)
1800
- );
1801
2010
  this.needsRebid = false;
1802
2011
  }
1803
- async bid(bidPerSeat, subaccountRange) {
1804
- if (!subaccountRange.length) return;
2012
+ async bid(bidPerSeat, subaccounts, historyEntry) {
1805
2013
  const prevLastBidTime = this.lastBidTime;
1806
2014
  try {
1807
2015
  this.lastBidTime = Date.now();
1808
- const result = await this.accountset.createMiningBids({
1809
- subaccountRange,
2016
+ const submitter = await this.accountset.createMiningBidTx({
2017
+ subaccounts,
1810
2018
  bidAmount: bidPerSeat,
1811
2019
  sendRewardsToSeed: true
1812
2020
  });
1813
- if (result.blockHash) {
2021
+ const tip = this.options.tipPerTransaction ?? 0n;
2022
+ const txResult = await submitter.submit({
2023
+ tip,
2024
+ useLatestNonce: true
2025
+ });
2026
+ const bidError = await txResult.inBlockPromise.then(() => void 0).catch((x) => x);
2027
+ let blockNumber;
2028
+ if (txResult.includedInBlock) {
1814
2029
  const client = await this.client;
1815
- const api = await client.at(result.blockHash);
1816
- this.stats.lastBlock = await api.query.system.number().then((x) => x.toNumber());
2030
+ const api = await client.at(txResult.includedInBlock);
2031
+ blockNumber = await api.query.system.number().then((x) => x.toNumber());
1817
2032
  }
1818
- this.stats.fees += result.finalFee ?? 0n;
1819
- this.stats.bids += subaccountRange.length;
1820
- if (bidPerSeat > this.stats.maxBidPerSeat) {
1821
- this.stats.maxBidPerSeat = bidPerSeat;
1822
- }
1823
- console.log("Done creating bids for cohort", this.cohortId);
1824
- if (result.bidError) throw result.bidError;
2033
+ const successfulBids = txResult.batchInterruptedIndex ?? subaccounts.length;
2034
+ this.history.onBidResult(historyEntry, {
2035
+ blockNumber,
2036
+ successfulBids,
2037
+ bidPerSeat,
2038
+ txFeePlusTip: txResult.finalFee ?? 0n,
2039
+ bidsAttempted: subaccounts.length,
2040
+ bidError
2041
+ });
2042
+ console.log("Done creating bids for cohort", {
2043
+ successfulBids,
2044
+ bidPerSeat,
2045
+ blockNumber
2046
+ });
2047
+ if (bidError) throw bidError;
1825
2048
  } catch (err) {
1826
2049
  this.lastBidTime = prevLastBidTime;
1827
2050
  console.error(`Error bidding for cohort ${this.cohortId}:`, err);
@@ -2499,8 +2722,8 @@ function vaultCli() {
2499
2722
  ).action(async ({ tip, argons, vaultId, ratio }) => {
2500
2723
  const accountset = await accountsetFromCli(program);
2501
2724
  const client = await accountset.client;
2502
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2503
- const microgons = BigInt(argons * 1e6);
2725
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2726
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2504
2727
  const rawVault = (await client.query.vaults.vaultsById(vaultId)).unwrap();
2505
2728
  if (rawVault.operatorAccountId.toHuman() !== accountset.seedAddress) {
2506
2729
  console.error("Vault does not belong to this account");
@@ -2560,8 +2783,8 @@ function vaultCli() {
2560
2783
  }
2561
2784
  const accountset = await accountsetFromCli(program);
2562
2785
  const client = await accountset.client;
2563
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2564
- const microgons = BigInt(argons * 1e6);
2786
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2787
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2565
2788
  const bitcoinLocks = new BitcoinLocks(Promise.resolve(client));
2566
2789
  const existentialDeposit = client.consts.balances.existentialDeposit.toBigInt();
2567
2790
  const tickDuration = (await client.query.ticks.genesisTicker()).tickDurationMillis.toNumber();
@@ -2766,7 +2989,7 @@ function miningCli() {
2766
2989
  const balance = await accountset.balance();
2767
2990
  const feeWiggleRoom = BigInt(25e3);
2768
2991
  const amountAvailable = balance - feeWiggleRoom;
2769
- let maxBidAmount = maxBid ? BigInt(maxBid * 1e6) : void 0;
2992
+ let maxBidAmount = maxBid ? BigInt(maxBid * MICROGONS_PER_ARGON) : void 0;
2770
2993
  let maxBalanceToUse = amountAvailable;
2771
2994
  if (maxBalance !== void 0) {
2772
2995
  if (maxBalance.endsWith("%")) {
@@ -2778,7 +3001,7 @@ function miningCli() {
2778
3001
  maxBalanceToUse = amountToBid;
2779
3002
  } else {
2780
3003
  maxBalanceToUse = BigInt(
2781
- Math.floor(parseFloat(maxBalance) * 1e6)
3004
+ Math.floor(parseFloat(maxBalance) * MICROGONS_PER_ARGON)
2782
3005
  );
2783
3006
  }
2784
3007
  maxBidAmount ??= maxBalanceToUse / BigInt(seatsToWin);
@@ -2800,9 +3023,11 @@ function miningCli() {
2800
3023
  subaccountRange,
2801
3024
  {
2802
3025
  maxBid: maxBidAmount,
2803
- minBid: BigInt((minBid ?? 0) * 1e6),
2804
- bidIncrement: BigInt(Math.floor(bidIncrement * 1e6)),
2805
- maxBalance: maxBalanceToUse,
3026
+ minBid: BigInt((minBid ?? 0) * MICROGONS_PER_ARGON),
3027
+ bidIncrement: BigInt(
3028
+ Math.floor(bidIncrement * MICROGONS_PER_ARGON)
3029
+ ),
3030
+ maxBudget: maxBalanceToUse,
2806
3031
  bidDelay
2807
3032
  }
2808
3033
  );
@@ -2834,7 +3059,10 @@ function miningCli() {
2834
3059
  );
2835
3060
  const tx = client.tx.utility.batchAll([
2836
3061
  client.tx.proxy.addProxy(address, "MiningBid", 0),
2837
- client.tx.balances.transferAllowDeath(address, BigInt(feeArgons * 1e6))
3062
+ client.tx.balances.transferAllowDeath(
3063
+ address,
3064
+ BigInt(feeArgons * MICROGONS_PER_ARGON)
3065
+ )
2838
3066
  ]);
2839
3067
  let keypair;
2840
3068
  try {
@@ -2883,8 +3111,8 @@ function liquidityCli() {
2883
3111
  parseFloat
2884
3112
  ).action(async ({ tip, argons, vaultId }) => {
2885
3113
  const accountset = await accountsetFromCli(program);
2886
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2887
- const microgons = BigInt(argons * 1e6);
3114
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
3115
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2888
3116
  const bidPool = new BidPool(
2889
3117
  accountset.client,
2890
3118
  accountset.txSubmitterPair
@@ -2909,7 +3137,7 @@ function liquidityCli() {
2909
3137
  "The tip to include with the transaction",
2910
3138
  parseFloat
2911
3139
  ).action(async ({ maxArgons, minPctSharing, tip }) => {
2912
- const maxAmountPerSlot = BigInt(maxArgons * 1e6);
3140
+ const maxAmountPerSlot = BigInt(maxArgons * MICROGONS_PER_ARGON);
2913
3141
  const accountset = await accountsetFromCli(program);
2914
3142
  const vaults = new VaultMonitor(
2915
3143
  accountset,
@@ -2922,7 +3150,7 @@ function liquidityCli() {
2922
3150
  accountset.client,
2923
3151
  accountset.txSubmitterPair
2924
3152
  );
2925
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
3153
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2926
3154
  console.log("Waiting for liquidity pool space...");
2927
3155
  vaults.events.on(
2928
3156
  "liquidity-pool-space-above",
@@ -2961,7 +3189,7 @@ function bitcoinCli() {
2961
3189
  ).description("Watch for bitcoin space available").action(async ({ argons }) => {
2962
3190
  const accountset = await accountsetFromCli(program);
2963
3191
  const bot = new VaultMonitor(accountset, {
2964
- bitcoinSpaceAvailable: argons ? BigInt(argons * 1e6) : 1n
3192
+ bitcoinSpaceAvailable: argons ? BigInt(argons * MICROGONS_PER_ARGON) : 1n
2965
3193
  });
2966
3194
  bot.events.on("bitcoin-space-above", async (vaultId, amount) => {
2967
3195
  const vault = bot.vaultsById[vaultId];
@@ -2990,13 +3218,13 @@ function bitcoinCli() {
2990
3218
  parseFloat,
2991
3219
  0
2992
3220
  ).action(async ({ argons, bitcoinXpub, maxLockFee, tip }) => {
2993
- const amountToLock = BigInt(argons * 1e6);
3221
+ const amountToLock = BigInt(argons * MICROGONS_PER_ARGON);
2994
3222
  const accountset = await accountsetFromCli(program);
2995
3223
  await BitcoinLocks.waitForSpace(accountset, {
2996
3224
  argonAmount: amountToLock,
2997
3225
  bitcoinXpub,
2998
- maxLockFee: maxLockFee !== void 0 ? BigInt(maxLockFee * 1e6) : void 0,
2999
- tip: BigInt(tip * 1e6)
3226
+ maxLockFee: maxLockFee !== void 0 ? BigInt(maxLockFee * MICROGONS_PER_ARGON) : void 0,
3227
+ tip: BigInt(tip * MICROGONS_PER_ARGON)
3000
3228
  }).then(({ vaultId, satoshis, txFee, btcFee }) => {
3001
3229
  console.log(
3002
3230
  `Locked ${satoshis} satoshis in vault ${vaultId}. Tx fee=${formatArgons(
@@ -3021,8 +3249,13 @@ async function keyringFromFile(opts) {
3021
3249
  }
3022
3250
  const path = opts.filePath.replace("~", os.homedir());
3023
3251
  const json = JSON.parse(await readFile(path, "utf-8"));
3252
+ let passphrase = opts.passphrase;
3253
+ if (opts.passphraseFile) {
3254
+ const passphrasePath = opts.passphraseFile.replace("~", os.homedir());
3255
+ passphrase = await readFile(passphrasePath, "utf-8");
3256
+ }
3024
3257
  const mainAccount = new import_api.Keyring().createFromJson(json);
3025
- mainAccount.decodePkcs8(opts.passphrase);
3258
+ mainAccount.decodePkcs8(passphrase);
3026
3259
  return mainAccount;
3027
3260
  }
3028
3261
  async function saveKeyringPair(opts) {
@@ -3057,6 +3290,11 @@ function buildCli() {
3057
3290
  "--account-passphrase <password>",
3058
3291
  "The password for your seed file"
3059
3292
  ).env("ACCOUNT_PASSPHRASE")
3293
+ ).addOption(
3294
+ new import_extra_typings6.Option(
3295
+ "--account-passphrase-file <path>",
3296
+ "The path to a password for your seed file"
3297
+ )
3060
3298
  ).addOption(
3061
3299
  new import_extra_typings6.Option(
3062
3300
  "-s, --subaccounts <range>",
@@ -3073,7 +3311,8 @@ async function accountsetFromCli(program, proxyForAddress) {
3073
3311
  if (opts.accountFilePath) {
3074
3312
  keypair = await keyringFromFile({
3075
3313
  filePath: opts.accountFilePath,
3076
- passphrase: opts.accountPassphrase
3314
+ passphrase: opts.accountPassphrase,
3315
+ passphraseFile: opts.accountPassphraseFile
3077
3316
  });
3078
3317
  }
3079
3318
  if (!keypair) {