@argonprotocol/mainchain 1.1.0-rc.7 → 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/clis/index.js CHANGED
@@ -32,8 +32,10 @@ __export(index_exports, {
32
32
  BitcoinLocks: () => BitcoinLocks,
33
33
  BlockWatch: () => BlockWatch,
34
34
  CohortBidder: () => CohortBidder,
35
+ ExtrinsicError: () => ExtrinsicError2,
35
36
  JsonExt: () => JsonExt,
36
37
  Keyring: () => Keyring,
38
+ MICROGONS_PER_ARGON: () => MICROGONS_PER_ARGON,
37
39
  MiningBids: () => MiningBids,
38
40
  MiningRotations: () => MiningRotations,
39
41
  TxSubmitter: () => TxSubmitter,
@@ -45,6 +47,7 @@ __export(index_exports, {
45
47
  convertPermillToBigNumber: () => convertPermillToBigNumber,
46
48
  createKeyringPair: () => createKeyringPair,
47
49
  decodeAddress: () => decodeAddress,
50
+ dispatchErrorToExtrinsicError: () => dispatchErrorToExtrinsicError,
48
51
  dispatchErrorToString: () => dispatchErrorToString,
49
52
  eventDataToJson: () => eventDataToJson,
50
53
  filterUndefined: () => filterUndefined,
@@ -148,119 +151,6 @@ var WageProtector = class _WageProtector {
148
151
  }
149
152
  };
150
153
 
151
- // src/utils.ts
152
- import BigNumber2, * as BN from "bignumber.js";
153
- var { ROUND_FLOOR } = BN;
154
- function formatArgons(x) {
155
- const isNegative = x < 0;
156
- let format = BigNumber2(x.toString()).abs().div(1e6).toFormat(2, ROUND_FLOOR);
157
- if (format.endsWith(".00")) {
158
- format = format.slice(0, -3);
159
- }
160
- return `${isNegative ? "-" : ""}\u20B3${format}`;
161
- }
162
- function formatPercent(x) {
163
- if (!x) return "na";
164
- return `${x.times(100).decimalPlaces(3)}%`;
165
- }
166
- function filterUndefined(obj) {
167
- return Object.fromEntries(
168
- Object.entries(obj).filter(
169
- ([_, value]) => value !== void 0 && value !== null
170
- )
171
- );
172
- }
173
- async function gettersToObject(obj) {
174
- if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
175
- const keys = [];
176
- for (const key in obj) {
177
- keys.push(key);
178
- }
179
- if (Symbol.iterator in obj) {
180
- const iterableToArray = [];
181
- for (const item of obj) {
182
- iterableToArray.push(await gettersToObject(item));
183
- }
184
- return iterableToArray;
185
- }
186
- const result = {};
187
- for (const key of keys) {
188
- const descriptor = Object.getOwnPropertyDescriptor(obj, key);
189
- if (descriptor && typeof descriptor.value === "function") {
190
- continue;
191
- }
192
- const value = descriptor && descriptor.get ? descriptor.get.call(obj) : obj[key];
193
- if (typeof value === "function") continue;
194
- result[key] = await gettersToObject(value);
195
- }
196
- return result;
197
- }
198
- function convertFixedU128ToBigNumber(fixedU128) {
199
- const decimalFactor = new BigNumber2(10).pow(new BigNumber2(18));
200
- const rawValue = new BigNumber2(fixedU128.toString());
201
- return rawValue.div(decimalFactor);
202
- }
203
- function convertPermillToBigNumber(permill) {
204
- const decimalFactor = new BigNumber2(1e6);
205
- const rawValue = new BigNumber2(permill.toString());
206
- return rawValue.div(decimalFactor);
207
- }
208
- function eventDataToJson(event) {
209
- const obj = {};
210
- event.data.forEach((data, index) => {
211
- const name = event.data.names?.[index];
212
- obj[name ?? `${index}`] = data.toJSON();
213
- });
214
- return obj;
215
- }
216
- function dispatchErrorToString(client, error) {
217
- let message = error.toString();
218
- if (error.isModule) {
219
- const decoded = client.registry.findMetaError(error.asModule);
220
- const { docs, name, section } = decoded;
221
- message = `${section}.${name}: ${docs.join(" ")}`;
222
- }
223
- return message;
224
- }
225
- function checkForExtrinsicSuccess(events, client) {
226
- return new Promise((resolve, reject) => {
227
- for (const { event } of events) {
228
- if (client.events.system.ExtrinsicSuccess.is(event)) {
229
- resolve();
230
- } else if (client.events.system.ExtrinsicFailed.is(event)) {
231
- const [dispatchError] = event.data;
232
- let errorInfo = dispatchError.toString();
233
- if (dispatchError.isModule) {
234
- const decoded = client.registry.findMetaError(dispatchError.asModule);
235
- errorInfo = `${decoded.section}.${decoded.name}`;
236
- }
237
- reject(
238
- new Error(
239
- `${event.section}.${event.method}:: ExtrinsicFailed:: ${errorInfo}`
240
- )
241
- );
242
- }
243
- }
244
- });
245
- }
246
- var JsonExt = class {
247
- static stringify(obj, space) {
248
- return JSON.stringify(
249
- obj,
250
- (_, v) => typeof v === "bigint" ? `${v}n` : v,
251
- space
252
- );
253
- }
254
- static parse(str) {
255
- return JSON.parse(str, (_, v) => {
256
- if (typeof v === "string" && v.endsWith("n")) {
257
- return BigInt(v.slice(0, -1));
258
- }
259
- return v;
260
- });
261
- }
262
- };
263
-
264
154
  // src/TxSubmitter.ts
265
155
  function logExtrinsicResult(result) {
266
156
  if (process.env.DEBUG) {
@@ -392,13 +282,12 @@ var TxResult = class {
392
282
  }
393
283
  }
394
284
  if (encounteredError) {
395
- const error = dispatchErrorToString(this.client, encounteredError);
396
- if (batchErrorIndex) {
397
- this.reject(
398
- new Error(`Error in batch#${batchErrorIndex}: ${error.toString()}`)
399
- );
400
- }
401
- this.reject(new Error(`Transaction failed: ${error}`));
285
+ const error = dispatchErrorToExtrinsicError(
286
+ this.client,
287
+ encounteredError,
288
+ batchErrorIndex
289
+ );
290
+ this.reject(error);
402
291
  } else {
403
292
  this.inBlockResolve(status.asInBlock.toU8a());
404
293
  }
@@ -413,6 +302,147 @@ var TxResult = class {
413
302
  }
414
303
  };
415
304
 
305
+ // src/utils.ts
306
+ import BigNumber2, * as BN from "bignumber.js";
307
+ var { ROUND_FLOOR } = BN;
308
+ var MICROGONS_PER_ARGON = 1e6;
309
+ function formatArgons(x) {
310
+ if (x === void 0 || x === null) return "na";
311
+ const isNegative = x < 0;
312
+ let format = BigNumber2(x.toString()).abs().div(MICROGONS_PER_ARGON).toFormat(2, ROUND_FLOOR);
313
+ if (format.endsWith(".00")) {
314
+ format = format.slice(0, -3);
315
+ }
316
+ return `${isNegative ? "-" : ""}\u20B3${format}`;
317
+ }
318
+ function formatPercent(x) {
319
+ if (!x) return "na";
320
+ return `${x.times(100).decimalPlaces(3)}%`;
321
+ }
322
+ function filterUndefined(obj) {
323
+ return Object.fromEntries(
324
+ Object.entries(obj).filter(
325
+ ([_, value]) => value !== void 0 && value !== null
326
+ )
327
+ );
328
+ }
329
+ async function gettersToObject(obj) {
330
+ if (obj === null || obj === void 0 || typeof obj !== "object") return obj;
331
+ const keys = [];
332
+ for (const key in obj) {
333
+ keys.push(key);
334
+ }
335
+ if (Symbol.iterator in obj) {
336
+ const iterableToArray = [];
337
+ for (const item of obj) {
338
+ iterableToArray.push(await gettersToObject(item));
339
+ }
340
+ return iterableToArray;
341
+ }
342
+ const result = {};
343
+ for (const key of keys) {
344
+ const descriptor = Object.getOwnPropertyDescriptor(obj, key);
345
+ if (descriptor && typeof descriptor.value === "function") {
346
+ continue;
347
+ }
348
+ const value = descriptor && descriptor.get ? descriptor.get.call(obj) : obj[key];
349
+ if (typeof value === "function") continue;
350
+ result[key] = await gettersToObject(value);
351
+ }
352
+ return result;
353
+ }
354
+ function convertFixedU128ToBigNumber(fixedU128) {
355
+ const decimalFactor = new BigNumber2(10).pow(new BigNumber2(18));
356
+ const rawValue = new BigNumber2(fixedU128.toString());
357
+ return rawValue.div(decimalFactor);
358
+ }
359
+ function convertPermillToBigNumber(permill) {
360
+ const decimalFactor = new BigNumber2(1e6);
361
+ const rawValue = new BigNumber2(permill.toString());
362
+ return rawValue.div(decimalFactor);
363
+ }
364
+ function eventDataToJson(event) {
365
+ const obj = {};
366
+ event.data.forEach((data, index) => {
367
+ const name = event.data.names?.[index];
368
+ obj[name ?? `${index}`] = data.toJSON();
369
+ });
370
+ return obj;
371
+ }
372
+ function dispatchErrorToString(client, error) {
373
+ let message = error.toString();
374
+ if (error.isModule) {
375
+ const decoded = client.registry.findMetaError(error.asModule);
376
+ const { docs, name, section } = decoded;
377
+ message = `${section}.${name}: ${docs.join(" ")}`;
378
+ }
379
+ return message;
380
+ }
381
+ var ExtrinsicError2 = class extends Error {
382
+ constructor(errorCode, details, batchInterruptedIndex) {
383
+ super(errorCode);
384
+ this.errorCode = errorCode;
385
+ this.details = details;
386
+ this.batchInterruptedIndex = batchInterruptedIndex;
387
+ }
388
+ toString() {
389
+ if (this.batchInterruptedIndex !== void 0) {
390
+ return `${this.errorCode} ${this.details ?? ""} (Batch interrupted at index ${this.batchInterruptedIndex})`;
391
+ }
392
+ return `${this.errorCode} ${this.details ?? ""}`;
393
+ }
394
+ };
395
+ function dispatchErrorToExtrinsicError(client, error, batchInterruptedIndex) {
396
+ if (error.isModule) {
397
+ const decoded = client.registry.findMetaError(error.asModule);
398
+ const { docs, name, section } = decoded;
399
+ return new ExtrinsicError2(
400
+ `${section}.${name}`,
401
+ docs.join(" "),
402
+ batchInterruptedIndex
403
+ );
404
+ }
405
+ return new ExtrinsicError2(error.toString(), void 0, batchInterruptedIndex);
406
+ }
407
+ function checkForExtrinsicSuccess(events, client) {
408
+ return new Promise((resolve, reject) => {
409
+ for (const { event } of events) {
410
+ if (client.events.system.ExtrinsicSuccess.is(event)) {
411
+ resolve();
412
+ } else if (client.events.system.ExtrinsicFailed.is(event)) {
413
+ const [dispatchError] = event.data;
414
+ let errorInfo = dispatchError.toString();
415
+ if (dispatchError.isModule) {
416
+ const decoded = client.registry.findMetaError(dispatchError.asModule);
417
+ errorInfo = `${decoded.section}.${decoded.name}`;
418
+ }
419
+ reject(
420
+ new Error(
421
+ `${event.section}.${event.method}:: ExtrinsicFailed:: ${errorInfo}`
422
+ )
423
+ );
424
+ }
425
+ }
426
+ });
427
+ }
428
+ var JsonExt = class {
429
+ static stringify(obj, space) {
430
+ return JSON.stringify(
431
+ obj,
432
+ (_, v) => typeof v === "bigint" ? `${v}n` : v,
433
+ space
434
+ );
435
+ }
436
+ static parse(str) {
437
+ return JSON.parse(str, (_, v) => {
438
+ if (typeof v === "string" && v.endsWith("n")) {
439
+ return BigInt(v.slice(0, -1));
440
+ }
441
+ return v;
442
+ });
443
+ }
444
+ };
445
+
416
446
  // src/AccountRegistry.ts
417
447
  var AccountRegistry = class _AccountRegistry {
418
448
  namedAccounts = /* @__PURE__ */ new Map();
@@ -825,6 +855,14 @@ var Accountset = class {
825
855
  );
826
856
  }
827
857
  }
858
+ async submitterBalance(blockHash) {
859
+ const client = await this.client;
860
+ const api = blockHash ? await client.at(blockHash) : client;
861
+ const accountData = await api.query.system.account(
862
+ this.txSubmitterPair.address
863
+ );
864
+ return accountData.data.free.toBigInt();
865
+ }
828
866
  async balance(blockHash) {
829
867
  const client = await this.client;
830
868
  const api = blockHash ? await client.at(blockHash) : client;
@@ -1087,18 +1125,18 @@ var Accountset = class {
1087
1125
  return new TxSubmitter(client, tx, this.txSubmitterPair);
1088
1126
  }
1089
1127
  /**
1090
- * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1128
+ * Create but don't submit a mining bid transaction.
1129
+ * @param options
1091
1130
  */
1092
- async createMiningBids(options) {
1093
- const accounts = this.getAccountsInRange(options.subaccountRange);
1131
+ async createMiningBidTx(options) {
1094
1132
  const client = await this.client;
1095
- let tip = options.tip ?? 0n;
1133
+ const { bidAmount, subaccounts, sendRewardsToSeed } = options;
1096
1134
  const batch = client.tx.utility.batch(
1097
- accounts.map((x) => {
1135
+ subaccounts.map((x) => {
1098
1136
  const keys = this.keys();
1099
- const rewards = options.sendRewardsToSeed ? { Account: this.seedAddress } : { Owner: null };
1137
+ const rewards = sendRewardsToSeed ? { Account: this.seedAddress } : { Owner: null };
1100
1138
  return client.tx.miningSlot.bid(
1101
- options.bidAmount,
1139
+ bidAmount,
1102
1140
  rewards,
1103
1141
  {
1104
1142
  grandpa: keys.gran.rawPublicKey,
@@ -1112,7 +1150,19 @@ var Accountset = class {
1112
1150
  if (this.isProxy) {
1113
1151
  tx = client.tx.proxy.proxy(this.seedAddress, "MiningBid", batch);
1114
1152
  }
1115
- const submitter = new TxSubmitter(client, tx, this.txSubmitterPair);
1153
+ return new TxSubmitter(client, tx, this.txSubmitterPair);
1154
+ }
1155
+ /**
1156
+ * Create a mining bid. This will create a bid for each account in the given range from the seed account as funding.
1157
+ */
1158
+ async createMiningBids(options) {
1159
+ const accounts = this.getAccountsInRange(options.subaccountRange);
1160
+ const client = await this.client;
1161
+ const submitter = await this.createMiningBidTx({
1162
+ ...options,
1163
+ subaccounts: accounts
1164
+ });
1165
+ const { tip = 0n } = options;
1116
1166
  const txFee = await submitter.feeEstimate(tip);
1117
1167
  let minBalance = options.bidAmount * BigInt(accounts.length);
1118
1168
  let totalFees = tip + 1n + txFee;
@@ -1556,27 +1606,24 @@ var VaultMonitor = class {
1556
1606
  }
1557
1607
  };
1558
1608
 
1559
- // src/CohortBidder.ts
1560
- var CohortBidder = class _CohortBidder {
1561
- constructor(accountset, cohortId, subaccounts, options) {
1562
- this.accountset = accountset;
1609
+ // src/CohortBidderHistory.ts
1610
+ var CohortBidderHistory = class _CohortBidderHistory {
1611
+ constructor(cohortId, subaccounts) {
1563
1612
  this.cohortId = cohortId;
1564
1613
  this.subaccounts = subaccounts;
1565
- this.options = options;
1614
+ this.maxSeatsInPlay = this.subaccounts.length;
1566
1615
  this.subaccounts.forEach((x) => {
1567
- this.allAddresses.add(x.address);
1616
+ this.myAddresses.add(x.address);
1568
1617
  });
1569
1618
  }
1570
- get client() {
1571
- return this.accountset.client;
1572
- }
1619
+ bidHistory = [];
1573
1620
  stats = {
1574
1621
  // number of seats won
1575
- seats: 0,
1622
+ seatsWon: 0,
1576
1623
  // sum of argons bid in successful bids
1577
1624
  totalArgonsBid: 0n,
1578
1625
  // total number of bids placed (includes 1 per seat)
1579
- bids: 0,
1626
+ bidsAttempted: 0,
1580
1627
  // fees including the tip
1581
1628
  fees: 0n,
1582
1629
  // Max bid per seat
@@ -1588,16 +1635,157 @@ var CohortBidder = class _CohortBidder {
1588
1635
  // The cohort expected argons per block
1589
1636
  cohortArgonsPerBlock: 0n,
1590
1637
  // The last block that bids are synced to
1591
- lastBlock: 0
1638
+ lastBlockNumber: 0
1592
1639
  };
1640
+ lastBids = [];
1641
+ myAddresses = /* @__PURE__ */ new Set();
1642
+ maxSeatsInPlay = 0;
1643
+ async init(client) {
1644
+ if (!this.stats.argonotsPerSeat) {
1645
+ const startingStats = await _CohortBidderHistory.getStartingData(client);
1646
+ Object.assign(this.stats, startingStats);
1647
+ }
1648
+ }
1649
+ maybeReducingSeats(maxSeats, reason, historyEntry) {
1650
+ if (this.maxSeatsInPlay > maxSeats) {
1651
+ historyEntry.maxSeatsReductionReason = reason;
1652
+ }
1653
+ this.maxSeatsInPlay = maxSeats;
1654
+ historyEntry.maxSeatsInPlay = maxSeats;
1655
+ }
1656
+ trackChange(next, blockNumber, tick, isLastEntry = false) {
1657
+ let winningBids = 0;
1658
+ let totalArgonsBid = 0n;
1659
+ const nextEntrants = [];
1660
+ for (const x of next) {
1661
+ const bid = x.bid.toBigInt();
1662
+ const address = x.accountId.toHuman();
1663
+ nextEntrants.push({ address, bid });
1664
+ if (this.myAddresses.has(address)) {
1665
+ winningBids++;
1666
+ totalArgonsBid += bid;
1667
+ }
1668
+ }
1669
+ this.stats.seatsWon = winningBids;
1670
+ this.stats.totalArgonsBid = totalArgonsBid;
1671
+ this.stats.lastBlockNumber = Math.max(
1672
+ blockNumber,
1673
+ this.stats.lastBlockNumber
1674
+ );
1675
+ const historyEntry = {
1676
+ cohortId: this.cohortId,
1677
+ blockNumber,
1678
+ tick,
1679
+ bidChanges: [],
1680
+ winningSeats: winningBids,
1681
+ maxSeatsInPlay: this.maxSeatsInPlay
1682
+ };
1683
+ const hasDiffs = JsonExt.stringify(nextEntrants) !== JsonExt.stringify(this.lastBids);
1684
+ if (!isLastEntry || hasDiffs) {
1685
+ this.bidHistory.unshift(historyEntry);
1686
+ }
1687
+ if (hasDiffs) {
1688
+ nextEntrants.forEach(({ address, bid }, i) => {
1689
+ const prevBidIndex = this.lastBids.findIndex(
1690
+ (y) => y.address === address
1691
+ );
1692
+ const entry = {
1693
+ address,
1694
+ bidAmount: bid,
1695
+ bidPosition: i,
1696
+ prevPosition: prevBidIndex === -1 ? null : prevBidIndex
1697
+ };
1698
+ if (prevBidIndex !== -1) {
1699
+ const prevBidAmount = this.lastBids[prevBidIndex].bid;
1700
+ if (prevBidAmount !== bid) {
1701
+ entry.prevBidAmount = prevBidAmount;
1702
+ }
1703
+ }
1704
+ historyEntry.bidChanges.push(entry);
1705
+ });
1706
+ this.lastBids.forEach(({ address, bid }, i) => {
1707
+ const nextBid = nextEntrants.some((y) => y.address === address);
1708
+ if (!nextBid) {
1709
+ historyEntry.bidChanges.push({
1710
+ address,
1711
+ bidAmount: bid,
1712
+ bidPosition: null,
1713
+ prevPosition: i
1714
+ });
1715
+ }
1716
+ });
1717
+ this.lastBids = nextEntrants;
1718
+ }
1719
+ return historyEntry;
1720
+ }
1721
+ onBidResult(historyEntry, param) {
1722
+ const {
1723
+ txFeePlusTip,
1724
+ bidPerSeat,
1725
+ bidsAttempted,
1726
+ successfulBids,
1727
+ blockNumber,
1728
+ bidError
1729
+ } = param;
1730
+ this.stats.fees += txFeePlusTip;
1731
+ this.stats.bidsAttempted += bidsAttempted;
1732
+ if (bidPerSeat > this.stats.maxBidPerSeat) {
1733
+ this.stats.maxBidPerSeat = bidPerSeat;
1734
+ }
1735
+ if (blockNumber !== void 0) {
1736
+ this.stats.lastBlockNumber = Math.max(
1737
+ blockNumber,
1738
+ this.stats.lastBlockNumber
1739
+ );
1740
+ }
1741
+ historyEntry.myBidsPlaced.failureReason = bidError;
1742
+ historyEntry.myBidsPlaced.successfulBids = successfulBids;
1743
+ historyEntry.myBidsPlaced.txFeePlusTip = txFeePlusTip;
1744
+ }
1745
+ static async getStartingData(api) {
1746
+ const argonotPrice = await api.query.priceIndex.current();
1747
+ let argonotUsdPrice = 0;
1748
+ if (argonotPrice.isSome) {
1749
+ argonotUsdPrice = convertFixedU128ToBigNumber(
1750
+ argonotPrice.unwrap().argonotUsdPrice.toBigInt()
1751
+ ).toNumber();
1752
+ }
1753
+ const argonotsPerSeat = await api.query.miningSlot.argonotsPerMiningSeat().then((x) => x.toBigInt());
1754
+ const cohortArgonsPerBlock = await api.query.blockRewards.argonsPerBlock().then((x) => x.toBigInt());
1755
+ return { argonotsPerSeat, argonotUsdPrice, cohortArgonsPerBlock };
1756
+ }
1757
+ };
1758
+
1759
+ // src/CohortBidder.ts
1760
+ var CohortBidder = class {
1761
+ constructor(accountset, cohortId, subaccounts, options) {
1762
+ this.accountset = accountset;
1763
+ this.cohortId = cohortId;
1764
+ this.subaccounts = subaccounts;
1765
+ this.options = options;
1766
+ this.history = new CohortBidderHistory(cohortId, subaccounts);
1767
+ this.subaccounts.forEach((x) => {
1768
+ this.myAddresses.add(x.address);
1769
+ });
1770
+ }
1771
+ get client() {
1772
+ return this.accountset.client;
1773
+ }
1774
+ get stats() {
1775
+ return this.history.stats;
1776
+ }
1777
+ get bidHistory() {
1778
+ return this.history.bidHistory;
1779
+ }
1593
1780
  unsubscribe;
1594
1781
  pendingRequest;
1595
1782
  retryTimeout;
1596
1783
  isStopped = false;
1597
1784
  needsRebid = false;
1598
1785
  lastBidTime = 0;
1786
+ history;
1599
1787
  millisPerTick;
1600
- allAddresses = /* @__PURE__ */ new Set();
1788
+ myAddresses = /* @__PURE__ */ new Set();
1601
1789
  async stop() {
1602
1790
  if (this.isStopped) return this.stats;
1603
1791
  this.isStopped = true;
@@ -1607,70 +1795,59 @@ var CohortBidder = class _CohortBidder {
1607
1795
  this.unsubscribe();
1608
1796
  }
1609
1797
  const client = await this.client;
1610
- const [nextCohort, nextCohortId, blockNumber] = await new Promise(async (resolve) => {
1611
- const unsub = await client.queryMulti(
1612
- [
1613
- client.query.miningSlot.nextSlotCohort,
1614
- client.query.miningSlot.nextCohortId,
1615
- client.query.miningSlot.isNextSlotBiddingOpen,
1616
- client.query.system.number
1617
- ],
1618
- ([nextCohort2, nextCohortId2, isBiddingStillOpen, blockNumber2]) => {
1619
- if (nextCohortId2.toNumber() !== this.cohortId || isBiddingStillOpen.isFalse) {
1620
- unsub();
1621
- resolve([nextCohort2, nextCohortId2, blockNumber2]);
1798
+ const [nextCohortId, isBiddingOpen] = await client.queryMulti([
1799
+ client.query.miningSlot.nextCohortId,
1800
+ client.query.miningSlot.isNextSlotBiddingOpen
1801
+ ]);
1802
+ if (nextCohortId.toNumber() === this.cohortId && isBiddingOpen.isTrue) {
1803
+ console.log("Bidding is still open, waiting for it to close");
1804
+ await new Promise(async (resolve) => {
1805
+ const unsub = await client.query.miningSlot.isNextSlotBiddingOpen(
1806
+ (isOpen) => {
1807
+ if (isOpen.isFalse) {
1808
+ unsub();
1809
+ resolve();
1810
+ }
1622
1811
  }
1623
- }
1624
- );
1625
- });
1626
- void await this.pendingRequest;
1627
- if (nextCohortId.toNumber() === this.cohortId) {
1628
- console.log("Bidder updating stats with bid queue");
1629
- this.updateStats(nextCohort);
1630
- } else {
1631
- const bestBlock = await client.rpc.chain.getBlockHash();
1632
- const api = await client.at(bestBlock);
1633
- const wonIndices = await api.query.miningSlot.accountIndexLookup.multi([...this.allAddresses]).then((x) => x.filter((x2) => x2.isSome).map((x2) => x2.value));
1634
- const wonSeats = await api.query.miningSlot.activeMinersByIndex.multi(wonIndices).then(
1635
- (x) => x.filter(
1636
- (x2) => x2.isSome && x2.value.cohortId.toNumber() === this.cohortId
1637
- ).map((x2) => x2.value)
1638
- );
1639
- console.log("Bidder updating stats with finalized cohort");
1640
- this.updateStats(wonSeats);
1812
+ );
1813
+ });
1641
1814
  }
1642
- this.stats.lastBlock = Math.max(
1643
- blockNumber.toNumber(),
1644
- this.stats.lastBlock
1645
- );
1815
+ void await this.pendingRequest;
1816
+ let header = await client.rpc.chain.getHeader();
1817
+ while (true) {
1818
+ const api2 = await client.at(header.hash);
1819
+ const cohortId = await api2.query.miningSlot.nextCohortId();
1820
+ if (cohortId.toNumber() === this.cohortId) {
1821
+ break;
1822
+ }
1823
+ header = await client.rpc.chain.getHeader(header.parentHash);
1824
+ }
1825
+ const api = await client.at(header.hash);
1826
+ const tick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1827
+ const cohort = await api.query.miningSlot.nextSlotCohort();
1828
+ this.history.trackChange(cohort, header.number.toNumber(), tick, true);
1829
+ console.log("Bidder stopped", {
1830
+ cohortId: this.cohortId,
1831
+ blockNumber: header.number.toNumber(),
1832
+ tick,
1833
+ cohort: cohort.map((x) => ({
1834
+ address: x.accountId.toHuman(),
1835
+ bid: x.bid.toBigInt()
1836
+ }))
1837
+ });
1646
1838
  return this.stats;
1647
1839
  }
1648
- static async getStartingData(api) {
1649
- const argonotPrice = await api.query.priceIndex.current();
1650
- let argonotUsdPrice = 0;
1651
- if (argonotPrice.isSome) {
1652
- argonotUsdPrice = convertFixedU128ToBigNumber(
1653
- argonotPrice.unwrap().argonotUsdPrice.toBigInt()
1654
- ).toNumber();
1655
- }
1656
- const argonotsPerSeat = await api.query.miningSlot.argonotsPerMiningSeat().then((x) => x.toBigInt());
1657
- const cohortArgonsPerBlock = await api.query.blockRewards.argonsPerBlock().then((x) => x.toBigInt());
1658
- return { argonotsPerSeat, argonotUsdPrice, cohortArgonsPerBlock };
1659
- }
1660
1840
  async start() {
1661
1841
  console.log(`Starting cohort ${this.cohortId} bidder`, {
1662
1842
  maxBid: formatArgons(this.options.maxBid),
1663
1843
  minBid: formatArgons(this.options.minBid),
1664
1844
  bidIncrement: formatArgons(this.options.bidIncrement),
1665
- maxBalance: formatArgons(this.options.maxBalance),
1845
+ maxBudget: formatArgons(this.options.maxBudget),
1666
1846
  bidDelay: this.options.bidDelay,
1667
1847
  subaccounts: this.subaccounts
1668
1848
  });
1669
1849
  const client = await this.client;
1670
- if (!this.stats.argonotsPerSeat) {
1671
- const startingStats = await _CohortBidder.getStartingData(client);
1672
- Object.assign(this.stats, startingStats);
1673
- }
1850
+ await this.history.init(client);
1674
1851
  this.millisPerTick ??= await client.query.ticks.genesisTicker().then((x) => x.tickDurationMillis.toNumber());
1675
1852
  this.unsubscribe = await client.queryMulti(
1676
1853
  [
@@ -1684,24 +1861,27 @@ var CohortBidder = class _CohortBidder {
1684
1861
  }
1685
1862
  );
1686
1863
  }
1687
- updateStats(next) {
1688
- let seats = 0;
1689
- let totalArgonsBid = 0n;
1690
- for (const x of next) {
1691
- if (this.allAddresses.has(x.accountId.toHuman())) {
1692
- seats++;
1693
- totalArgonsBid += x.bid.toBigInt();
1694
- }
1695
- }
1696
- this.stats.seats = seats;
1697
- this.stats.totalArgonsBid = totalArgonsBid;
1698
- }
1699
1864
  async checkSeats(next) {
1700
- if (this.isStopped || this.pendingRequest) return;
1865
+ if (this.isStopped) return;
1866
+ clearTimeout(this.retryTimeout);
1867
+ const client = await this.client;
1868
+ const bestBlock = await client.rpc.chain.getBlockHash();
1869
+ const api = await client.at(bestBlock);
1870
+ const blockNumber = await api.query.system.number().then((x) => x.toNumber());
1871
+ if (this.bidHistory[0]?.blockNumber >= blockNumber) {
1872
+ return;
1873
+ }
1874
+ const tick = await api.query.ticks.currentTick().then((x) => x.toNumber());
1875
+ const historyEntry = this.history.trackChange(next, blockNumber, tick);
1876
+ if (this.pendingRequest) return;
1701
1877
  const ticksSinceLastBid = Math.floor(
1702
1878
  (Date.now() - this.lastBidTime) / this.millisPerTick
1703
1879
  );
1704
1880
  if (ticksSinceLastBid < this.options.bidDelay) {
1881
+ this.retryTimeout = setTimeout(
1882
+ () => void this.checkCurrentSeats(),
1883
+ this.millisPerTick
1884
+ );
1705
1885
  return;
1706
1886
  }
1707
1887
  console.log(
@@ -1709,12 +1889,19 @@ var CohortBidder = class _CohortBidder {
1709
1889
  this.cohortId,
1710
1890
  this.subaccounts.map((x) => x.index)
1711
1891
  );
1712
- this.updateStats(next);
1713
- this.needsRebid = this.subaccounts.some(
1714
- (x) => !next.some((y) => y.accountId.toHuman() === x.address)
1715
- );
1892
+ const winningBids = historyEntry.winningSeats;
1893
+ this.needsRebid = winningBids < this.subaccounts.length;
1716
1894
  if (!this.needsRebid) return;
1717
- const lowestBid = next.at(-1)?.bid.toBigInt() ?? -this.options.bidIncrement;
1895
+ const winningAddresses = new Set(next.map((x) => x.accountId.toHuman()));
1896
+ let lowestBid = -this.options.bidIncrement;
1897
+ if (next.length) {
1898
+ for (let i = next.length - 1; i >= 0; i--) {
1899
+ if (!this.myAddresses.has(next[i].accountId.toHuman())) {
1900
+ lowestBid = next.at(i).bid.toBigInt();
1901
+ break;
1902
+ }
1903
+ }
1904
+ }
1718
1905
  const MIN_INCREMENT = 10000n;
1719
1906
  let nextBid = lowestBid + this.options.bidIncrement;
1720
1907
  if (nextBid < this.options.minBid) {
@@ -1722,83 +1909,119 @@ var CohortBidder = class _CohortBidder {
1722
1909
  }
1723
1910
  if (nextBid > this.options.maxBid) {
1724
1911
  nextBid = this.options.maxBid;
1725
- if (nextBid - lowestBid < MIN_INCREMENT) {
1726
- console.log(
1727
- `Can't make any more bids for ${this.cohortId} with given constraints.`,
1728
- {
1729
- lowestCurrentBid: formatArgons(lowestBid),
1730
- nextAttemptedBid: formatArgons(nextBid),
1731
- maxBid: formatArgons(this.options.maxBid)
1732
- }
1733
- );
1734
- return;
1912
+ }
1913
+ const fakeTx = await this.accountset.createMiningBidTx({
1914
+ subaccounts: this.subaccounts,
1915
+ bidAmount: nextBid,
1916
+ sendRewardsToSeed: true
1917
+ });
1918
+ let availableBalanceForBids = await api.query.system.account(this.accountset.txSubmitterPair.address).then((x) => x.data.free.toBigInt());
1919
+ for (const bid of next) {
1920
+ if (this.myAddresses.has(bid.accountId.toHuman())) {
1921
+ availableBalanceForBids += bid.bid.toBigInt();
1735
1922
  }
1736
1923
  }
1924
+ const tip = this.options.tipPerTransaction ?? 0n;
1925
+ const feeEstimate = await fakeTx.feeEstimate(tip);
1926
+ const feePlusTip = feeEstimate + tip;
1927
+ let budgetForSeats = this.options.maxBudget - feePlusTip;
1928
+ if (budgetForSeats > availableBalanceForBids) {
1929
+ budgetForSeats = availableBalanceForBids - feePlusTip;
1930
+ }
1737
1931
  if (nextBid < lowestBid) {
1738
1932
  console.log(
1739
1933
  `Can't bid ${formatArgons(nextBid)}. Current lowest bid is ${formatArgons(
1740
1934
  lowestBid
1741
1935
  )}.`
1742
1936
  );
1937
+ this.history.maybeReducingSeats(
1938
+ winningBids,
1939
+ "MaxBidTooLow" /* MaxBidTooLow */,
1940
+ historyEntry
1941
+ );
1743
1942
  return;
1744
1943
  }
1745
- const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(this.options.maxBalance / nextBid);
1746
- if (seatsInBudget <= 0) {
1944
+ if (nextBid - lowestBid < MIN_INCREMENT) {
1747
1945
  console.log(
1748
- `Can't afford any seats at ${formatArgons(nextBid)}. Would exceed our max balance of ${formatArgons(this.options.maxBalance)}.`
1946
+ `Can't make any more bids for ${this.cohortId} with given constraints.`,
1947
+ {
1948
+ lowestCurrentBid: formatArgons(lowestBid),
1949
+ nextAttemptedBid: formatArgons(nextBid),
1950
+ maxBid: formatArgons(this.options.maxBid)
1951
+ }
1952
+ );
1953
+ this.history.maybeReducingSeats(
1954
+ winningBids,
1955
+ "MaxBidTooLow" /* MaxBidTooLow */,
1956
+ historyEntry
1749
1957
  );
1750
1958
  return;
1751
1959
  }
1752
- if (this.subaccounts.length > seatsInBudget) {
1753
- const toKeep = [];
1754
- for (const account of this.subaccounts) {
1755
- if (toKeep.length >= seatsInBudget) break;
1756
- if (account.isRebid) {
1757
- toKeep.push(account);
1758
- }
1759
- }
1760
- for (const account of this.subaccounts) {
1761
- if (toKeep.length >= seatsInBudget) break;
1762
- if (!account.isRebid) {
1763
- toKeep.push(account);
1764
- }
1765
- }
1766
- const removedIndices = this.subaccounts.filter((x) => !toKeep.some((y) => y.index === x.index)).map((x) => x.index);
1767
- this.subaccounts = toKeep;
1768
- console.log("Had to remove some subaccounts to fit in budget:", {
1769
- removedIndices,
1770
- seatsInBudget,
1771
- budget: formatArgons(this.options.maxBalance)
1960
+ const seatsInBudget = nextBid === 0n ? this.subaccounts.length : Number(budgetForSeats / nextBid);
1961
+ let accountsToUse = [...this.subaccounts];
1962
+ if (accountsToUse.length > seatsInBudget) {
1963
+ const reason = availableBalanceForBids - feePlusTip < nextBid * BigInt(seatsInBudget) ? "InsufficientFunds" /* InsufficientFunds */ : "MaxBudgetTooLow" /* MaxBudgetTooLow */;
1964
+ this.history.maybeReducingSeats(seatsInBudget, reason, historyEntry);
1965
+ accountsToUse.sort((a, b) => {
1966
+ const isWinningA = winningAddresses.has(a.address);
1967
+ const isWinningB = winningAddresses.has(b.address);
1968
+ if (isWinningA && !isWinningB) return -1;
1969
+ if (!isWinningA && isWinningB) return 1;
1970
+ if (a.isRebid && !b.isRebid) return -1;
1971
+ if (!a.isRebid && b.isRebid) return 1;
1972
+ return a.index - b.index;
1772
1973
  });
1974
+ accountsToUse.length = seatsInBudget;
1975
+ }
1976
+ if (accountsToUse.length > winningBids) {
1977
+ historyEntry.myBidsPlaced = {
1978
+ bids: accountsToUse.length,
1979
+ bidPerSeat: nextBid,
1980
+ txFeePlusTip: feePlusTip,
1981
+ successfulBids: 0
1982
+ };
1983
+ this.pendingRequest = this.bid(nextBid, accountsToUse, historyEntry);
1984
+ } else if (historyEntry.bidChanges.length === 0) {
1985
+ this.history.bidHistory.shift();
1773
1986
  }
1774
- this.pendingRequest = this.bid(
1775
- nextBid,
1776
- this.subaccounts.map((x) => x.index)
1777
- );
1778
1987
  this.needsRebid = false;
1779
1988
  }
1780
- async bid(bidPerSeat, subaccountRange) {
1781
- if (!subaccountRange.length) return;
1989
+ async bid(bidPerSeat, subaccounts, historyEntry) {
1782
1990
  const prevLastBidTime = this.lastBidTime;
1783
1991
  try {
1784
1992
  this.lastBidTime = Date.now();
1785
- const result = await this.accountset.createMiningBids({
1786
- subaccountRange,
1993
+ const submitter = await this.accountset.createMiningBidTx({
1994
+ subaccounts,
1787
1995
  bidAmount: bidPerSeat,
1788
1996
  sendRewardsToSeed: true
1789
1997
  });
1790
- if (result.blockHash) {
1998
+ const tip = this.options.tipPerTransaction ?? 0n;
1999
+ const txResult = await submitter.submit({
2000
+ tip,
2001
+ useLatestNonce: true
2002
+ });
2003
+ const bidError = await txResult.inBlockPromise.then(() => void 0).catch((x) => x);
2004
+ let blockNumber;
2005
+ if (txResult.includedInBlock) {
1791
2006
  const client = await this.client;
1792
- const api = await client.at(result.blockHash);
1793
- this.stats.lastBlock = await api.query.system.number().then((x) => x.toNumber());
2007
+ const api = await client.at(txResult.includedInBlock);
2008
+ blockNumber = await api.query.system.number().then((x) => x.toNumber());
1794
2009
  }
1795
- this.stats.fees += result.finalFee ?? 0n;
1796
- this.stats.bids += subaccountRange.length;
1797
- if (bidPerSeat > this.stats.maxBidPerSeat) {
1798
- this.stats.maxBidPerSeat = bidPerSeat;
1799
- }
1800
- console.log("Done creating bids for cohort", this.cohortId);
1801
- if (result.bidError) throw result.bidError;
2010
+ const successfulBids = txResult.batchInterruptedIndex ?? subaccounts.length;
2011
+ this.history.onBidResult(historyEntry, {
2012
+ blockNumber,
2013
+ successfulBids,
2014
+ bidPerSeat,
2015
+ txFeePlusTip: txResult.finalFee ?? 0n,
2016
+ bidsAttempted: subaccounts.length,
2017
+ bidError
2018
+ });
2019
+ console.log("Done creating bids for cohort", {
2020
+ successfulBids,
2021
+ bidPerSeat,
2022
+ blockNumber
2023
+ });
2024
+ if (bidError) throw bidError;
1802
2025
  } catch (err) {
1803
2026
  this.lastBidTime = prevLastBidTime;
1804
2027
  console.error(`Error bidding for cohort ${this.cohortId}:`, err);
@@ -2478,8 +2701,8 @@ function vaultCli() {
2478
2701
  ).action(async ({ tip, argons, vaultId, ratio }) => {
2479
2702
  const accountset = await accountsetFromCli(program);
2480
2703
  const client = await accountset.client;
2481
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2482
- const microgons = BigInt(argons * 1e6);
2704
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2705
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2483
2706
  const rawVault = (await client.query.vaults.vaultsById(vaultId)).unwrap();
2484
2707
  if (rawVault.operatorAccountId.toHuman() !== accountset.seedAddress) {
2485
2708
  console.error("Vault does not belong to this account");
@@ -2539,8 +2762,8 @@ function vaultCli() {
2539
2762
  }
2540
2763
  const accountset = await accountsetFromCli(program);
2541
2764
  const client = await accountset.client;
2542
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2543
- const microgons = BigInt(argons * 1e6);
2765
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2766
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2544
2767
  const bitcoinLocks = new BitcoinLocks(Promise.resolve(client));
2545
2768
  const existentialDeposit = client.consts.balances.existentialDeposit.toBigInt();
2546
2769
  const tickDuration = (await client.query.ticks.genesisTicker()).tickDurationMillis.toNumber();
@@ -2745,7 +2968,7 @@ function miningCli() {
2745
2968
  const balance = await accountset.balance();
2746
2969
  const feeWiggleRoom = BigInt(25e3);
2747
2970
  const amountAvailable = balance - feeWiggleRoom;
2748
- let maxBidAmount = maxBid ? BigInt(maxBid * 1e6) : void 0;
2971
+ let maxBidAmount = maxBid ? BigInt(maxBid * MICROGONS_PER_ARGON) : void 0;
2749
2972
  let maxBalanceToUse = amountAvailable;
2750
2973
  if (maxBalance !== void 0) {
2751
2974
  if (maxBalance.endsWith("%")) {
@@ -2757,7 +2980,7 @@ function miningCli() {
2757
2980
  maxBalanceToUse = amountToBid;
2758
2981
  } else {
2759
2982
  maxBalanceToUse = BigInt(
2760
- Math.floor(parseFloat(maxBalance) * 1e6)
2983
+ Math.floor(parseFloat(maxBalance) * MICROGONS_PER_ARGON)
2761
2984
  );
2762
2985
  }
2763
2986
  maxBidAmount ??= maxBalanceToUse / BigInt(seatsToWin);
@@ -2779,9 +3002,11 @@ function miningCli() {
2779
3002
  subaccountRange,
2780
3003
  {
2781
3004
  maxBid: maxBidAmount,
2782
- minBid: BigInt((minBid ?? 0) * 1e6),
2783
- bidIncrement: BigInt(Math.floor(bidIncrement * 1e6)),
2784
- maxBalance: maxBalanceToUse,
3005
+ minBid: BigInt((minBid ?? 0) * MICROGONS_PER_ARGON),
3006
+ bidIncrement: BigInt(
3007
+ Math.floor(bidIncrement * MICROGONS_PER_ARGON)
3008
+ ),
3009
+ maxBudget: maxBalanceToUse,
2785
3010
  bidDelay
2786
3011
  }
2787
3012
  );
@@ -2813,7 +3038,10 @@ function miningCli() {
2813
3038
  );
2814
3039
  const tx = client.tx.utility.batchAll([
2815
3040
  client.tx.proxy.addProxy(address, "MiningBid", 0),
2816
- client.tx.balances.transferAllowDeath(address, BigInt(feeArgons * 1e6))
3041
+ client.tx.balances.transferAllowDeath(
3042
+ address,
3043
+ BigInt(feeArgons * MICROGONS_PER_ARGON)
3044
+ )
2817
3045
  ]);
2818
3046
  let keypair;
2819
3047
  try {
@@ -2862,8 +3090,8 @@ function liquidityCli() {
2862
3090
  parseFloat
2863
3091
  ).action(async ({ tip, argons, vaultId }) => {
2864
3092
  const accountset = await accountsetFromCli(program);
2865
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
2866
- const microgons = BigInt(argons * 1e6);
3093
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
3094
+ const microgons = BigInt(argons * MICROGONS_PER_ARGON);
2867
3095
  const bidPool = new BidPool(
2868
3096
  accountset.client,
2869
3097
  accountset.txSubmitterPair
@@ -2888,7 +3116,7 @@ function liquidityCli() {
2888
3116
  "The tip to include with the transaction",
2889
3117
  parseFloat
2890
3118
  ).action(async ({ maxArgons, minPctSharing, tip }) => {
2891
- const maxAmountPerSlot = BigInt(maxArgons * 1e6);
3119
+ const maxAmountPerSlot = BigInt(maxArgons * MICROGONS_PER_ARGON);
2892
3120
  const accountset = await accountsetFromCli(program);
2893
3121
  const vaults = new VaultMonitor(
2894
3122
  accountset,
@@ -2901,7 +3129,7 @@ function liquidityCli() {
2901
3129
  accountset.client,
2902
3130
  accountset.txSubmitterPair
2903
3131
  );
2904
- const resolvedTip = tip ? BigInt(tip * 1e6) : 0n;
3132
+ const resolvedTip = tip ? BigInt(tip * MICROGONS_PER_ARGON) : 0n;
2905
3133
  console.log("Waiting for liquidity pool space...");
2906
3134
  vaults.events.on(
2907
3135
  "liquidity-pool-space-above",
@@ -2940,7 +3168,7 @@ function bitcoinCli() {
2940
3168
  ).description("Watch for bitcoin space available").action(async ({ argons }) => {
2941
3169
  const accountset = await accountsetFromCli(program);
2942
3170
  const bot = new VaultMonitor(accountset, {
2943
- bitcoinSpaceAvailable: argons ? BigInt(argons * 1e6) : 1n
3171
+ bitcoinSpaceAvailable: argons ? BigInt(argons * MICROGONS_PER_ARGON) : 1n
2944
3172
  });
2945
3173
  bot.events.on("bitcoin-space-above", async (vaultId, amount) => {
2946
3174
  const vault = bot.vaultsById[vaultId];
@@ -2969,13 +3197,13 @@ function bitcoinCli() {
2969
3197
  parseFloat,
2970
3198
  0
2971
3199
  ).action(async ({ argons, bitcoinXpub, maxLockFee, tip }) => {
2972
- const amountToLock = BigInt(argons * 1e6);
3200
+ const amountToLock = BigInt(argons * MICROGONS_PER_ARGON);
2973
3201
  const accountset = await accountsetFromCli(program);
2974
3202
  await BitcoinLocks.waitForSpace(accountset, {
2975
3203
  argonAmount: amountToLock,
2976
3204
  bitcoinXpub,
2977
- maxLockFee: maxLockFee !== void 0 ? BigInt(maxLockFee * 1e6) : void 0,
2978
- tip: BigInt(tip * 1e6)
3205
+ maxLockFee: maxLockFee !== void 0 ? BigInt(maxLockFee * MICROGONS_PER_ARGON) : void 0,
3206
+ tip: BigInt(tip * MICROGONS_PER_ARGON)
2979
3207
  }).then(({ vaultId, satoshis, txFee, btcFee }) => {
2980
3208
  console.log(
2981
3209
  `Locked ${satoshis} satoshis in vault ${vaultId}. Tx fee=${formatArgons(
@@ -3000,8 +3228,13 @@ async function keyringFromFile(opts) {
3000
3228
  }
3001
3229
  const path = opts.filePath.replace("~", os.homedir());
3002
3230
  const json = JSON.parse(await readFile(path, "utf-8"));
3231
+ let passphrase = opts.passphrase;
3232
+ if (opts.passphraseFile) {
3233
+ const passphrasePath = opts.passphraseFile.replace("~", os.homedir());
3234
+ passphrase = await readFile(passphrasePath, "utf-8");
3235
+ }
3003
3236
  const mainAccount = new Keyring().createFromJson(json);
3004
- mainAccount.decodePkcs8(opts.passphrase);
3237
+ mainAccount.decodePkcs8(passphrase);
3005
3238
  return mainAccount;
3006
3239
  }
3007
3240
  async function saveKeyringPair(opts) {
@@ -3036,6 +3269,11 @@ function buildCli() {
3036
3269
  "--account-passphrase <password>",
3037
3270
  "The password for your seed file"
3038
3271
  ).env("ACCOUNT_PASSPHRASE")
3272
+ ).addOption(
3273
+ new Option2(
3274
+ "--account-passphrase-file <path>",
3275
+ "The path to a password for your seed file"
3276
+ )
3039
3277
  ).addOption(
3040
3278
  new Option2(
3041
3279
  "-s, --subaccounts <range>",
@@ -3052,7 +3290,8 @@ async function accountsetFromCli(program, proxyForAddress) {
3052
3290
  if (opts.accountFilePath) {
3053
3291
  keypair = await keyringFromFile({
3054
3292
  filePath: opts.accountFilePath,
3055
- passphrase: opts.accountPassphrase
3293
+ passphrase: opts.accountPassphrase,
3294
+ passphraseFile: opts.accountPassphraseFile
3056
3295
  });
3057
3296
  }
3058
3297
  if (!keypair) {