dequanto 0.1.80 → 0.1.84

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.
Files changed (79) hide show
  1. package/lib/cjs/blocks/BlockDateResolver.js +59 -23
  2. package/lib/cjs/blocks/BlockDateResolver.js.map +1 -1
  3. package/lib/cjs/contracts/deploy/Deployments.js +2 -1
  4. package/lib/cjs/contracts/deploy/Deployments.js.map +1 -1
  5. package/lib/cjs/contracts/deploy/proxy/ProxyDeployment.js +1 -1
  6. package/lib/cjs/contracts/deploy/proxy/ProxyDeployment.js.map +1 -1
  7. package/lib/cjs/erc4337/Erc4337Factory.js +0 -1
  8. package/lib/cjs/erc4337/Erc4337Factory.js.map +1 -1
  9. package/lib/cjs/indexer/EventsIndexer.js +14 -2
  10. package/lib/cjs/indexer/EventsIndexer.js.map +1 -1
  11. package/lib/cjs/prebuilt-factories/TimelockControllerFactory.js +251 -0
  12. package/lib/cjs/prebuilt-factories/TimelockControllerFactory.js.map +1 -0
  13. package/lib/cjs/services/TimelockService/TimelockService.js +52 -2
  14. package/lib/cjs/services/TimelockService/TimelockService.js.map +1 -1
  15. package/lib/cjs/txs/TxWriter.js +1 -1
  16. package/lib/cjs/txs/TxWriter.js.map +1 -1
  17. package/lib/cjs/txs/agents/TimelockAgent.js +90 -0
  18. package/lib/cjs/txs/agents/TimelockAgent.js.map +1 -0
  19. package/lib/cjs/txs/agents/TxWriterAccountAgents.js +2 -0
  20. package/lib/cjs/txs/agents/TxWriterAccountAgents.js.map +1 -1
  21. package/lib/cjs/utils/$account.js +17 -1
  22. package/lib/cjs/utils/$account.js.map +1 -1
  23. package/lib/cjs/utils/$bigint.js +19 -2
  24. package/lib/cjs/utils/$bigint.js.map +1 -1
  25. package/lib/cjs/utils/$date.js +11 -0
  26. package/lib/cjs/utils/$date.js.map +1 -1
  27. package/lib/esm/blocks/BlockDateResolver.js.map +1 -1
  28. package/lib/esm/blocks/BlockDateResolver.mjs +59 -23
  29. package/lib/esm/contracts/deploy/Deployments.js.map +1 -1
  30. package/lib/esm/contracts/deploy/Deployments.mjs +2 -1
  31. package/lib/esm/contracts/deploy/proxy/ProxyDeployment.js.map +1 -1
  32. package/lib/esm/contracts/deploy/proxy/ProxyDeployment.mjs +1 -1
  33. package/lib/esm/erc4337/Erc4337Factory.js.map +1 -1
  34. package/lib/esm/erc4337/Erc4337Factory.mjs +0 -1
  35. package/lib/esm/indexer/EventsIndexer.js.map +1 -1
  36. package/lib/esm/indexer/EventsIndexer.mjs +14 -2
  37. package/lib/esm/prebuilt-factories/TimelockControllerFactory.js.map +1 -0
  38. package/lib/esm/prebuilt-factories/TimelockControllerFactory.mjs +244 -0
  39. package/lib/esm/services/TimelockService/TimelockService.js.map +1 -1
  40. package/lib/esm/services/TimelockService/TimelockService.mjs +52 -2
  41. package/lib/esm/txs/TxWriter.js.map +1 -1
  42. package/lib/esm/txs/TxWriter.mjs +1 -1
  43. package/lib/esm/txs/agents/TimelockAgent.js.map +1 -0
  44. package/lib/esm/txs/agents/TimelockAgent.mjs +85 -0
  45. package/lib/esm/txs/agents/TxWriterAccountAgents.js.map +1 -1
  46. package/lib/esm/txs/agents/TxWriterAccountAgents.mjs +2 -0
  47. package/lib/esm/utils/$account.js.map +1 -1
  48. package/lib/esm/utils/$account.mjs +17 -1
  49. package/lib/esm/utils/$bigint.js.map +1 -1
  50. package/lib/esm/utils/$bigint.mjs +19 -2
  51. package/lib/esm/utils/$date.js.map +1 -1
  52. package/lib/esm/utils/$date.mjs +11 -0
  53. package/lib/types/blocks/BlockDateResolver.d.ts +7 -5
  54. package/lib/types/contracts/deploy/Deployments.d.ts +3 -0
  55. package/lib/types/contracts/deploy/proxy/ProxyDeployment.d.ts +1 -0
  56. package/lib/types/models/TAccount.d.ts +7 -1
  57. package/lib/types/prebuilt-factories/TimelockControllerFactory.d.ts +188 -0
  58. package/lib/types/services/TimelockService/TimelockService.d.ts +18 -3
  59. package/lib/types/txs/TxWriter.d.ts +20 -13
  60. package/lib/types/txs/agents/TimelockAgent.d.ts +26 -0
  61. package/lib/types/txs/agents/TxWriterAccountAgents.d.ts +2 -2
  62. package/lib/types/utils/$account.d.ts +2 -1
  63. package/lib/types/utils/$bigint.d.ts +2 -1
  64. package/lib/types/utils/$date.d.ts +1 -0
  65. package/package.json +1 -1
  66. package/src/blocks/BlockDateResolver.ts +61 -28
  67. package/src/contracts/deploy/Deployments.ts +5 -1
  68. package/src/contracts/deploy/proxy/ProxyDeployment.ts +2 -1
  69. package/src/erc4337/Erc4337Factory.ts +0 -2
  70. package/src/indexer/EventsIndexer.ts +18 -3
  71. package/src/models/TAccount.ts +11 -1
  72. package/src/prebuilt-factories/TimelockControllerFactory.ts +582 -0
  73. package/src/services/TimelockService/TimelockService.ts +83 -7
  74. package/src/txs/TxWriter.ts +29 -17
  75. package/src/txs/agents/TimelockAgent.ts +116 -0
  76. package/src/txs/agents/TxWriterAccountAgents.ts +4 -2
  77. package/src/utils/$account.ts +18 -2
  78. package/src/utils/$bigint.ts +19 -2
  79. package/src/utils/$date.ts +11 -1
