dequanto 0.1.78 → 0.1.81

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 (36) hide show
  1. package/lib/cjs/contracts/deploy/Deployments.js +5 -1
  2. package/lib/cjs/contracts/deploy/Deployments.js.map +1 -1
  3. package/lib/cjs/contracts/deploy/proxy/ProxyDeployment.js +11 -5
  4. package/lib/cjs/contracts/deploy/proxy/ProxyDeployment.js.map +1 -1
  5. package/lib/cjs/hardhat/HardhatProvider.js +3 -1
  6. package/lib/cjs/hardhat/HardhatProvider.js.map +1 -1
  7. package/lib/cjs/indexer/EventsIndexer.js +14 -2
  8. package/lib/cjs/indexer/EventsIndexer.js.map +1 -1
  9. package/lib/cjs/services/TimelockService/TimelockService.js +30 -0
  10. package/lib/cjs/services/TimelockService/TimelockService.js.map +1 -1
  11. package/lib/cjs/utils/$bigint.js +19 -2
  12. package/lib/cjs/utils/$bigint.js.map +1 -1
  13. package/lib/esm/contracts/deploy/Deployments.js.map +1 -1
  14. package/lib/esm/contracts/deploy/Deployments.mjs +5 -1
  15. package/lib/esm/contracts/deploy/proxy/ProxyDeployment.js.map +1 -1
  16. package/lib/esm/contracts/deploy/proxy/ProxyDeployment.mjs +11 -5
  17. package/lib/esm/hardhat/HardhatProvider.js.map +1 -1
  18. package/lib/esm/hardhat/HardhatProvider.mjs +3 -1
  19. package/lib/esm/indexer/EventsIndexer.js.map +1 -1
  20. package/lib/esm/indexer/EventsIndexer.mjs +14 -2
  21. package/lib/esm/services/TimelockService/TimelockService.js.map +1 -1
  22. package/lib/esm/services/TimelockService/TimelockService.mjs +30 -0
  23. package/lib/esm/utils/$bigint.js.map +1 -1
  24. package/lib/esm/utils/$bigint.mjs +19 -2
  25. package/lib/types/contracts/deploy/Deployments.d.ts +7 -0
  26. package/lib/types/contracts/deploy/proxy/ProxyDeployment.d.ts +2 -0
  27. package/lib/types/hardhat/HardhatProvider.d.ts +1 -0
  28. package/lib/types/services/TimelockService/TimelockService.d.ts +4 -0
  29. package/lib/types/utils/$bigint.d.ts +2 -1
  30. package/package.json +1 -1
  31. package/src/contracts/deploy/Deployments.ts +16 -1
  32. package/src/contracts/deploy/proxy/ProxyDeployment.ts +18 -12
  33. package/src/hardhat/HardhatProvider.ts +4 -1
  34. package/src/indexer/EventsIndexer.ts +18 -3
  35. package/src/services/TimelockService/TimelockService.ts +36 -0
  36. package/src/utils/$bigint.ts +19 -2
