@argonprotocol/mainchain 1.1.0-rc.7 → 1.1.0

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