@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.
package/lib/cli.cjs CHANGED
@@ -44,8 +44,10 @@ __export(index_exports, {
44
44
  BitcoinLocks: () => BitcoinLocks,
45
45
  BlockWatch: () => BlockWatch,
46
46
  CohortBidder: () => CohortBidder,
47
+ ExtrinsicError: () => ExtrinsicError2,
47
48
  JsonExt: () => JsonExt,
48
49
  Keyring: () => import_api.Keyring,
50
+ MICROGONS_PER_ARGON: () => MICROGONS_PER_ARGON,
49
51
  MiningBids: () => MiningBids,
50
52
  MiningRotations: () => MiningRotations,
51
53
  TxSubmitter: () => TxSubmitter,
@@ -57,6 +59,7 @@ __export(index_exports, {
57
59
  convertPermillToBigNumber: () => convertPermillToBigNumber,
58
60
  createKeyringPair: () => createKeyringPair,
59
61
  decodeAddress: () => import_util_crypto.decodeAddress,
62
+ dispatchErrorToExtrinsicError: () => dispatchErrorToExtrinsicError,
60
63
  dispatchErrorToString: () => dispatchErrorToString,
61
64
  eventDataToJson: () => eventDataToJson,
62
65
  filterUndefined: () => filterUndefined,
@@ -155,119 +158,6 @@ var WageProtector = class _WageProtector {
155
158
  }
156
159
  };
157
160
 
158
- // src/utils.ts
159
- var BN = __toESM(require("bignumber.js"), 1);
160
- var { ROUND_FLOOR } = BN;
161
- function formatArgons(x) {
162
- const isNegative = x < 0;
163
- let format = (0, BN.default)(x.toString()).abs().div(1e6).toFormat(2, ROUND_FLOOR);
164
- if (format.endsWith(".00")) {
165
- format = format.slice(0, -3);
166
- }
167
- return `${isNegative ? "-" : ""}\u20B3${format}`;
168
- }
169
- function formatPercent(x) {
170
- if (!x) return "na";
171
- return `${x.times(100).decimalPlaces(3)}%`;
172
- }
173
- function filterUndefined(obj) {
174
- return Object.fromEntries(
175
- Object.entries(obj).filter(
176
- ([_, value]) => value !== void 0 && value !== null
177
- )
178
- );
179
- }
180
- async function gettersToObject(obj) {
181
- if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
182
- const keys = [];
183
- for (const key in obj) {
184
- keys.push(key);
185
- }
186
- if (Symbol.iterator in obj) {
187
- const iterableToArray = [];
188
- for (const item of obj) {
189
- iterableToArray.push(await gettersToObject(item));
190
- }
191
- return iterableToArray;
192
- }
193
- const result = {};
194
- for (const key of keys) {
195
- const descriptor = Object.getOwnPropertyDescriptor(obj, key);
196
- if (descriptor && typeof descriptor.value === "function") {
197
- continue;
198
- }
199
- const value = descriptor && descriptor.get ? descriptor.get.call(obj) : obj[key];
200
- if (typeof value === "function") continue;
201
- result[key] = await gettersToObject(value);
202
- }
203
- return result;
204
- }
205
- function convertFixedU128ToBigNumber(fixedU128) {
206
- const decimalFactor = new BN.default(10).pow(new BN.default(18));
207
- const rawValue = new BN.default(fixedU128.toString());
208
- return rawValue.div(decimalFactor);
209
- }
210
- function convertPermillToBigNumber(permill) {
211
- const decimalFactor = new BN.default(1e6);
212
- const rawValue = new BN.default(permill.toString());
213
- return rawValue.div(decimalFactor);
214
- }
215
- function eventDataToJson(event) {
216
- const obj = {};
217
- event.data.forEach((data, index) => {
218
- const name = event.data.names?.[index];
219
- obj[name ?? `${index}`] = data.toJSON();
220
- });
221
- return obj;
222
- }
223
- function dispatchErrorToString(client, error) {
224
- let message = error.toString();
225
- if (error.isModule) {
226
- const decoded = client.registry.findMetaError(error.asModule);
227
- const { docs, name, section } = decoded;
228
- message = `${section}.${name}: ${docs.join(" ")}`;
229
- }
230
- return message;
231
- }
232
- function checkForExtrinsicSuccess(events, client) {
233
- return new Promise((resolve, reject) => {
234
- for (const { event } of events) {
235
- if (client.events.system.ExtrinsicSuccess.is(event)) {
236
- resolve();
237
- } else if (client.events.system.ExtrinsicFailed.is(event)) {
238
- const [dispatchError] = event.data;
239
- let errorInfo = dispatchError.toString();
240
- if (dispatchError.isModule) {
241
- const decoded = client.registry.findMetaError(dispatchError.asModule);
242
- errorInfo = `${decoded.section}.${decoded.name}`;
243
- }
244
- reject(
245
- new Error(
246
- `${event.section}.${event.method}:: ExtrinsicFailed:: ${errorInfo}`
247
- )
248
- );
249
- }
250
- }
251
- });
252
- }
253
- var JsonExt = class {
254
- static stringify(obj, space) {
255
- return JSON.stringify(
256
- obj,
257
- (_, v) => typeof v === "bigint" ? `${v}n` : v,
258
- space
259
- );
260
- }
261
- static parse(str) {
262
- return JSON.parse(str, (_, v) => {
263
- if (typeof v === "string" && v.endsWith("n")) {
264
- return BigInt(v.slice(0, -1));
265
- }
266
- return v;
267
- });
268
- }
269
- };
270
-
271
161
  // src/TxSubmitter.ts
272
162
  function logExtrinsicResult(result) {
273
163
  if (process.env.DEBUG) {
@@ -399,13 +289,12 @@ var TxResult = class {
399
289
  }
400
290
  }
401
291
  if (encounteredError) {
402
- const error = dispatchErrorToString(this.client, encounteredError);
403
- if (batchErrorIndex) {
404
- this.reject(
405
- new Error(`Error in batch#${batchErrorIndex}: ${error.toString()}`)
406
- );
407
- }
408
- this.reject(new Error(`Transaction failed: ${error}`));
292
+ const error = dispatchErrorToExtrinsicError(
293
+ this.client,
294
+ encounteredError,
295
+ batchErrorIndex
296
+ );
297
+ this.reject(error);
409
298
  } else {
410
299
  this.inBlockResolve(status.asInBlock.toU8a());
411
300
  }
@@ -420,6 +309,147 @@ var TxResult = class {
420
309
  }
421
310
  };
422
311
 
312
+ // src/utils.ts
313
+ var BN = __toESM(require("bignumber.js"), 1);
314
+ var { ROUND_FLOOR } = BN;
315
+ var MICROGONS_PER_ARGON = 1e6;
316
+ function formatArgons(x) {
317
+ if (x === void 0 || x === null) return "na";
318
+ const isNegative = x < 0;
319
+ let format = (0, BN.default)(x.toString()).abs().div(MICROGONS_PER_ARGON).toFormat(2, ROUND_FLOOR);
320
+ if (format.endsWith(".00")) {
321
+ format = format.slice(0, -3);
322
+ }
323
+ return `${isNegative ? "-" : ""}\u20B3${format}`;
324
+ }
325
+ function formatPercent(x) {
326
+ if (!x) return "na";
327
+ return `${x.times(100).decimalPlaces(3)}%`;
328
+ }
329
+ function filterUndefined(obj) {
330
+ return Object.fromEntries(
331
+ Object.entries(obj).filter(
332
+ ([_, value]) => value !== void 0 && value !== null
333
+ )
334
+ );
335
+ }
336
+ async function gettersToObject(obj) {
337
+ if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
338
+ const keys = [];
339
+ for (const key in obj) {
340
+ keys.push(key);
341
+ }
342
+ if (Symbol.iterator in obj) {
343
+ const iterableToArray = [];
344
+ for (const item of obj) {
345
+ iterableToArray.push(await gettersToObject(item));
346
+ }
347
+ return iterableToArray;
348
+ }
349
+ const result = {};
350
+ for (const key of keys) {
351
+ const descriptor = Object.getOwnPropertyDescriptor(obj, key);
352
+ if (descriptor && typeof descriptor.value === "function") {
353
+ continue;
354
+ }
355
+ const value = descriptor && descriptor.get ? descriptor.get.call(obj) : obj[key];
356
+ if (typeof value === "function") continue;
357
+ result[key] = await gettersToObject(value);
358
+ }
359
+ return result;
360
+ }
361
+ function convertFixedU128ToBigNumber(fixedU128) {
362
+ const decimalFactor = new BN.default(10).pow(new BN.default(18));
363
+ const rawValue = new BN.default(fixedU128.toString());
364
+ return rawValue.div(decimalFactor);
365
+ }
366
+ function convertPermillToBigNumber(permill) {
367
+ const decimalFactor = new BN.default(1e6);
368
+ const rawValue = new BN.default(permill.toString());
369
+ return rawValue.div(decimalFactor);
370
+ }
371
+ function eventDataToJson(event) {
372
+ const obj = {};
373
+ event.data.forEach((data, index) => {
374
+ const name = event.data.names?.[index];
375
+ obj[name ?? `${index}`] = data.toJSON();
376
+ });
377
+ return obj;
378
+ }
379
+ function dispatchErrorToString(client, error) {
380
+ let message = error.toString();
381
+ if (error.isModule) {
382
+ const decoded = client.registry.findMetaError(error.asModule);
383
+ const { docs, name, section } = decoded;
384
+ message = `${section}.${name}: ${docs.join(" ")}`;
385
+ }
386
+ return message;
387
+ }
388
+ var ExtrinsicError2 = class extends Error {
389
+ constructor(errorCode, details, batchInterruptedIndex) {
390
+ super(errorCode);
391
+ this.errorCode = errorCode;
392
+ this.details = details;
393
+ this.batchInterruptedIndex = batchInterruptedIndex;
394
+ }
395
+ toString() {
396
+ if (this.batchInterruptedIndex !== void 0) {
397
+ return `${this.errorCode} ${this.details ?? ""} (Batch interrupted at index ${this.batchInterruptedIndex})`;
398
+ }
399
+ return `${this.errorCode} ${this.details ?? ""}`;
400
+ }
401
+ };
402
+ function dispatchErrorToExtrinsicError(client, error, batchInterruptedIndex) {
403
+ if (error.isModule) {
404
+ const decoded = client.registry.findMetaError(error.asModule);
405
+ const { docs, name, section } = decoded;
406
+ return new ExtrinsicError2(
407
+ `${section}.${name}`,
408
+ docs.join(" "),
409
+ batchInterruptedIndex
410
+ );
411
+ }
412
+ return new ExtrinsicError2(error.toString(), void 0, batchInterruptedIndex);
413
+ }
414
+ function checkForExtrinsicSuccess(events, client) {
415
+ return new Promise((resolve, reject) => {
416
+ for (const { event } of events) {
417
+ if (client.events.system.ExtrinsicSuccess.is(event)) {
418
+ resolve();
419
+ } else if (client.events.system.ExtrinsicFailed.is(event)) {
420
+ const [dispatchError] = event.data;
421
+ let errorInfo = dispatchError.toString();
422
+ if (dispatchError.isModule) {
423
+ const decoded = client.registry.findMetaError(dispatchError.asModule);
424
+ errorInfo = `${decoded.section}.${decoded.name}`;
425
+ }
426
+ reject(
427
+ new Error(
428
+ `${event.section}.${event.method}:: ExtrinsicFailed:: ${errorInfo}`
429
+ )
430
+ );
431
+ }
432
+ }
433
+ });
434
+ }
435
+ var JsonExt = class {
436
+ static stringify(obj, space) {
437
+ return JSON.stringify(
438
+ obj,
439
+ (_, v) => typeof v === "bigint" ? `${v}n` : v,
440
+ space
441
+ );
442
+ }
443
+ static parse(str) {
444
+ return JSON.parse(str, (_, v) => {
445
+ if (typeof v === "string" && v.endsWith("n")) {
446
+ return BigInt(v.slice(0, -1));
447
+ }
448
+ return v;
449
+ });
450
+ }
451
+ };
452
+
423
453
  // src/AccountRegistry.ts
424
454
  var AccountRegistry = class _AccountRegistry {
425
455
  namedAccounts = /* @__PURE__ */ new Map();
@@ -652,7 +682,7 @@ var MiningRotations = class {
652
682
  const slot1StartTick = this.genesisTick + this.miningConfig.slotBiddingStartAfterTicks + ticksBetweenSlots;
653
683
  if (tick < slot1StartTick) return 0;
654
684
  const ticksSinceSlot1 = tick - slot1StartTick;
655
- return Math.floor(ticksSinceSlot1 / ticksBetweenSlots);
685
+ return Math.floor(ticksSinceSlot1 / ticksBetweenSlots) + 1;
656
686
  }
657
687
  async getForHeader(client, header) {
658
688
  if (header.number.toNumber() === 0) return 0;
@@ -832,6 +862,14 @@ var Accountset = class {
832
862
  );
833
863
  }
834
864
  }
865
+ async submitterBalance(blockHash) {
866
+ const client = await this.client;
867
+ const api = blockHash ? await client.at(blockHash) : client;
868
+ const accountData = await api.query.system.account(
869
+ this.txSubmitterPair.address
870
+ );
871
+ return accountData.data.free.toBigInt();
872
+ }
835
873
  async balance(blockHash) {
836
874
  const client = await this.client;
837
875
  const api = blockHash ? await client.at(blockHash) : client;
@@ -1094,18 +1132,18 @@ var Accountset = class {
1094
1132
  return new TxSubmitter(client, tx, this.txSubmitterPair);
1095
1133
  }
1096
1134
  /**
1097
- * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1135
+ * Create but don't submit a mining bid transaction.
1136
+ * @param options
1098
1137
  */
1099
- async createMiningBids(options) {
1100
- const accounts = this.getAccountsInRange(options.subaccountRange);
1138
+ async createMiningBidTx(options) {
1101
1139
  const client = await this.client;
1102
- let tip = options.tip ?? 0n;
1140
+ const { bidAmount, subaccounts, sendRewardsToSeed } = options;
1103
1141
  const batch = client.tx.utility.batch(
1104
- accounts.map((x) => {
1142
+ subaccounts.map((x) => {
1105
1143
  const keys = this.keys();
1106
- const rewards = options.sendRewardsToSeed ? { Account: this.seedAddress } : { Owner: null };
1144
+ const rewards = sendRewardsToSeed ? { Account: this.seedAddress } : { Owner: null };
1107
1145
  return client.tx.miningSlot.bid(
1108
- options.bidAmount,
1146
+ bidAmount,
1109
1147
  rewards,
1110
1148
  {
1111
1149
  grandpa: keys.gran.rawPublicKey,
@@ -1119,7 +1157,19 @@ var Accountset = class {
1119
1157
  if (this.isProxy) {
1120
1158
  tx = client.tx.proxy.proxy(this.seedAddress, "MiningBid", batch);
1121
1159
  }
1122
- const submitter = new TxSubmitter(client, tx, this.txSubmitterPair);
1160
+ return new TxSubmitter(client, tx, this.txSubmitterPair);
1161
+ }
1162
+ /**
1163
+ * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1164
+ */
1165
+ async createMiningBids(options) {
1166
+ const accounts = this.getAccountsInRange(options.subaccountRange);
1167
+ const client = await this.client;
1168
+ const submitter = await this.createMiningBidTx({
1169
+ ...options,
1170
+ subaccounts: accounts
1171
+ });
1172
+ const { tip = 0n } = options;
1123
1173
  const txFee = await submitter.feeEstimate(tip);
1124
1174
  let minBalance = options.bidAmount * BigInt(accounts.length);
1125
1175
  let totalFees = tip + 1n + txFee;
@@ -1563,27 +1613,24 @@ var VaultMonitor = class {
1563
1613
  }
1564
1614
  };
1565
1615
 
1566
- // src/CohortBidder.ts
1567
- var CohortBidder = class _CohortBidder {
1568
- constructor(accountset, cohortId, subaccounts, options) {
1569
- this.accountset = accountset;
1616
+ // src/CohortBidderHistory.ts
1617
+ var CohortBidderHistory = class _CohortBidderHistory {
1618
+ constructor(cohortId, subaccounts) {
1570
1619
  this.cohortId = cohortId;
1571
1620
  this.subaccounts = subaccounts;
1572
- this.options = options;
1621
+ this.maxSeatsInPlay = this.subaccounts.length;
1573
1622
  this.subaccounts.forEach((x) => {
1574
- this.allAddresses.add(x.address);
1623
+ this.myAddresses.add(x.address);
1575
1624
  });
1576
1625
  }
1577
- get client() {
1578
- return this.accountset.client;
1579
- }
1626
+ bidHistory = [];
1580
1627
  stats = {
1581
1628
  // number of seats won
1582
- seats: 0,
1629
+ seatsWon: 0,
1583
1630
  // sum of argons bid in successful bids
1584
1631
  totalArgonsBid: 0n,
1585
1632
  // total number of bids placed (includes 1 per seat)
1586
- bids: 0,
1633
+ bidsAttempted: 0,
1587
1634
  // fees including the tip
1588
1635
  fees: 0n,
1589
1636
  // Max bid per seat
@@ -1595,16 +1642,157 @@ var CohortBidder = class _CohortBidder {
1595
1642
  // The cohort expected argons per block
1596
1643
  cohortArgonsPerBlock: 0n,
1597
1644
  // The last block that bids are synced to
1598
- lastBlock: 0
1645
+ lastBlockNumber: 0
1599
1646
  };
1647
+ lastBids = [];
1648
+ myAddresses = /* @__PURE__ */ new Set();
1649
+ maxSeatsInPlay = 0;
1650
+ async init(client) {
1651
+ if (!this.stats.argonotsPerSeat) {
1652
+ const startingStats = await _CohortBidderHistory.getStartingData(client);
1653
+ Object.assign(this.stats, startingStats);
1654
+ }
1655
+ }
1656
+ maybeReducingSeats(maxSeats, reason, historyEntry) {
1657
+ if (this.maxSeatsInPlay > maxSeats) {
1658
+ historyEntry.maxSeatsReductionReason = reason;
1659
+ }
1660
+ this.maxSeatsInPlay = maxSeats;
1661
+ historyEntry.maxSeatsInPlay = maxSeats;
1662
+ }
1663
+ trackChange(next, blockNumber, tick, isLastEntry = false) {
1664
+ let winningBids = 0;
1665
+ let totalArgonsBid = 0n;
1666
+ const nextEntrants = [];
1667
+ for (const x of next) {
1668
+ const bid = x.bid.toBigInt();
1669
+ const address = x.accountId.toHuman();
1670
+ nextEntrants.push({ address, bid });
1671
+ if (this.myAddresses.has(address)) {
1672
+ winningBids++;
1673
+ totalArgonsBid += bid;
1674
+ }
1675
+ }
1676
+ this.stats.seatsWon = winningBids;
1677
+ this.stats.totalArgonsBid = totalArgonsBid;
1678
+ this.stats.lastBlockNumber = Math.max(
1679
+ blockNumber,
1680
+ this.stats.lastBlockNumber
1681
+ );
1682
+ const historyEntry = {
1683
+ cohortId: this.cohortId,
1684
+ blockNumber,
1685
+ tick,
1686
+ bidChanges: [],
1687
+ winningSeats: winningBids,
1688
+ maxSeatsInPlay: this.maxSeatsInPlay
1689
+ };
1690
+ const hasDiffs = JsonExt.stringify(nextEntrants) !== JsonExt.stringify(this.lastBids);
1691
+ if (!isLastEntry || hasDiffs) {
1692
+ this.bidHistory.unshift(historyEntry);
1693
+ }
1694
+ if (hasDiffs) {
1695
+ nextEntrants.forEach(({ address, bid }, i) => {
1696
+ const prevBidIndex = this.lastBids.findIndex(
1697
+ (y) => y.address === address
1698
+ );
1699
+ const entry = {
1700
+ address,
1701
+ bidAmount: bid,
1702
+ bidPosition: i,
1703
+ prevPosition: prevBidIndex === -1 ? null : prevBidIndex
1704
+ };
1705
+ if (prevBidIndex !== -1) {
1706
+ const prevBidAmount = this.lastBids[prevBidIndex].bid;
1707
+ if (prevBidAmount !== bid) {
1708
+ entry.prevBidAmount = prevBidAmount;
1709
+ }
1710
+ }
1711
+ historyEntry.bidChanges.push(entry);
1712
+ });
1713
+ this.lastBids.forEach(({ address, bid }, i) => {
1714
+ const nextBid = nextEntrants.some((y) => y.address === address);
1715
+ if (!nextBid) {
1716
+ historyEntry.bidChanges.push({
1717
+ address,
1718
+ bidAmount: bid,
1719
+ bidPosition: null,
1720
+ prevPosition: i
1721
+ });
1722
+ }
1723
+ });
1724
+ this.lastBids = nextEntrants;
1725
+ }
1726
+ return historyEntry;
1727
+ }
1728
+ onBidResult(historyEntry, param) {
1729
+ const {
1730
+ txFeePlusTip,
1731
+ bidPerSeat,
1732
+ bidsAttempted,
1733
+ successfulBids,
1734
+ blockNumber,
1735
+ bidError
1736
+ } = param;
1737
+ this.stats.fees += txFeePlusTip;
1738
+ this.stats.bidsAttempted += bidsAttempted;
1739
+ if (bidPerSeat > this.stats.maxBidPerSeat) {
1740
+ this.stats.maxBidPerSeat = bidPerSeat;
1741
+ }
1742
+ if (blockNumber !== void 0) {
1743
+ this.stats.lastBlockNumber = Math.max(
1744
+ blockNumber,
1745
+ this.stats.lastBlockNumber
1746
+ );
1747
+ }
1748
+ historyEntry.myBidsPlaced.failureReason = bidError;
1749
+ historyEntry.myBidsPlaced.successfulBids = successfulBids;
1750
+ historyEntry.myBidsPlaced.txFeePlusTip = txFeePlusTip;
1751
+ }
1752
+ static async getStartingData(api) {
1753
+ const argonotPrice = await api.query.priceIndex.current();
1754
+ let argonotUsdPrice = 0;
1755
+ if (argonotPrice.isSome) {
1756
+ argonotUsdPrice = convertFixedU128ToBigNumber(
1757
+ argonotPrice.unwrap().argonotUsdPrice.toBigInt()
1758
+ ).toNumber();
1759
+ }
1760
+ const argonotsPerSeat = await api.query.miningSlot.argonotsPerMiningSeat().then((x) => x.toBigInt());
1761
+ const cohortArgonsPerBlock = await api.query.blockRewards.argonsPerBlock().then((x) => x.toBigInt());
1762
+ return { argonotsPerSeat, argonotUsdPrice, cohortArgonsPerBlock };
1763
+ }
1764
+ };
1765
+
1766
+ // src/CohortBidder.ts
1767
+ var CohortBidder = class {
1768
+ constructor(accountset, cohortId, subaccounts, options) {
1769
+ this.accountset = accountset;
1770
+ this.cohortId = cohortId;
1771
+ this.subaccounts = subaccounts;
1772
+ this.options = options;
1773
+ this.history = new CohortBidderHistory(cohortId, subaccounts);
1774
+ this.subaccounts.forEach((x) => {
1775
+ this.myAddresses.add(x.address);
1776
+ });
1777
+ }
1778
+ get client() {
1779
+ return this.accountset.client;
1780
+ }
1781
+ get stats() {
1782
+ return this.history.stats;
1783
+ }
1784
+ get bidHistory() {
1785
+ return this.history.bidHistory;
1786
+ }
1600
1787
  unsubscribe;
1601
1788
  pendingRequest;
1602
1789
  retryTimeout;
1603
1790
  isStopped = false;
1604
1791
  needsRebid = false;
1605
1792
  lastBidTime = 0;
1793
+ history;
1606
1794
  millisPerTick;
1607
- allAddresses = /* @__PURE__ */ new Set();
1795
+ myAddresses = /* @__PURE__ */ new Set();
1608
1796
  async stop() {
1609
1797
  if (this.isStopped) return this.stats;
1610
1798
  this.isStopped = true;
@@ -1614,70 +1802,59 @@ var CohortBidder = class _CohortBidder {
1614
1802
  this.unsubscribe();
1615
1803
  }
1616
1804
  const client = await this.client;
1617
- const [nextCohort, nextCohortId, blockNumber] = await new Promise(async (resolve) => {
1618
- const unsub = await client.queryMulti(
1619
- [
1620
- client.query.miningSlot.nextSlotCohort,
1621
- client.query.miningSlot.nextCohortId,
1622
- client.query.miningSlot.isNextSlotBiddingOpen,
1623
- client.query.system.number
1624
- ],
1625
- ([nextCohort2, nextCohortId2, isBiddingStillOpen, blockNumber2]) => {
1626
- if (nextCohortId2.toNumber() !== this.cohortId || isBiddingStillOpen.isFalse) {
1627
- unsub();
1628
- resolve([nextCohort2, nextCohortId2, blockNumber2]);
1805
+ const [nextCohortId, isBiddingOpen] = await client.queryMulti([
1806
+ client.query.miningSlot.nextCohortId,
1807
+ client.query.miningSlot.isNextSlotBiddingOpen
1808
+ ]);
1809
+ if (nextCohortId.toNumber() === this.cohortId && isBiddingOpen.isTrue) {
1810
+ console.log("Bidding is still open, waiting for it to close");
1811
+ await new Promise(async (resolve) => {
1812
+ const unsub = await client.query.miningSlot.isNextSlotBiddingOpen(
1813
+ (isOpen) => {
1814
+ if (isOpen.isFalse) {
1815
+ unsub();
1816
+ resolve();
1817
+ }
1629
1818
  }
1630
- }
1631
- );
1632
- });
1633
- void await this.pendingRequest;
1634
- if (nextCohortId.toNumber() === this.cohortId) {
1635
- console.log("Bidder updating stats with bid queue");
1636
- this.updateStats(nextCohort);
1637
- } else {
1638
- const bestBlock = await client.rpc.chain.getBlockHash();
1639
- const api = await client.at(bestBlock);
1640
- const wonIndices = await api.query.miningSlot.accountIndexLookup.multi([...this.allAddresses]).then((x) => x.filter((x2) => x2.isSome).map((x2) => x2.value));
1641
- const wonSeats = await api.query.miningSlot.activeMinersByIndex.multi(wonIndices).then(
1642
- (x) => x.filter(
1643
- (x2) => x2.isSome && x2.value.cohortId.toNumber() === this.cohortId
1644
- ).map((x2) => x2.value)
1645
- );
1646
- console.log("Bidder updating stats with finalized cohort");
1647
- this.updateStats(wonSeats);
1819
+ );
1820
+ });
1648
1821
  }
1649
- this.stats.lastBlock = Math.max(
1650
- blockNumber.toNumber(),
1651
- this.stats.lastBlock
1652
- );
1822
+ void await this.pendingRequest;
1823
+ let header = await client.rpc.chain.getHeader();
1824
+ while (true) {
1825
+ const api2 = await client.at(header.hash);
1826
+ const cohortId = await api2.query.miningSlot.nextCohortId();
1827
+ if (cohortId.toNumber() === this.cohortId) {
1828
+ break;
1829
+ }
1830
+ header = await client.rpc.chain.getHeader(header.parentHash);
1831
+ }
1832
+ const api = await client.at(header.hash);
1833
+ const tick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1834
+ const cohort = await api.query.miningSlot.nextSlotCohort();
1835
+ this.history.trackChange(cohort, header.number.toNumber(), tick, true);
1836
+ console.log("Bidder stopped", {
1837
+ cohortId: this.cohortId,
1838
+ blockNumber: header.number.toNumber(),
1839
+ tick,
1840
+ cohort: cohort.map((x) => ({
1841
+ address: x.accountId.toHuman(),
1842
+ bid: x.bid.toBigInt()
1843
+ }))
1844
+ });
1653
1845
  return this.stats;
1654
1846
  }
1655
- static async getStartingData(api) {
1656
- const argonotPrice = await api.query.priceIndex.current();
1657
- let argonotUsdPrice = 0;
1658
- if (argonotPrice.isSome) {
1659
- argonotUsdPrice = convertFixedU128ToBigNumber(
1660
- argonotPrice.unwrap().argonotUsdPrice.toBigInt()
1661
- ).toNumber();
1662
- }
1663
- const argonotsPerSeat = await api.query.miningSlot.argonotsPerMiningSeat().then((x) => x.toBigInt());
1664
- const cohortArgonsPerBlock = await api.query.blockRewards.argonsPerBlock().then((x) => x.toBigInt());
1665
- return { argonotsPerSeat, argonotUsdPrice, cohortArgonsPerBlock };
1666
- }
1667
1847
  async start() {
1668
1848
  console.log(`Starting cohort ${this.cohortId} bidder`, {
1669
1849
  maxBid: formatArgons(this.options.maxBid),
1670
1850
  minBid: formatArgons(this.options.minBid),
1671
1851
  bidIncrement: formatArgons(this.options.bidIncrement),
1672
- maxBalance: formatArgons(this.options.maxBalance),
1852
+ maxBudget: formatArgons(this.options.maxBudget),
1673
1853
  bidDelay: this.options.bidDelay,
1674
1854
  subaccounts: this.subaccounts
1675
1855
  });
1676
1856
  const client = await this.client;
1677
- if (!this.stats.argonotsPerSeat) {
1678
- const startingStats = await _CohortBidder.getStartingData(client);
1679
- Object.assign(this.stats, startingStats);
1680
- }
1857
+ await this.history.init(client);
1681
1858
  this.millisPerTick ??= await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1682
1859
  this.unsubscribe = await client.queryMulti(
1683
1860
  [
@@ -1691,24 +1868,27 @@ var CohortBidder = class _CohortBidder {
1691
1868
  }
1692
1869
  );
1693
1870
  }
1694
- updateStats(next) {
1695
- let seats = 0;
1696
- let totalArgonsBid = 0n;
1697
- for (const x of next) {
1698
- if (this.allAddresses.has(x.accountId.toHuman())) {
1699
- seats++;
1700
- totalArgonsBid += x.bid.toBigInt();
1701
- }
1702
- }
1703
- this.stats.seats = seats;
1704
- this.stats.totalArgonsBid = totalArgonsBid;
1705
- }
1706
1871
  async checkSeats(next) {
1707
- if (this.isStopped || this.pendingRequest) return;
1872
+ if (this.isStopped) return;
1873
+ clearTimeout(this.retryTimeout);
1874
+ const client = await this.client;
1875
+ const bestBlock = await client.rpc.chain.getBlockHash();
1876
+ const api = await client.at(bestBlock);
1877
+ const blockNumber = await api.query.system.number().then((x) => x.toNumber());
1878
+ if (this.bidHistory[0]?.blockNumber >= blockNumber) {
1879
+ return;
1880
+ }
1881
+ const tick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1882
+ const historyEntry = this.history.trackChange(next, blockNumber, tick);
1883
+ if (this.pendingRequest) return;
1708
1884
  const ticksSinceLastBid = Math.floor(
1709
1885
  (Date.now() - this.lastBidTime) / this.millisPerTick
1710
1886
  );
1711
1887
  if (ticksSinceLastBid < this.options.bidDelay) {
1888
+ this.retryTimeout = setTimeout(
1889
+ () => void this.checkCurrentSeats(),
1890
+ this.millisPerTick
1891
+ );
1712
1892
  return;
1713
1893
  }
1714
1894
  console.log(
@@ -1716,12 +1896,19 @@ var CohortBidder = class _CohortBidder {
1716
1896
  this.cohortId,
1717
1897
  this.subaccounts.map((x) => x.index)
1718
1898
  );
1719
- this.updateStats(next);
1720
- this.needsRebid = this.subaccounts.some(
1721
- (x) => !next.some((y) => y.accountId.toHuman() === x.address)
1722
- );
1899
+ const winningBids = historyEntry.winningSeats;
1900
+ this.needsRebid = winningBids < this.subaccounts.length;
1723
1901
  if (!this.needsRebid) return;
1724
- const lowestBid = next.at(-1)?.bid.toBigInt() ?? -this.options.bidIncrement;
1902
+ const winningAddresses = new Set(next.map((x) => x.accountId.toHuman()));
1903
+ let lowestBid = -this.options.bidIncrement;
1904
+ if (next.length) {
1905
+ for (let i = next.length - 1; i >= 0; i--) {
1906
+ if (!this.myAddresses.has(next[i].accountId.toHuman())) {
1907
+ lowestBid = next.at(i).bid.toBigInt();
1908
+ break;
1909
+ }
1910
+ }
1911
+ }
1725
1912
  const MIN_INCREMENT = 10000n;
1726
1913
  let nextBid = lowestBid + this.options.bidIncrement;
1727
1914
  if (nextBid < this.options.minBid) {
@@ -1729,83 +1916,119 @@ var CohortBidder = class _CohortBidder {
1729
1916
  }
1730
1917
  if (nextBid > this.options.maxBid) {
1731
1918
  nextBid = this.options.maxBid;
1732
- if (nextBid - lowestBid < MIN_INCREMENT) {
1733
- console.log(
1734
- `Can't make any more bids for ${this.cohortId} with given constraints.`,
1735
- {
1736
- lowestCurrentBid: formatArgons(lowestBid),
1737
- nextAttemptedBid: formatArgons(nextBid),
1738
- maxBid: formatArgons(this.options.maxBid)
1739
- }
1740
- );
1741
- return;
1919
+ }
1920
+ const fakeTx = await this.accountset.createMiningBidTx({
1921
+ subaccounts: this.subaccounts,
1922
+ bidAmount: nextBid,
1923
+ sendRewardsToSeed: true
1924
+ });
1925
+ let availableBalanceForBids = await api.query.system.account(this.accountset.txSubmitterPair.address).then((x) => x.data.free.toBigInt());
1926
+ for (const bid of next) {
1927
+ if (this.myAddresses.has(bid.accountId.toHuman())) {
1928
+ availableBalanceForBids += bid.bid.toBigInt();
1742
1929
  }
1743
1930
  }
1931
+ const tip = this.options.tipPerTransaction ?? 0n;
1932
+ const feeEstimate = await fakeTx.feeEstimate(tip);
1933
+ const feePlusTip = feeEstimate + tip;
1934
+ let budgetForSeats = this.options.maxBudget - feePlusTip;
1935
+ if (budgetForSeats > availableBalanceForBids) {
1936
+ budgetForSeats = availableBalanceForBids - feePlusTip;
1937
+ }
1744
1938
  if (nextBid < lowestBid) {
1745
1939
  console.log(
1746
1940
  `Can't bid ${formatArgons(nextBid)}. Current lowest bid is ${formatArgons(
1747
1941
  lowestBid
1748
1942
  )}.`
1749
1943
  );
1944
+ this.history.maybeReducingSeats(
1945
+ winningBids,
1946
+ "MaxBidTooLow" /* MaxBidTooLow */,
1947
+ historyEntry
1948
+ );
1750
1949
  return;
1751
1950
  }
1752
- const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(this.options.maxBalance / nextBid);
1753
- if (seatsInBudget <= 0) {
1951
+ if (nextBid - lowestBid < MIN_INCREMENT) {
1754
1952
  console.log(
1755
- `Can't afford any seats at ${formatArgons(nextBid)}. Would exceed our max balance of ${formatArgons(this.options.maxBalance)}.`
1953
+ `Can't make any more bids for ${this.cohortId} with given constraints.`,
1954
+ {
1955
+ lowestCurrentBid: formatArgons(lowestBid),
1956
+ nextAttemptedBid: formatArgons(nextBid),
1957
+ maxBid: formatArgons(this.options.maxBid)
1958
+ }
1959
+ );
1960
+ this.history.maybeReducingSeats(
1961
+ winningBids,
1962
+ "MaxBidTooLow" /* MaxBidTooLow */,
1963
+ historyEntry
1756
1964
  );
1757
1965
  return;
1758
1966
  }
1759
- if (this.subaccounts.length > seatsInBudget) {
1760
- const toKeep = [];
1761
- for (const account of this.subaccounts) {
1762
- if (toKeep.length >= seatsInBudget) break;
1763
- if (account.isRebid) {
1764
- toKeep.push(account);
1765
- }
1766
- }
1767
- for (const account of this.subaccounts) {
1768
- if (toKeep.length >= seatsInBudget) break;
1769
- if (!account.isRebid) {
1770
- toKeep.push(account);
1771
- }
1772
- }
1773
- const removedIndices = this.subaccounts.filter((x) => !toKeep.some((y) => y.index === x.index)).map((x) => x.index);
1774
- this.subaccounts = toKeep;
1775
- console.log("Had to remove some subaccounts to fit in budget:", {
1776
- removedIndices,
1777
- seatsInBudget,
1778
- budget: formatArgons(this.options.maxBalance)
1967
+ const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(budgetForSeats / nextBid);
1968
+ let accountsToUse = [...this.subaccounts];
1969
+ if (accountsToUse.length > seatsInBudget) {
1970
+ const reason = availableBalanceForBids - feePlusTip < nextBid * BigInt(seatsInBudget) ? "InsufficientFunds" /* InsufficientFunds */ : "MaxBudgetTooLow" /* MaxBudgetTooLow */;
1971
+ this.history.maybeReducingSeats(seatsInBudget, reason, historyEntry);
1972
+ accountsToUse.sort((a, b) => {
1973
+ const isWinningA = winningAddresses.has(a.address);
1974
+ const isWinningB = winningAddresses.has(b.address);
1975
+ if (isWinningA && !isWinningB) return -1;
1976
+ if (!isWinningA && isWinningB) return 1;
1977
+ if (a.isRebid && !b.isRebid) return -1;
1978
+ if (!a.isRebid && b.isRebid) return 1;
1979
+ return a.index - b.index;
1779
1980
  });
1981
+ accountsToUse.length = seatsInBudget;
1982
+ }
1983
+ if (accountsToUse.length > winningBids) {
1984
+ historyEntry.myBidsPlaced = {
1985
+ bids: accountsToUse.length,
1986
+ bidPerSeat: nextBid,
1987
+ txFeePlusTip: feePlusTip,
1988
+ successfulBids: 0
1989
+ };
1990
+ this.pendingRequest = this.bid(nextBid, accountsToUse, historyEntry);
1991
+ } else if (historyEntry.bidChanges.length === 0) {
1992
+ this.history.bidHistory.shift();
1780
1993
  }
1781
- this.pendingRequest = this.bid(
1782
- nextBid,
1783
- this.subaccounts.map((x) => x.index)
1784
- );
1785
1994
  this.needsRebid = false;
1786
1995
  }
1787
- async bid(bidPerSeat, subaccountRange) {
1788
- if (!subaccountRange.length) return;
1996
+ async bid(bidPerSeat, subaccounts, historyEntry) {
1789
1997
  const prevLastBidTime = this.lastBidTime;
1790
1998
  try {
1791
1999
  this.lastBidTime = Date.now();
1792
- const result = await this.accountset.createMiningBids({
1793
- subaccountRange,
2000
+ const submitter = await this.accountset.createMiningBidTx({
2001
+ subaccounts,
1794
2002
  bidAmount: bidPerSeat,
1795
2003
  sendRewardsToSeed: true
1796
2004
  });
1797
- if (result.blockHash) {
2005
+ const tip = this.options.tipPerTransaction ?? 0n;
2006
+ const txResult = await submitter.submit({
2007
+ tip,
2008
+ useLatestNonce: true
2009
+ });
2010
+ const bidError = await txResult.inBlockPromise.then(() => void 0).catch((x) => x);
2011
+ let blockNumber;
2012
+ if (txResult.includedInBlock) {
1798
2013
  const client = await this.client;
1799
- const api = await client.at(result.blockHash);
1800
- this.stats.lastBlock = await api.query.system.number().then((x) => x.toNumber());
2014
+ const api = await client.at(txResult.includedInBlock);
2015
+ blockNumber = await api.query.system.number().then((x) => x.toNumber());
1801
2016
  }
1802
- this.stats.fees += result.finalFee ?? 0n;
1803
- this.stats.bids += subaccountRange.length;
1804
- if (bidPerSeat > this.stats.maxBidPerSeat) {
1805
- this.stats.maxBidPerSeat = bidPerSeat;
1806
- }
1807
- console.log("Done creating bids for cohort", this.cohortId);
1808
- if (result.bidError) throw result.bidError;
2017
+ const successfulBids = txResult.batchInterruptedIndex ?? subaccounts.length;
2018
+ this.history.onBidResult(historyEntry, {
2019
+ blockNumber,
2020
+ successfulBids,
2021
+ bidPerSeat,
2022
+ txFeePlusTip: txResult.finalFee ?? 0n,
2023
+ bidsAttempted: subaccounts.length,
2024
+ bidError
2025
+ });
2026
+ console.log("Done creating bids for cohort", {
2027
+ successfulBids,
2028
+ bidPerSeat,
2029
+ blockNumber
2030
+ });
2031
+ if (bidError) throw bidError;
1809
2032
  } catch (err) {
1810
2033
  this.lastBidTime = prevLastBidTime;
1811
2034
  console.error(`Error bidding for cohort ${this.cohortId}:`, err);
@@ -2483,8 +2706,8 @@ function vaultCli() {
2483
2706
  ).action(async ({ tip, argons, vaultId, ratio }) => {
2484
2707
  const accountset = await accountsetFromCli(program2);
2485
2708
  const client = await accountset.client;
2486
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2487
- const microgons = BigInt(argons * 1e6);
2709
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2710
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2488
2711
  const rawVault = (await client.query.vaults.vaultsById(vaultId)).unwrap();
2489
2712
  if (rawVault.operatorAccountId.toHuman() !== accountset.seedAddress) {
2490
2713
  console.error("Vault does not belong to this account");
@@ -2544,8 +2767,8 @@ function vaultCli() {
2544
2767
  }
2545
2768
  const accountset = await accountsetFromCli(program2);
2546
2769
  const client = await accountset.client;
2547
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2548
- const microgons = BigInt(argons * 1e6);
2770
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2771
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2549
2772
  const bitcoinLocks = new BitcoinLocks(Promise.resolve(client));
2550
2773
  const existentialDeposit = client.consts.balances.existentialDeposit.toBigInt();
2551
2774
  const tickDuration = (await client.query.ticks.genesisTicker()).tickDurationMillis.toNumber();
@@ -2750,7 +2973,7 @@ function miningCli() {
2750
2973
  const balance = await accountset.balance();
2751
2974
  const feeWiggleRoom = BigInt(25e3);
2752
2975
  const amountAvailable = balance - feeWiggleRoom;
2753
- let maxBidAmount = maxBid ? BigInt(maxBid * 1e6) : void 0;
2976
+ let maxBidAmount = maxBid ? BigInt(maxBid * MICROGONS_PER_ARGON) : void 0;
2754
2977
  let maxBalanceToUse = amountAvailable;
2755
2978
  if (maxBalance !== void 0) {
2756
2979
  if (maxBalance.endsWith("%")) {
@@ -2762,7 +2985,7 @@ function miningCli() {
2762
2985
  maxBalanceToUse = amountToBid;
2763
2986
  } else {
2764
2987
  maxBalanceToUse = BigInt(
2765
- Math.floor(parseFloat(maxBalance) * 1e6)
2988
+ Math.floor(parseFloat(maxBalance) * MICROGONS_PER_ARGON)
2766
2989
  );
2767
2990
  }
2768
2991
  maxBidAmount ??= maxBalanceToUse / BigInt(seatsToWin);
@@ -2784,9 +3007,11 @@ function miningCli() {
2784
3007
  subaccountRange,
2785
3008
  {
2786
3009
  maxBid: maxBidAmount,
2787
- minBid: BigInt((minBid ?? 0) * 1e6),
2788
- bidIncrement: BigInt(Math.floor(bidIncrement * 1e6)),
2789
- maxBalance: maxBalanceToUse,
3010
+ minBid: BigInt((minBid ?? 0) * MICROGONS_PER_ARGON),
3011
+ bidIncrement: BigInt(
3012
+ Math.floor(bidIncrement * MICROGONS_PER_ARGON)
3013
+ ),
3014
+ maxBudget: maxBalanceToUse,
2790
3015
  bidDelay
2791
3016
  }
2792
3017
  );
@@ -2818,7 +3043,10 @@ function miningCli() {
2818
3043
  );
2819
3044
  const tx = client.tx.utility.batchAll([
2820
3045
  client.tx.proxy.addProxy(address, "MiningBid", 0),
2821
- client.tx.balances.transferAllowDeath(address, BigInt(feeArgons * 1e6))
3046
+ client.tx.balances.transferAllowDeath(
3047
+ address,
3048
+ BigInt(feeArgons * MICROGONS_PER_ARGON)
3049
+ )
2822
3050
  ]);
2823
3051
  let keypair;
2824
3052
  try {
@@ -2867,8 +3095,8 @@ function liquidityCli() {
2867
3095
  parseFloat
2868
3096
  ).action(async ({ tip, argons, vaultId }) => {
2869
3097
  const accountset = await accountsetFromCli(program2);
2870
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2871
- const microgons = BigInt(argons * 1e6);
3098
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
3099
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2872
3100
  const bidPool = new BidPool(
2873
3101
  accountset.client,
2874
3102
  accountset.txSubmitterPair
@@ -2893,7 +3121,7 @@ function liquidityCli() {
2893
3121
  "The tip to include with the transaction",
2894
3122
  parseFloat
2895
3123
  ).action(async ({ maxArgons, minPctSharing, tip }) => {
2896
- const maxAmountPerSlot = BigInt(maxArgons * 1e6);
3124
+ const maxAmountPerSlot = BigInt(maxArgons * MICROGONS_PER_ARGON);
2897
3125
  const accountset = await accountsetFromCli(program2);
2898
3126
  const vaults = new VaultMonitor(
2899
3127
  accountset,
@@ -2906,7 +3134,7 @@ function liquidityCli() {
2906
3134
  accountset.client,
2907
3135
  accountset.txSubmitterPair
2908
3136
  );
2909
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
3137
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2910
3138
  console.log("Waiting for liquidity pool space...");
2911
3139
  vaults.events.on(
2912
3140
  "liquidity-pool-space-above",
@@ -2945,7 +3173,7 @@ function bitcoinCli() {
2945
3173
  ).description("Watch for bitcoin space available").action(async ({ argons }) => {
2946
3174
  const accountset = await accountsetFromCli(program2);
2947
3175
  const bot = new VaultMonitor(accountset, {
2948
- bitcoinSpaceAvailable: argons ? BigInt(argons * 1e6) : 1n
3176
+ bitcoinSpaceAvailable: argons ? BigInt(argons * MICROGONS_PER_ARGON) : 1n
2949
3177
  });
2950
3178
  bot.events.on("bitcoin-space-above", async (vaultId, amount) => {
2951
3179
  const vault = bot.vaultsById[vaultId];
@@ -2974,13 +3202,13 @@ function bitcoinCli() {
2974
3202
  parseFloat,
2975
3203
  0
2976
3204
  ).action(async ({ argons, bitcoinXpub, maxLockFee, tip }) => {
2977
- const amountToLock = BigInt(argons * 1e6);
3205
+ const amountToLock = BigInt(argons * MICROGONS_PER_ARGON);
2978
3206
  const accountset = await accountsetFromCli(program2);
2979
3207
  await BitcoinLocks.waitForSpace(accountset, {
2980
3208
  argonAmount: amountToLock,
2981
3209
  bitcoinXpub,
2982
- maxLockFee: maxLockFee !== void 0 ? BigInt(maxLockFee * 1e6) : void 0,
2983
- tip: BigInt(tip * 1e6)
3210
+ maxLockFee: maxLockFee !== void 0 ? BigInt(maxLockFee * MICROGONS_PER_ARGON) : void 0,
3211
+ tip: BigInt(tip * MICROGONS_PER_ARGON)
2984
3212
  }).then(({ vaultId, satoshis, txFee, btcFee }) => {
2985
3213
  console.log(
2986
3214
  `Locked ${satoshis} satoshis in vault ${vaultId}. Tx fee=${formatArgons(
@@ -3005,8 +3233,13 @@ async function keyringFromFile(opts) {
3005
3233
  }
3006
3234
  const path = opts.filePath.replace("~", os.homedir());
3007
3235
  const json = JSON.parse(await readFile(path, "utf-8"));
3236
+ let passphrase = opts.passphrase;
3237
+ if (opts.passphraseFile) {
3238
+ const passphrasePath = opts.passphraseFile.replace("~", os.homedir());
3239
+ passphrase = await readFile(passphrasePath, "utf-8");
3240
+ }
3008
3241
  const mainAccount = new import_api.Keyring().createFromJson(json);
3009
- mainAccount.decodePkcs8(opts.passphrase);
3242
+ mainAccount.decodePkcs8(passphrase);
3010
3243
  return mainAccount;
3011
3244
  }
3012
3245
  async function saveKeyringPair(opts) {
@@ -3041,6 +3274,11 @@ function buildCli() {
3041
3274
  "--account-passphrase <password>",
3042
3275
  "The password for your seed file"
3043
3276
  ).env("ACCOUNT_PASSPHRASE")
3277
+ ).addOption(
3278
+ new import_extra_typings6.Option(
3279
+ "--account-passphrase-file <path>",
3280
+ "The path to a password for your seed file"
3281
+ )
3044
3282
  ).addOption(
3045
3283
  new import_extra_typings6.Option(
3046
3284
  "-s, --subaccounts <range>",
@@ -3057,7 +3295,8 @@ async function accountsetFromCli(program2, proxyForAddress) {
3057
3295
  if (opts.accountFilePath) {
3058
3296
  keypair = await keyringFromFile({
3059
3297
  filePath: opts.accountFilePath,
3060
- passphrase: opts.accountPassphrase
3298
+ passphrase: opts.accountPassphrase,
3299
+ passphraseFile: opts.accountPassphraseFile
3061
3300
  });
3062
3301
  }
3063
3302
  if (!keypair) {