@boostxyz/sdk 7.2.0 → 7.3.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.
@@ -576,18 +576,25 @@ export class EventAction extends DeployableTarget<
576
576
  throw new ValidationAbiMissingError(signature);
577
577
  }
578
578
 
579
- let address: Address | undefined;
580
579
  if ('logs' in params) {
581
- for (let log of params.logs) {
580
+ const signatureMatchingLogs = params.logs
581
+ .filter((log) => log.topics[0] === signature)
582
+ .map((log) => decodeAndReorderLogArgs(event, log));
583
+
584
+ for (const log of signatureMatchingLogs) {
582
585
  if (!isAddressEqual(log.address, claimant.targetContract)) continue;
583
- let addressCandidate = this.validateClaimantAgainstArgs(
586
+ const addressCandidate = this.validateClaimantAgainstArgs(
584
587
  claimant,
585
588
  log,
586
589
  );
587
590
  if (addressCandidate) return addressCandidate;
588
591
  }
589
- return address;
590
592
  }
593
+
594
+ if (!('hash' in params)) {
595
+ return undefined;
596
+ }
597
+
591
598
  const receipt = await getTransactionReceipt(this._config, {
592
599
  ...params,
593
600
  chainId: claimant.chainid,
@@ -613,7 +620,6 @@ export class EventAction extends DeployableTarget<
613
620
  let addressCandidate = this.validateClaimantAgainstArgs(claimant, log);
614
621
  if (addressCandidate) return addressCandidate;
615
622
  }
616
- return address;
617
623
  }
618
624
  if (claimant.signatureType === SignatureType.FUNC && 'hash' in params) {
619
625
  const transaction = await getTransaction(this._config, {
@@ -1252,6 +1258,139 @@ export class EventAction extends DeployableTarget<
1252
1258
  }
1253
1259
  return false;
1254
1260
  }
1261
+
1262
+ /**
1263
+ * Retrieves logs that match the criteria for event-based action steps.
1264
+ *
1265
+ * @public
1266
+ * @async
1267
+ * @param {ValidateActionStepParams} params - Parameters for fetching and filtering logs.
1268
+ * @returns {Promise<EventLog[]>} - A promise that resolves to an array of matching event logs.
1269
+ */
1270
+ public async getLogsForActionSteps(
1271
+ params: ValidateActionStepParams,
1272
+ ): Promise<EventLog[]> {
1273
+ const actionSteps = await this.getActionSteps();
1274
+ const actionStepLogs: EventLog[] = [];
1275
+
1276
+ for (const actionStep of actionSteps) {
1277
+ if (actionStep.signatureType === SignatureType.EVENT) {
1278
+ const logs = await this.getLogsForActionStep(actionStep, params);
1279
+ actionStepLogs.push(...logs);
1280
+ }
1281
+ }
1282
+ return actionStepLogs;
1283
+ }
1284
+
1285
+ /**
1286
+ * Finds logs that match the criteria for a specific action step.
1287
+ *
1288
+ * @public
1289
+ * @async
1290
+ * @param {ActionStep} actionStep - The action step to find logs for
1291
+ * @param {ValidateActionStepParams} params - Parameters for validation
1292
+ * @returns {Promise<EventLog[]>}
1293
+ */
1294
+ public async getLogsForActionStep(
1295
+ actionStep: ActionStep,
1296
+ params: ValidateActionStepParams,
1297
+ ): Promise<EventLog[]> {
1298
+ if (actionStep.signatureType !== SignatureType.EVENT) {
1299
+ return [];
1300
+ }
1301
+
1302
+ const signature = actionStep.signature;
1303
+ let event: AbiEvent;
1304
+ if (params.abiItem) event = params.abiItem as AbiEvent;
1305
+ else {
1306
+ const sigPool = params.knownSignatures as Record<Hex, AbiEvent>;
1307
+ event = sigPool[signature] as AbiEvent;
1308
+ }
1309
+
1310
+ if (!event) {
1311
+ throw new ValidationAbiMissingError(signature);
1312
+ }
1313
+
1314
+ if ('logs' in params) {
1315
+ return this.filterLogsByActionStepCriteria(
1316
+ actionStep,
1317
+ params.logs,
1318
+ event,
1319
+ );
1320
+ }
1321
+
1322
+ const receipt = await getTransactionReceipt(this._config, {
1323
+ ...params,
1324
+ chainId: actionStep.chainid,
1325
+ });
1326
+
1327
+ if (
1328
+ params.notBeforeBlockNumber &&
1329
+ receipt.blockNumber < params.notBeforeBlockNumber
1330
+ ) {
1331
+ return [];
1332
+ }
1333
+
1334
+ // Special handling for Transfer events
1335
+ if (actionStep.signature === TRANSFER_SIGNATURE) {
1336
+ const { decodedLogs, event } = await this.decodeTransferLogs(receipt);
1337
+ return this.filterLogsByActionStepCriteria(
1338
+ actionStep,
1339
+ decodedLogs,
1340
+ event,
1341
+ );
1342
+ }
1343
+
1344
+ const decodedLogs = receipt.logs
1345
+ .filter((log) => log.topics[0] === toEventSelector(event))
1346
+ .map((log) => decodeAndReorderLogArgs(event, log));
1347
+
1348
+ return this.filterLogsByActionStepCriteria(actionStep, decodedLogs, event);
1349
+ }
1350
+
1351
+ /**
1352
+ * Filters logs that meet the given action step criteria
1353
+ *
1354
+ * @private
1355
+ * @param {ActionStep} actionStep
1356
+ * @param {EventLogs} logs
1357
+ * @param {AbiEvent} eventAbi
1358
+ * @returns {EventLog[]}
1359
+ */
1360
+ private filterLogsByActionStepCriteria(
1361
+ actionStep: ActionStep,
1362
+ logs: EventLogs,
1363
+ eventAbi: AbiEvent,
1364
+ ): EventLog[] {
1365
+ const criteria = actionStep.actionParameter;
1366
+ const filteredLogs: EventLog[] = [];
1367
+
1368
+ if (!logs.length) return filteredLogs;
1369
+
1370
+ for (let log of logs) {
1371
+ if (!isAddressEqual(log.address, actionStep.targetContract)) continue;
1372
+
1373
+ try {
1374
+ if (!Array.isArray(log.args)) {
1375
+ continue;
1376
+ }
1377
+ const { value, type } = this.parseFieldFromAbi(
1378
+ log.args,
1379
+ criteria.fieldIndex,
1380
+ eventAbi.inputs || [],
1381
+ criteria.fieldType,
1382
+ );
1383
+ criteria.fieldType = type;
1384
+ if (this.validateFieldAgainstCriteria(criteria, value, { log })) {
1385
+ filteredLogs.push(log as EventLog);
1386
+ }
1387
+ } catch {
1388
+ // If there's an error on this log, keep trying with the next one
1389
+ }
1390
+ }
1391
+
1392
+ return filteredLogs;
1393
+ }
1255
1394
  }
1256
1395
 
1257
1396
  /**
@@ -37,6 +37,7 @@ import {
37
37
  import { ERC20PeggedVariableCriteriaIncentiveV2 as ERC20PeggedVariableCriteriaIncentiveV2Bases } from '../../dist/deployments.json';
38
38
  import {
39
39
  SignatureType,
40
+ decodeAndReorderLogArgs,
40
41
  getScalarValueFromTuple,
41
42
  isCriteriaFieldIndexTuple,
42
43
  } from '../Actions/EventAction';
@@ -235,25 +236,63 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
235
236
  * @throws {InvalidCriteriaTypeError | NoMatchingLogsError | DecodedArgsError}
236
237
  */
237
238
  public async getIncentiveScalar(
238
- { chainId, hash, knownSignatures }: GetIncentiveScalarV2Params,
239
+ { chainId, hash, knownSignatures, logs }: GetIncentiveScalarV2Params,
239
240
  params?: ReadParams,
240
241
  ): Promise<bigint> {
241
242
  const criteria = await this.getIncentiveCriteria(params);
242
243
  if (criteria.criteriaType === SignatureType.EVENT) {
243
- const transactionReceipt = await getTransactionReceipt(this._config, {
244
- chainId,
245
- hash,
246
- });
244
+ const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
245
+
247
246
  if (criteria.fieldIndex === CheatCodes.GAS_REBATE_INCENTIVE) {
247
+ const transactionReceipt = await getTransactionReceipt(this._config, {
248
+ chainId,
249
+ hash,
250
+ });
248
251
  const totalCost =
249
252
  transactionReceipt.gasUsed * transactionReceipt.effectiveGasPrice + // Normal gas cost
250
253
  (transactionReceipt.blobGasUsed ?? 0n) *
251
254
  (transactionReceipt.blobGasPrice ?? 0n); // Blob gas cost - account for potential undefined values
252
255
  return totalCost;
253
256
  }
254
- const logs = transactionReceipt.logs;
255
257
 
256
- if (logs.length === 0) {
258
+ // if logs are provided, use them to extract the scalar
259
+ if (logs && logs.length > 0) {
260
+ try {
261
+ // only check logs that match the criteria signature
262
+ const signatureMatchingLogs = logs
263
+ .filter((log) => log.topics && log.topics[0] === criteria.signature)
264
+ .map((log) => decodeAndReorderLogArgs(eventAbi, log));
265
+
266
+ if (signatureMatchingLogs.length > 0) {
267
+ for (const log of signatureMatchingLogs) {
268
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
269
+ return getScalarValueFromTuple(
270
+ log.args as unknown[],
271
+ criteria.fieldIndex,
272
+ );
273
+ }
274
+ const scalarValue = log.args
275
+ ? (log.args as string[])[criteria.fieldIndex]
276
+ : undefined;
277
+ if (scalarValue !== undefined) {
278
+ return BigInt(scalarValue);
279
+ }
280
+ }
281
+ }
282
+ } catch (e) {
283
+ throw new DecodedArgsError(
284
+ `An error occurred while extracting scalar from logs: ${(e as Error).message}`,
285
+ );
286
+ }
287
+ }
288
+
289
+ const transactionReceipt = await getTransactionReceipt(this._config, {
290
+ chainId,
291
+ hash,
292
+ });
293
+ const receiptLogs = transactionReceipt.logs;
294
+
295
+ if (receiptLogs.length === 0) {
257
296
  throw new NoMatchingLogsError(
258
297
  `No logs found for event signature ${criteria.signature}`,
259
298
  );
@@ -264,7 +303,7 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
264
303
  const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
265
304
  const decodedEvents = parseEventLogs({
266
305
  abi: [eventAbi],
267
- logs,
306
+ logs: receiptLogs,
268
307
  });
269
308
  if (decodedEvents == undefined || decodedEvents.length === 0) {
270
309
  throw new NoMatchingLogsError(
@@ -9,6 +9,7 @@ import {
9
9
  type AbiEvent,
10
10
  type AbiFunction,
11
11
  type Address,
12
+ type GetLogsReturnType,
12
13
  type Hex,
13
14
  decodeAbiParameters,
14
15
  decodeFunctionData,
@@ -22,6 +23,7 @@ import { ERC20VariableCriteriaIncentiveV2 as ERC20VariableCriteriaIncentiveV2Bas
22
23
  import {
23
24
  SignatureType,
24
25
  ValueType,
26
+ decodeAndReorderLogArgs,
25
27
  getScalarValueFromTuple,
26
28
  isCriteriaFieldIndexTuple,
27
29
  } from '../Actions/EventAction';
@@ -115,6 +117,7 @@ export interface GetIncentiveScalarV2Params {
115
117
  chainId: number;
116
118
  hash: Hex;
117
119
  knownSignatures: Record<Hex, AbiFunction | AbiEvent>;
120
+ logs?: GetLogsReturnType<AbiEvent, AbiEvent[], true>;
118
121
  }
119
122
 
120
123
  /**
@@ -247,25 +250,63 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
247
250
  * @throws {InvalidCriteriaTypeError | NoMatchingLogsError | DecodedArgsError}
248
251
  */
249
252
  public async getIncentiveScalar(
250
- { chainId, hash, knownSignatures }: GetIncentiveScalarV2Params,
253
+ { chainId, hash, knownSignatures, logs }: GetIncentiveScalarV2Params,
251
254
  params?: ReadParams,
252
255
  ): Promise<bigint> {
253
256
  const criteria = await this.getIncentiveCriteria(params);
254
257
  if (criteria.criteriaType === SignatureType.EVENT) {
255
- const transactionReceipt = await getTransactionReceipt(this._config, {
256
- chainId,
257
- hash,
258
- });
258
+ const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
259
+
259
260
  if (criteria.fieldIndex === CheatCodes.GAS_REBATE_INCENTIVE) {
261
+ const transactionReceipt = await getTransactionReceipt(this._config, {
262
+ chainId,
263
+ hash,
264
+ });
260
265
  const totalCost =
261
266
  transactionReceipt.gasUsed * transactionReceipt.effectiveGasPrice + // Normal gas cost
262
267
  (transactionReceipt.blobGasUsed ?? 0n) *
263
268
  (transactionReceipt.blobGasPrice ?? 0n); // Blob gas cost - account for potential undefined values
264
269
  return totalCost;
265
270
  }
266
- const logs = transactionReceipt.logs;
267
271
 
268
- if (logs.length === 0) {
272
+ // if logs are provided, use them to extract the scalar
273
+ if (logs && logs.length > 0) {
274
+ try {
275
+ // only check logs that match the criteria signature
276
+ const signatureMatchingLogs = logs
277
+ .filter((log) => log.topics && log.topics[0] === criteria.signature)
278
+ .map((log) => decodeAndReorderLogArgs(eventAbi, log));
279
+
280
+ if (signatureMatchingLogs.length > 0) {
281
+ for (const log of signatureMatchingLogs) {
282
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
283
+ return getScalarValueFromTuple(
284
+ log.args as unknown[],
285
+ criteria.fieldIndex,
286
+ );
287
+ }
288
+ const scalarValue = log.args
289
+ ? (log.args as string[])[criteria.fieldIndex]
290
+ : undefined;
291
+ if (scalarValue !== undefined) {
292
+ return BigInt(scalarValue);
293
+ }
294
+ }
295
+ }
296
+ } catch (e) {
297
+ throw new DecodedArgsError(
298
+ `An error occurred while extracting scalar from logs: ${(e as Error).message}`,
299
+ );
300
+ }
301
+ }
302
+
303
+ const transactionReceipt = await getTransactionReceipt(this._config, {
304
+ chainId,
305
+ hash,
306
+ });
307
+ const receiptLogs = transactionReceipt.logs;
308
+
309
+ if (receiptLogs.length === 0) {
269
310
  throw new NoMatchingLogsError(
270
311
  `No logs found for event signature ${criteria.signature}`,
271
312
  );
@@ -276,7 +317,7 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
276
317
  const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
277
318
  const decodedEvents = parseEventLogs({
278
319
  abi: [eventAbi],
279
- logs,
320
+ logs: receiptLogs,
280
321
  });
281
322
  if (decodedEvents == undefined || decodedEvents.length === 0) {
282
323
  throw new NoMatchingLogsError(