@@ -1,6 +1,4 @@
1
1
  import memd from 'memd';
2
- import { TimelockController } from '@dequanto/prebuilt/openzeppelin/TimelockController';
3
- import { ContractBase } from '@dequanto/contracts/ContractBase';
4
2
  import { JsonArrayStore } from '@dequanto/json/JsonArrayStore';
5
3
  import { IAccount } from '@dequanto/models/TAccount';
6
4
  import { TAddress } from '@dequanto/models/TAddress';
@@ -19,10 +17,25 @@ import { File } from 'atma-io';
19
17
  import { ITimelockTx, ITimelockTxParamsNormalized, ITimelockTxParams, ITimelockService, ETimelockTxStatus } from './ITimelockService';
20
18
  import { TTxWriteMethodKeys } from '@dequanto/utils/types';
21
19
 
20
+ import type { TimelockController } from '@dequanto/prebuilt/openzeppelin/TimelockController';
21
+ import type { ContractBase } from '@dequanto/contracts/ContractBase';
22
+
23
+ import { TxDataBuilder } from '@dequanto/txs/TxDataBuilder';
24
+
25
+ const CONFIG = {
26
+ dir: `0x/data`
27
+ };
22
28
 
23
29
 
24
30
  type TTimelockController = ContractBase & Pick<TimelockController,
25
- 'schedule' | 'scheduleBatch' | 'execute' | 'executeBatch' | 'getMinDelay' | 'cancel'
31
+ 'schedule'
32
+ | 'scheduleBatch'
33
+ | 'execute'
34
+ | 'executeBatch'
35
+ | 'getMinDelay'
36
+ | 'cancel'
37
+ | 'extractLogsCallScheduled'
38
+ | 'extractLogsCallSalt'
26
39
  >;
27
40
 