@@ -22,6 +22,7 @@ export interface IBeacon extends ContractBase {
22
22
  interface IDeploymentCtx {
23
23
  ImplementationContract: Constructor<ContractBase>;
24
24
  deployer: IAccount;
25
+ owner?: IAccount;
25
26
  deployments: Deployments;
26
27
  implementation: {
27
28
  address: TAddress;
@@ -30,6 +31,7 @@ interface IDeploymentCtx {
30
31
  options?: {
31
32
  skipStorageLayoutCheck?: boolean;
32
33
  };
34
+ upgradeImplementation?: boolean;
33
35
  }
34
36
  interface IProxyDeploymentCtx extends IDeploymentCtx {
35
37
  proxyId: string;
@@ -35,6 +35,7 @@ export declare class HardhatProvider {
35
35
  deployer?: EoAccount;
36
36
  arguments?: any[];
37
37
  client?: Web3Client;
38
+ tx?: TEth.Hex;
38
39
  }): Promise<{
39
40
  contract: T;
40
41
  receipt: TEth.TxReceipt;
@@ -18,6 +18,10 @@ export declare class TimelockService implements ITimelockService {
18
18
  status: ETimelockTxStatus;
19
19
  schedule: ITimelockTx;
20
20
  }>;
21
+ getPendingFromTx(txHash: TEth.Hex): Promise<{
22
+ status: ETimelockTxStatus;
23
+ schedule: ITimelockTx;
24
+ }>;
21
25
  executePendingByTitle(sender: IAccount, title: string): Promise<{
22
26
  tx: TxWriter;
23
27
  schedule: ITimelockTx;
@@ -6,8 +6,9 @@ export declare namespace $bigint {
6
6
  function max(...args: bigint[]): bigint;
7
7
  function min(...args: bigint[]): bigint;
8
8
  function toBigInt(amount: string | number | bigint | Uint8Array): bigint;
9
+ function from(amount: number | bigint | string): bigint;
9
10
  /**
10
- * @param amount e.g "2.4 ether", "10 gwei", "1.7^18", "123456"
11
+ * @param amount e.g "2.4 ether", "10 gwei", "1.7^18", "123456", "1.7e18"
11
12
  */
12
13
  function parse(amount: string): bigint;
13
14
  function ensureWei(amount: number | bigint, decimals: number): bigint;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dequanto",
3
- "version": "0.1.78",
3
+ "version": "0.1.81",
4
4
  "author": {
5
5
  "name": "Alex Kit",
6
6
  "email": "alex.kit@atmajs.com"
@@ -22,6 +22,7 @@ import { TAddress } from '@dequanto/models/TAddress';
22
22
  import { $promise } from '@dequanto/utils/$promise';
23
23
  import { l } from '@dequanto/utils/$logger';
24
24
  import { $bytecode } from '@dequanto/evm/utils/$bytecode';
25
+ import { THex } from '@dequanto/models/THex';
25
26
 
26
27
 
27
28
 
@@ -37,6 +38,15 @@ type TDeploymentOptions = {
37
38
 
38
39
  // Will be used for verification process
39
40
  proxyFor?: TAddress
41
+
42
+ deployment?: {
43
+ // Pending deployment transaction will be re-checked
44
+ tx?: TEth.Hex
45
+ // When false, the implementation won't be updated in proxy
46
+ upgradeProxy?: boolean
47
+ // Owner, if differes from deployer
48
+ owner?: TEth.IAccount
49
+ }
40
50
  }
41
51
  type TVerificationOptions = TDeploymentOptions & {
42
52
  // otherwise will be fetched from the deployment TX
@@ -67,6 +77,7 @@ export class Deployments {
67
77
  }
68
78
 
69
79
  constructor(public client: Web3Client, public deployer: IAccount, public opts: {
80
+ owner?: IAccount
70
81
  Proxy?: Constructor<ContractBase>,
71
82
  ProxyAdmin?: Constructor<IProxyAdmin>
72
83
  directory?: string
@@ -252,6 +263,7 @@ export class Deployments {
252
263
  arguments: constructorArgs,
253
264
  client: this.client,
254
265
  deployer: this.deployer as any,
266
+ tx: opts.deployment?.tx
255
267
  });
256
268
 
257
269
  let deployment = await this.store.saveDeployment(deployedContract, {
@@ -304,6 +316,7 @@ export class Deployments {
304
316
  force: opts?.force,
305
317
  latest: this.opts?.checkBytecode !== false,
306
318
  verification: opts?.verification,
319
+ deployment: opts?.deployment
307
320
  });
308
321
 
309
322
  let data = serializeInitData(id, contractImpl, opts.initialize);
@@ -317,11 +330,13 @@ export class Deployments {
317
330
  ImplementationContract: CtorImpl,
318
331
  proxyId: proxyId,
319
332
  deployer: this.deployer,
333
+ owner: opts.deployment?.owner ?? this.opts?.owner ?? this.deployer,
320
334
  deployments: this,
321
335
  implementation: {
322
336
  address: implementationAddress,
323
337
  initData: data
324
- }
338
+ },
339
+ upgradeImplementation: opts.deployment?.upgradeProxy ?? true
325
340
  })
326
341
 
327
342
  if (contractImplDeployment.implementation == null) {
@@ -37,6 +37,7 @@ export interface IBeacon extends ContractBase {
37
37
  interface IDeploymentCtx {
38
38
  ImplementationContract: Constructor<ContractBase>
39
39
  deployer: IAccount
40
+ owner?: IAccount
40
41
  deployments: Deployments
41
42
  implementation: {
42
43
  address: TAddress
@@ -45,6 +46,7 @@ interface IDeploymentCtx {
45
46
  options?: {
46
47
  skipStorageLayoutCheck?: boolean
47
48
  }
49
+ upgradeImplementation?: boolean
48
50
  }
49
51
 
50
52
  interface IProxyDeploymentCtx extends IDeploymentCtx {
@@ -151,6 +153,7 @@ export class ProxyDeployment {
151
153
 
152
154
 
153
155
  let hasProxy = await deployments.has(Proxy, proxyOpts);
156
+ let shouldUpdate = ctx.upgradeImplementation ?? true;
154
157
  let {
155
158
  contract: contractProxy,
156
159
  receipt: contractProxyReceipt,
@@ -201,18 +204,21 @@ export class ProxyDeployment {
201
204
  let slotValue = await client.getStorageAt(contractProxy.address, SLOT);
202
205
  let address = `0x` + slotValue.slice(-40);
203
206
  if ($address.eq(address, implAddress) === false) {
204
- await this.requireCompatibleStorageLayout(proxyId, ctx);
205
-
206
- $logger.log(`Upgrading ProxyAdmin(${contractProxyAdmin.address}) to ${implAddress} (${v}) from ${address}`);
207
- let receipt = await Interfaces.call(
208
- deployer,
209
- contractProxyAdmin,
210
- Interfaces.TransparentProxy[v].contractProxyAdmin.upgradeAndCall,
211
- contractProxy.address,
212
- implAddress,
213
- null // data
214
- );
215
- await this.saveStorageLayout(proxyId, ctx);
207
+ if (shouldUpdate) {
208
+ await this.requireCompatibleStorageLayout(proxyId, ctx);
209
+ $logger.log(`Upgrading ProxyAdmin(${contractProxyAdmin.address}) to ${implAddress} (${v}) from ${address}`);
210
+ let receipt = await Interfaces.call(
211
+ ctx.owner ?? deployer,
212
+ contractProxyAdmin,
213
+ Interfaces.TransparentProxy[v].contractProxyAdmin.upgradeAndCall,
214
+ contractProxy.address,
215
+ implAddress,
216
+ null // data
217
+ );
218
+ await this.saveStorageLayout(proxyId, ctx);
219
+ } else {
220
+ $logger.log(`Skip upgrade ProxyAdmin(${contractProxyAdmin.address}) to ${implAddress} (${v}) from ${address}`);
221
+ }
216
222
  }
217
223
  }
218
224
  if (hasProxy === false && contractProxyReceipt != null) {
@@ -142,6 +142,7 @@ export class HardhatProvider {
142
142
  deployer?: EoAccount
143
143
  arguments?: any[]
144
144
  client?: Web3Client
145
+ tx?: TEth.Hex
145
146
  }): Promise<{
146
147
  contract: T
147
148
  receipt: TEth.TxReceipt
@@ -155,7 +156,9 @@ export class HardhatProvider {
155
156
  let receipt: TEth.TxReceipt;
156
157
 
157
158
  try {
158
- receipt = await factory.deploy();
159
+ receipt = options?.tx
160
+ ? await client.getTransactionReceipt(options.tx)
161
+ : await factory.deploy();
159
162
  } catch (error) {
160
163
  let wrapped = new Error(`Deploy ${Ctor.name} failed: ` + error.message + `\n ${error.stack}`);
161
164
  (wrapped as any).data = error.data;
@@ -106,7 +106,9 @@ export class EventsIndexer <TContract extends ContractBase> {
106
106
  > (
107
107
  event: TLogName | TLogName[] | '*',
108
108
  options?: {
109
+ // includes block
109
110
  fromBlock?: number
111
+ // includes block
110
112
  toBlock?: number
111
113
  blockRangeLimits?: WClient['blockRangeLimits']
112
114
  params?: Partial<TContract['Types']['Events'][TLogName]['outputParams']>
@@ -183,6 +185,10 @@ export class EventsIndexer <TContract extends ContractBase> {
183
185
  fromBlock?: number
184
186
  filterKey?: string
185
187
  }): Promise<TRange[]> {
188
+ let fromBlock = opts?.fromBlock ?? initialBlockNumber;
189
+ if (fromBlock != null) {
190
+ $require.lte(fromBlock, toBlock, `Invalid block range order`);
191
+ }
186
192
  let logsMetaArr = await this.storeMeta.fetch();
187
193
  let eventsBlock = alot(logsMetaArr)
188
194
  .filter(x => x.filterKey == opts?.filterKey)
@@ -198,15 +204,24 @@ export class EventsIndexer <TContract extends ContractBase> {
198
204
  if (hasInitialBlock === false) {
199
205
  let blockNr = opts?.fromBlock ?? await this.getInitialBlockNumber();
200
206
  logsMeta.filter(x => x.lastBlock == null).forEach(x => x.lastBlock = blockNr);
201
- };
207
+ }
202
208
 
203
209
  let ranges = [] as TRange[];
204
- let blockNumbers = [ ...logsMeta.map(x => x.lastBlock), toBlock ];
205
- let blockNumberSteps = alot(blockNumbers).distinct().sortBy(x => x).toArray();
210
+ let blockNumbers = [ ...logsMeta.map(x => x.lastBlock), toBlock ].filter(x => x <= toBlock);
206
211
 
212
+ let blockNumberSteps = alot(blockNumbers).distinct().sortBy(x => x).toArray();
213
+ if (blockNumberSteps.length === 1) {
214
+ let [ block ] = blockNumberSteps;
215
+ ranges.push({
216
+ fromBlock: block,
217
+ toBlock: block,
218
+ events: events
219
+ });
220
+ }
207
221
  for (let i = 0; i < blockNumberSteps.length - 1; i++) {
208
222
  let from = blockNumberSteps[i];
209
223
  if (i > 0) {
224
+ // The range includes both blocks: [x, y], but we want (x, y], so we make [x + 1, y]
210
225
  from += 1;
211
226
  }
212
227
  let to = blockNumberSteps[i + 1];
@@ -57,6 +57,42 @@ export class TimelockService implements ITimelockService {
57
57
  return { status, schedule };
58
58
  }
59
59
 
60
+ async getPendingFromTx (txHash: TEth.Hex): Promise<{
61
+ status: ETimelockTxStatus;
62
+ schedule: ITimelockTx;
63
+ }> {
64
+ let receipt = await this.timelock.client.getTransactionReceipt(txHash);
65
+ $require.notNull(receipt, `Tx ${txHash} not found`);
66
+ let block = await this.timelock.client.getBlock(receipt.blockNumber);
67
+ let contract = new TimelockController(void 0, this.timelock.client);
68
+ let callScheduled = contract.extractLogsCallScheduled(receipt);
69
+ $require.gte(callScheduled.length, 1, `Expected at least 1 CallScheduled log`);
70
+
71
+ let callSaltArr = contract.extractLogsCallSalt(receipt);
72
+ $require.eq(callSaltArr.length, 1, `Expected 1 CallSalt log, but got ${callSaltArr.length}`);
73
+ let [ callSalt ] = callSaltArr;
74
+
75
+ let [ callScheduleFirst ] = callScheduled;
76
+ callScheduleFirst.params.delay
77
+
78
+ let schedule = {
79
+ sender: null,
80
+ key: callSalt.params.id,
81
+ id: callSalt.params.id,
82
+ salt: callSalt.params.salt,
83
+ to: callScheduled.map(x => x.params.target),
84
+ data: callScheduled.map(x => x.params.data),
85
+ value: callScheduled.map(x => $hex.ensure(x.params.value)),
86
+ predecessor: null,
87
+ createdAt: block.timestamp,
88
+ validAt: block.timestamp + Number(callScheduleFirst.params.delay),
89
+ status: 'pending',
90
+ txSchedule: txHash,
91
+ } as ITimelockTx;
92
+ let status = await this.getScheduleStatus(schedule);
93
+ return { status, schedule };
94
+ }
95
+
60
96
  async executePendingByTitle (sender: IAccount, title: string): Promise<{
61
97
  tx: TxWriter;
62
98
  schedule: ITimelockTx;
@@ -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);