28
41
  export class TimelockService implements ITimelockService {
@@ -37,7 +50,7 @@ export class TimelockService implements ITimelockService {
37
50
  // Only for hardhat client. Default: false
38
51
  execute?: boolean
39
52
 
40
- // Directory to store the submitted schedules, default: `./0x/data/`
53
+ // Directory to store the submitted schedules, default: `./0x/data/`, or use `TimelockService.config` to override it globally
41
54
  dir?: string
42
55
  }
43
56
  ) {
@@ -57,6 +70,42 @@ export class TimelockService implements ITimelockService {
57
70
  return { status, schedule };
58
71
  }
59
72
 
73
+ async getPendingFromTx (txHash: TEth.Hex): Promise<{
74
+ status: ETimelockTxStatus;
75
+ schedule: ITimelockTx;
76
+ }> {
77
+ let receipt = await this.timelock.client.getTransactionReceipt(txHash);
78
+ $require.notNull(receipt, `Tx ${txHash} not found`);
79
+ let block = await this.timelock.client.getBlock(receipt.blockNumber);
80
+ let contract = this.timelock;
81
+ let callScheduled = contract.extractLogsCallScheduled(receipt);
82
+ $require.gte(callScheduled.length, 1, `Expected at least 1 CallScheduled log`);
83
+
84
+ let callSaltArr = contract.extractLogsCallSalt(receipt);
85
+ $require.eq(callSaltArr.length, 1, `Expected 1 CallSalt log, but got ${callSaltArr.length}`);
86
+ let [ callSalt ] = callSaltArr;
87
+
88
+ let [ callScheduleFirst ] = callScheduled;
89
+ callScheduleFirst.params.delay
90
+
91
+ let schedule = {
92
+ sender: null,
93
+ key: callSalt.params.id,
94
+ id: callSalt.params.id,
95
+ salt: callSalt.params.salt,
96
+ to: callScheduled.map(x => x.params.target),
97
+ data: callScheduled.map(x => x.params.data),
98
+ value: callScheduled.map(x => $hex.ensure(x.params.value)),
99
+ predecessor: null,
100
+ createdAt: block.timestamp,
101
+ validAt: block.timestamp + Number(callScheduleFirst.params.delay),
102
+ status: 'pending',
103
+ txSchedule: txHash,
104
+ } as ITimelockTx;
105
+ let status = await this.getScheduleStatus(schedule);
106
+ return { status, schedule };
107
+ }
108
+
60
109
  async executePendingByTitle (sender: IAccount, title: string): Promise<{
61
110
  tx: TxWriter;
62
111
  schedule: ITimelockTx;
@@ -103,11 +152,32 @@ export class TimelockService implements ITimelockService {
103
152
  schedule: ITimelockTx
104
153
  tx?: TEth.Hex
105
154
  }> {
106
-
107
155
  let txParams = await this.getTxParamsNormalizedFromContract(uniqueTaskName, sender, contract, method, ...params);
108
156
  return await this.processTxParams(txParams);
109
157
  }
110
158
 
159
+ async processData (
160
+ sender: IAccount,
161
+ builder: TxDataBuilder
162
+ ): Promise<{
163
+ prevStatus: ETimelockTxStatus
164
+ status: ETimelockTxStatus
165
+ schedule: ITimelockTx
166
+ tx?: TEth.Hex
167
+ }> {
168
+ let { to, data, value } = builder.data;
169
+ let titleKey = `${to}${data}`;
170
+ let params = <ITimelockTxParams> {
171
+ title: $contract.keccak256(titleKey, 'hex'),
172
+ sender: sender,
173
+ to: to,
174
+ data: data,
175
+ value: value
176
+ };
177
+ let txParams = await this.getTxParamsNormalized (params);
178
+ return await this.processTxParams(txParams);
179
+ }
180
+
111
181
  /** Schedules-Wait-Execute a task distinguished by the unique task name
112
182
  *
113
183
  * 1. if schedule doesn't exist, create it
@@ -485,7 +555,7 @@ export class TimelockService implements ITimelockService {
485
555
  private async getUniqueByKey (key: TEth.Hex): Promise<ITimelockTx> {
486
556
  let store = await this.getStore();
487
557
  let all = await store.getAll();
488
- let arr = all.filter(x => x.key === key);
558
+ let arr = all.filter(x => x.key === key && x.status === 'pending');
489
559
  $require.lt(arr.length, 2, `Timelock service expects ${key} to be unique. Found ${arr.length}`);
490
560
  return arr.length === 1 ? arr[0] : null;
491
561
  }
@@ -577,7 +647,7 @@ export class TimelockService implements ITimelockService {
577
647
  @memd.deco.memoize({ perInstance: true })
578
648
  private async getStore () {
579
649
  let { platform, network } = this.timelock.client;
580
- let dir = this.options?.dir ?? `0x/data`;
650
+ let dir = this.options?.dir ?? CONFIG.dir;
581
651
 
582
652
  let path = getPath(platform, dir);
583
653
  if (platform === 'hardhat' && network !== platform) {
@@ -595,6 +665,12 @@ export class TimelockService implements ITimelockService {
595
665
  key: x => x.id
596
666
  });
597
667
  }
668
+
669
+ static config (config: Partial<typeof CONFIG>) {
670
+ if (config.dir) {
671
+ CONFIG.dir = CONFIG.dir;
672
+ }
673
+ }
598
674
  }
599
675
 
600
676
  namespace util {
@@ -26,15 +26,17 @@ import { TxLogParser } from './receipt/TxLogParser';
26
26
 
27
27
  import { ISafeServiceTransport } from '@dequanto/safe/transport/ISafeServiceTransport';
28
28
  import { SigFileTransport } from './sig-transports/SigFileTransport';
29
- import { TxWriterAccountAgents } from './agents/TxWriterAccountAgents';
30
29
  import { PromiseEvent } from '@dequanto/class/PromiseEvent';
31
30
  import { $sig } from '@dequanto/utils/$sig';
32
31
  import { TEth } from '@dequanto/models/TEth';
33
32
  import { SafeServiceTypes } from '@dequanto/safe/types/SafeServiceTypes';
34
33
  import { ChainAccountService } from '@dequanto/ChainAccountService';
35
34
  import { $is } from '@dequanto/utils/$is';
35
+ import { TxWriterAccountAgents } from './agents/TxWriterAccountAgents';
36
+
36
37
 
37
- interface ITxWriterEvents {
38
+
39
+ export interface ITxWriterEvents {
38
40
  transactionHash (hash: TEth.Hex)
39
41
  receipt (receipt: TEth.TxReceipt)
40
42
  confirmation (confNumber: number, receipt: TEth.TxReceipt)
@@ -43,6 +45,25 @@ interface ITxWriterEvents {
43
45
  log (message: string)
44
46
  safeTxProposed (safeTx: SafeServiceTypes.ProposeTransactionProps)
45
47
  }
48
+ export interface ITxWriterEmitter {
49
+ onSent: PromiseLike<string | TEth.Hex>
50
+ onCompleted: PromiseLike<TEth.TxReceipt>
51
+
52
+ tx: ITxWriterTransaction
53
+ receipt: TEth.TxReceipt
54
+
55
+ on (event: keyof ITxWriterEvents, callback: Function): any | this
56
+ }
57
+
58
+ export interface ITxWriterTransaction {
59
+ timestamp: number
60
+ confirmations: number,
61
+ hash?: TEth.Hex
62
+ timeout?: NodeJS.Timer
63
+ receipt?: TEth.TxReceipt
64
+ error?: Error
65
+ knownLogs?: ITxLogItem[]
66
+ }
46
67
  export interface ITxWriterOptions {
47
68
  timeout?: number | boolean
48
69
  retries?: number
@@ -80,7 +101,7 @@ export interface ITxWriterOptions {
80
101
 
81
102
  const DEFAULTS: ITxWriterOptions = {};
82
103
 
83
- export class TxWriter extends class_EventEmitter<ITxWriterEvents> {
104
+ export class TxWriter extends class_EventEmitter<ITxWriterEvents> implements ITxWriterEmitter {
84
105
 
85
106
  onSent = new class_Dfr<string | TEth.Hex>();
86
107
  onCompleted = new class_Dfr<TEth.TxReceipt>();
@@ -108,17 +129,9 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> {
108
129
  }
109
130
 
110
131
  id = Math.round(Math.random() * 10**10) + '';
111
- tx: {
112
- timestamp: number
113
- confirmations: number,
114
- hash?: TEth.Hex
115
- timeout?: NodeJS.Timer
116
- receipt?: TEth.TxReceipt
117
- error?: Error
118
- knownLogs?: ITxLogItem[]
119
- } = null
120
-
121
- txs: TxWriter['tx'][] = []
132
+ tx: ITxWriterTransaction = null
133
+
134
+ txs: ITxWriterTransaction[] = []
122
135
  options: ITxWriterOptions;
123
136
 
124
137
 
@@ -173,9 +186,8 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> {
173
186
 
174
187
  let agent = TxWriterAccountAgents.get(this.account);
175
188
  if (agent != null) {
176
-
177
189
  let sender = await this.getSender();
178
- let innerWriter: TxWriter;
190
+ let innerWriter: ITxWriterEmitter;
179
191
  try {
180
192
  innerWriter = await agent.process(sender, this.account, this);
181
193
  } catch (error) {
@@ -479,7 +491,7 @@ export class TxWriter extends class_EventEmitter<ITxWriterEvents> {
479
491
  }
480
492
  this.sendTxInner();
481
493
  }
482
- private pipeInnerWriter (innerWriter: TxWriter) {
494
+ private pipeInnerWriter (innerWriter: ITxWriterEmitter) {
483
495
  innerWriter.onCompleted.then(
484
496
  (receipt) => {
485
497
  this.tx = innerWriter.tx;
@@ -0,0 +1,116 @@
1
+ import { EoAccount, TAccount, TimelockAccount } from '@dequanto/models/TAccount';
2
+ import { ITxWriterAccountAgent } from './TxWriterAccountAgents';
3
+ import { $account } from '@dequanto/utils/$account';
4
+ import { ITxWriterEmitter, ITxWriterEvents, ITxWriterTransaction, TxWriter } from '../TxWriter';
5
+
6
+ import { ChainAccountService } from '@dequanto/ChainAccountService';
7
+ import { $promise } from '@dequanto/utils/$promise';
8
+ import { class_Dfr, class_EventEmitter } from 'atma-utils';
9
+ import { TEth } from '@dequanto/models/TEth';
10
+ import { $require } from '@dequanto/utils/$require';
11
+ import { $date } from '@dequanto/utils/$date';
12
+ import { ITimelockTx } from '@dequanto/services/TimelockService/ITimelockService';
13
+ import { Web3Client } from '@dequanto/clients/Web3Client';
14
+
15
+ import { TimelockService } from '@dequanto/services/TimelockService/TimelockService';
16
+ import { TimelockControllerFactory } from '@dequanto/prebuilt-factories/TimelockControllerFactory';
17
+
18
+
19
+ export class TimelockAgent implements ITxWriterAccountAgent {
20
+ supports (account: TAccount) {
21
+ return $account.isTimelock(account);
22
+ }
23
+ async process (senderMix: string | EoAccount, timelockAccount: TimelockAccount, outerWriter: TxWriter) {
24
+
25
+ let { client, options } = outerWriter;
26
+ let TimelockController = TimelockControllerFactory();
27
+ let timelock = new TimelockController(timelockAccount.address, client);
28
+ let service = new TimelockService(timelock, {
29
+ simulate: false,
30
+ });
31
+ let sender = typeof senderMix === 'string'
32
+ ? await ChainAccountService.get(senderMix) as EoAccount
33
+ : senderMix;
34
+
35
+ let inner = new TimelockTxWriter(
36
+ client,
37
+ sender,
38
+ service,
39
+ outerWriter,
40
+ );
41
+
42
+ await inner.process();
43
+ return inner;
44
+ }
45
+ }
46
+
47
+ export class TimelockTxWriter extends class_EventEmitter<ITxWriterEvents> implements ITxWriterEmitter {
48
+
49
+ onSent = new class_Dfr<string | TEth.Hex>()
50
+ onCompleted = new class_Dfr<TEth.TxReceipt>()
51
+ receipt: TEth.TxReceipt
52
+ tx: ITxWriterTransaction
53
+
54
+ schedule: ITimelockTx
55
+ delayTimer: any
56
+
57
+ constructor (
58
+ private client: Web3Client,
59
+ private sender: TEth.IAccount,
60
+ private service: TimelockService,
61
+ private outerWriter: TxWriter,
62
+ ) {
63
+ super();
64
+ }
65
+
66
+ async process () {
67
+ let { sender, service, client, outerWriter } = this;
68
+
69
+ let { error, result } = await $promise.caught(service.processData(sender, outerWriter.builder));
70
+ if (error) {
71
+ this.onCompleted.reject(error);
72
+ this.emit('error', error);
73
+ return this;
74
+ }
75
+ if (result.status === 'completed') {
76
+ $require.Hex(result.tx, 'Timelock transaction hash expected');
77
+ let receipt = await client.getTransactionReceipt(result.tx);
78
+ let block = await client.getBlock(receipt.blockNumber);
79
+ let latestBlock = await client.getBlockNumber();
80
+ $require.notNull(receipt, `Receipt for ${result.tx} not found`);
81
+
82
+ let tx = {
83
+ timestamp: block.timestamp,
84
+ confirmations: latestBlock - block.number,
85
+ hash: receipt.transactionHash,
86
+ receipt: receipt,
87
+ error: null,
88
+ knownLogs: null,
89
+ } as ITxWriterTransaction;
90
+
91
+ this.tx = tx;
92
+ this.emit('transactionHash', receipt.transactionHash);
93
+ this.emit('receipt', receipt);
94
+ this.onCompleted.resolve(receipt);
95
+ return this;
96
+ }
97
+ if (result.status === 'pending') {
98
+ let readyAt = $date.fromUnixTimestamp(result.schedule.validAt);
99
+ let readyAtF = $date.format(readyAt, 'yyyy-MM-DD HH:mm:ss');
100
+ this.emit('log', `Timelock transaction pending: ${result.schedule.id}, ready at: ${readyAtF}`);
101
+ this.onSent.resolve(result.schedule.id);
102
+
103
+ let ms = readyAt.valueOf() - Date.now();
104
+ $require.gt(ms, 0, `The transaction must be in 'ready' state`);
105
+ this.delayTimer = setTimeout(() => {
106
+ this.process();
107
+ }, ms);
108
+ return this;
109
+ }
110
+ if (result.status === 'ready') {
111
+ throw new Error(`[TimelockAgent] Service emits 'ready' status, however it should execute the transaction directly`);
112
+ }
113
+
114
+ throw new Error(`[TimelockAgent] Unsupported status: ${result.status}`);
115
+ }
116
+ }
@@ -1,13 +1,14 @@
1
1
  import type { EoAccount, TAccount } from '@dequanto/models/TAccount';
2
- import type { TxWriter } from '../TxWriter';
2
+ import type { ITxWriterEmitter, TxWriter } from '../TxWriter';
3
3
  import { SafeAgent } from './SafeAgent';
4
4
  import { Erc4337Agent } from './Erc4337Agent';
5
+ import { TimelockAgent } from './TimelockAgent';
5
6
 
6
7
 
7
8
 
8
9
  export interface ITxWriterAccountAgent {
9
10
  supports (account: TAccount): boolean
10
- process (sender: EoAccount, account: TAccount, outerWriter: TxWriter): Promise<TxWriter>
11
+ process (sender: EoAccount, account: TAccount, outerWriter: TxWriter): Promise<ITxWriterEmitter>
11
12
  }
12
13
 
13
14
  export namespace TxWriterAccountAgents {
@@ -15,6 +16,7 @@ export namespace TxWriterAccountAgents {
15
16
  const agents: ITxWriterAccountAgent[] = [
16
17
  new SafeAgent(),
17
18
  new Erc4337Agent(),
19
+ new TimelockAgent(),
18
20
  ];
19
21
 
20
22
  export function register (agent: ITxWriterAccountAgent) {
@@ -1,5 +1,6 @@
1
- import { EoAccount, Erc4337Account, SafeAccount, TAccount } from "@dequanto/models/TAccount";
1
+ import { EoAccount, Erc4337Account, SafeAccount, TAccount, TimelockAccount } from "@dequanto/models/TAccount";
2
2
  import { $address } from './$address';
3
+ import { $require } from './$require';
3
4
 
4
5
  export namespace $account {
5
6
 
@@ -11,10 +12,11 @@ export namespace $account {
11
12
  return { name: account };
12
13
  }
13
14
 
14
- let acc = isSafe(account) || isErc4337 (account)
15
+ let acc = isSafe(account) || isErc4337 (account) || isTimelock(account)
15
16
  ? account.operator
16
17
  : account;
17
18
 
19
+ $require.notNull(acc, `Sender not resolved for ${ account?.address ?? account }`);
18
20
  return acc as EoAccount;
19
21
  }
20
22
 
@@ -45,4 +47,18 @@ export namespace $account {
45
47
  }
46
48
  return false;
47
49
  }
50
+
51
+ export function isTimelock (account:TAccount): account is TimelockAccount {
52
+ if (account == null) {
53
+ return false;
54
+ }
55
+ let rgx = /^timelock\//;
56
+ if (typeof account === 'string') {
57
+ return rgx.test(account);
58
+ }
59
+ if (account.type === 'timelock' || rgx.test(account.name)) {
60
+ return true;
61
+ }
62
+ return false;
63
+ }
48
64
  }
@@ -49,8 +49,25 @@ export namespace $bigint {
49
49
  return BigInt(Math.round(amount));
50
50
  }
51
51
 
52
+ export function from (amount: number | bigint | string): bigint {
53
+ if (amount == null) {
54
+ return 0n;
55
+ }
56
+ switch (typeof amount) {
57
+ case 'bigint':
58
+ return amount;
59
+ case 'number':
60
+ return BigInt(amount);
61
+ case'string':
62
+ return parse(amount);
63
+ default:
64
+ break;
65
+ }
66
+ throw new Error(`Invalid $bigint.from type: ${amount}`);
67
+ }
68
+
52
69
  /**
53
- * @param amount e.g "2.4 ether", "10 gwei", "1.7^18", "123456"
70
+ * @param amount e.g "2.4 ether", "10 gwei", "1.7^18", "123456", "1.7e18"
54
71
  */
55
72
  export function parse (amount: string): bigint {
56
73
  if (/^\d+$/.test(amount) || $is.Hex(amount) ) {
@@ -76,7 +93,7 @@ export namespace $bigint {
76
93
  }
77
94
 
78
95
  // 2.5^18
79
- let rgxMantissa = /^(?<number>[\d.]+)\s*\^\s*(?<decimals>\d+)$/;
96
+ let rgxMantissa = /^(?<number>[\d.]+)\s*[\^e]\s*(?<decimals>\d+)$/;
80
97
  let rgxMantissaMatch = rgxMantissa.exec(amount);
81
98
  if (rgxMantissaMatch != null) {
82
99
  let number = Number(rgxMantissaMatch.groups.number);
@@ -250,6 +250,17 @@ export namespace $date {
250
250
  result.setHours(23, 59, 59, 999);
251
251
  return result;
252
252
  }
253
+ export function weekNumber(date = new Date()) {
254
+ date = new Date(date);
255
+ date.setHours(0, 0, 0, 0);
256
+
257
+ // Set to nearest Thursday: current date + 4 - current day number
258
+ const dayNum = date.getDay() || 7;
259
+ date.setDate(date.getDate() + 4 - dayNum);
260
+ // Calculate week number
261
+ const yearStart = new Date(Date.UTC(date.getFullYear(), 0, 1));
262
+ return Math.ceil((((date.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
263
+ }
253
264
  export function monthStart(date = new Date()) {
254
265
  let result = new Date(date);
255
266
  result.setDate(1);
@@ -264,7 +275,6 @@ export namespace $date {
264
275
  return result;
265
276
  }
266
277
 
267
-
268
278
  /** date1 + X === date2 */
269
279
  export function daysBetween(a: Date, b: Date, abs: boolean = true) {
270
280
  let aStart = dayStart(a);