@boostxyz/sdk 7.0.0 → 7.2.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.
Files changed (28) hide show
  1. package/dist/Actions/EventAction.cjs +1 -1
  2. package/dist/Actions/EventAction.cjs.map +1 -1
  3. package/dist/Actions/EventAction.d.ts +46 -0
  4. package/dist/Actions/EventAction.d.ts.map +1 -1
  5. package/dist/Actions/EventAction.js +395 -345
  6. package/dist/Actions/EventAction.js.map +1 -1
  7. package/dist/BoostCore.cjs.map +1 -1
  8. package/dist/BoostCore.d.ts +2 -2
  9. package/dist/BoostCore.d.ts.map +1 -1
  10. package/dist/BoostCore.js.map +1 -1
  11. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentiveV2.cjs +1 -1
  12. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentiveV2.cjs.map +1 -1
  13. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentiveV2.d.ts.map +1 -1
  14. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentiveV2.js +79 -68
  15. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentiveV2.js.map +1 -1
  16. package/dist/Incentives/ERC20VariableCriteriaIncentiveV2.cjs +1 -1
  17. package/dist/Incentives/ERC20VariableCriteriaIncentiveV2.cjs.map +1 -1
  18. package/dist/Incentives/ERC20VariableCriteriaIncentiveV2.d.ts.map +1 -1
  19. package/dist/Incentives/ERC20VariableCriteriaIncentiveV2.js +84 -73
  20. package/dist/Incentives/ERC20VariableCriteriaIncentiveV2.js.map +1 -1
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.js +179 -175
  23. package/package.json +1 -1
  24. package/src/Actions/EventAction.test.ts +90 -0
  25. package/src/Actions/EventAction.ts +119 -2
  26. package/src/BoostCore.ts +1 -1
  27. package/src/Incentives/ERC20PeggedVariableCriteriaIncentiveV2.ts +24 -5
  28. package/src/Incentives/ERC20VariableCriteriaIncentiveV2.ts +25 -5
@@ -41,6 +41,9 @@ import {
41
41
  transactionSenderClaimant,
42
42
  packFieldIndexes,
43
43
  unpackFieldIndexes,
44
+ packCriteriaFieldIndexes,
45
+ unpackCriteriaFieldIndexes,
46
+ isCriteriaFieldIndexTuple,
44
47
  decodeAndReorderLogArgs
45
48
  } from "./EventAction";
46
49
  import { allKnownSignatures } from "@boostxyz/test/allKnownSignatures";
@@ -1512,3 +1515,90 @@ describe('decodeAndReorderLogArgs', () => {
1512
1515
  expect(result.args[3]).toBe(5284n);
1513
1516
  });
1514
1517
  });
1518
+
1519
+ describe("criteria field index tuple support", () => {
1520
+ describe("packCriteriaFieldIndexes", () => {
1521
+ test("packs two indices into a single value", () => {
1522
+ const packed = packCriteriaFieldIndexes([3, 5])
1523
+ expect(packed).toBeGreaterThanOrEqual(32);
1524
+ expect(packed).toBeLessThanOrEqual(253);
1525
+ });
1526
+
1527
+ test("throws error if any index exceeds the allowed range (0-13)", () => {
1528
+ expect(() => packCriteriaFieldIndexes([14, 5])).toThrowError(
1529
+ "Tuple indices must be between 0-13"
1530
+ );
1531
+
1532
+ expect(() => packCriteriaFieldIndexes([5, 14])).toThrowError(
1533
+ "Tuple indices must be between 0-13"
1534
+ );
1535
+
1536
+ expect(() => packCriteriaFieldIndexes([-1, 5])).toThrowError(
1537
+ "Tuple indices must be between 0-13"
1538
+ );
1539
+ });
1540
+
1541
+ test("different input pairs result in different packed values", () => {
1542
+ const packed1 = packCriteriaFieldIndexes([1, 2]);
1543
+ const packed2 = packCriteriaFieldIndexes([2, 1]);
1544
+ const packed3 = packCriteriaFieldIndexes([1, 3]);
1545
+
1546
+ expect(packed1).not.toBe(packed2);
1547
+ expect(packed1).not.toBe(packed3);
1548
+ expect(packed2).not.toBe(packed3);
1549
+ });
1550
+ });
1551
+
1552
+ describe("unpackCriteriaFieldIndexes", () => {
1553
+ test("unpacks tuple index values (>= 32) correctly", () => {
1554
+ const packed = packCriteriaFieldIndexes([4, 7]);
1555
+
1556
+ const result = unpackCriteriaFieldIndexes(packed);
1557
+ expect(result.length).toBe(2);
1558
+ expect(result).toEqual([4, 7]);
1559
+ });
1560
+
1561
+ test("throws error if packed value is out of valid range", () => {
1562
+ expect(() => unpackCriteriaFieldIndexes(15)).toThrowError(
1563
+ "Field index must be between 32-253"
1564
+ );
1565
+
1566
+ expect(() => unpackCriteriaFieldIndexes(254)).toThrowError(
1567
+ "Field index must be between 32-253"
1568
+ );
1569
+
1570
+ expect(() => unpackCriteriaFieldIndexes(-1)).toThrowError(
1571
+ "Field index must be between 32-253"
1572
+ );
1573
+ });
1574
+ });
1575
+
1576
+ describe("isCriteriaFieldIndexTuple", () => {
1577
+ test("correctly identifies tuple indices vs simple indices", () => {
1578
+ // Test with simple index (< 32)
1579
+ expect(isCriteriaFieldIndexTuple(15)).toBe(false);
1580
+
1581
+ // Test with tuple index (>= 32)
1582
+ const packed = packCriteriaFieldIndexes([2, 3]);
1583
+ expect(isCriteriaFieldIndexTuple(packed)).toBe(true);
1584
+
1585
+ // Test edge cases
1586
+ expect(isCriteriaFieldIndexTuple(0)).toBe(false);
1587
+ expect(isCriteriaFieldIndexTuple(31)).toBe(false);
1588
+ expect(isCriteriaFieldIndexTuple(32)).toBe(true);
1589
+ });
1590
+ });
1591
+
1592
+ describe("criteria field index functions in practice", () => {
1593
+ test("round-trip packing and unpacking preserves the original values", () => {
1594
+ for (let i = 0; i <= 13; i++) {
1595
+ for (let j = 0; j <= 13; j++) {
1596
+ const original: [number, number] = [i, j];
1597
+ const packed = packCriteriaFieldIndexes(original);
1598
+ const unpacked = unpackCriteriaFieldIndexes(packed);
1599
+ expect(unpacked).toEqual(original);
1600
+ }
1601
+ }
1602
+ });
1603
+ });
1604
+ });
@@ -584,7 +584,7 @@ export class EventAction extends DeployableTarget<
584
584
  claimant,
585
585
  log,
586
586
  );
587
- if (addressCandidate) address = addressCandidate;
587
+ if (addressCandidate) return addressCandidate;
588
588
  }
589
589
  return address;
590
590
  }
@@ -611,7 +611,7 @@ export class EventAction extends DeployableTarget<
611
611
  for (let log of decodedLogs) {
612
612
  if (!isAddressEqual(log.address, claimant.targetContract)) continue;
613
613
  let addressCandidate = this.validateClaimantAgainstArgs(claimant, log);
614
- if (addressCandidate) address = addressCandidate;
614
+ if (addressCandidate) return addressCandidate;
615
615
  }
616
616
  return address;
617
617
  }
@@ -1781,3 +1781,120 @@ export function decodeAndReorderLogArgs(event: AbiEvent, log: Log) {
1781
1781
  args: reorderedArgs,
1782
1782
  } as EventLog;
1783
1783
  }
1784
+
1785
+ /**
1786
+ * IMPORTANT: For variable incentive criteria use only.
1787
+ * Do NOT use for action steps - use {@link packFieldIndexes} instead.
1788
+ *
1789
+ * Packs two field indices into a single uint8 value for criteria tuple access.
1790
+ * Both indices must be between 0-13 to fit in the packed format.
1791
+ *
1792
+ * Uses an offset of 32 to avoid collision with normal field indices (which are 0-31),
1793
+ * allowing the system to distinguish between direct field access and tuple access.
1794
+ *
1795
+ * @export
1796
+ * @param {[number, number]} param0 - A tuple of [firstIndex, secondIndex]
1797
+ * @returns {number} - Packed uint8 value with base offset of 32
1798
+ * @throws {InvalidTupleEncodingError} - If either index is outside the valid range (0-13)
1799
+ */
1800
+ export function packCriteriaFieldIndexes([firstIndex, secondIndex]: [
1801
+ number,
1802
+ number,
1803
+ ]): number {
1804
+ if (
1805
+ firstIndex < 0 ||
1806
+ firstIndex > 13 ||
1807
+ secondIndex < 0 ||
1808
+ secondIndex > 13
1809
+ ) {
1810
+ throw new InvalidTupleEncodingError(
1811
+ `Tuple indices must be between 0-13, got: [${firstIndex}, ${secondIndex}]`,
1812
+ );
1813
+ }
1814
+ return 32 + (firstIndex << 4) + secondIndex;
1815
+ }
1816
+
1817
+ /**
1818
+ * Unpacks a uint8 packed index value into an array of indices.
1819
+ *
1820
+ * @export
1821
+ * @param {number} packed - Packed index value
1822
+ * @returns {[number, number]} - [firstIndex, secondIndex]
1823
+ */
1824
+ export function unpackCriteriaFieldIndexes(packed: number): [number, number] {
1825
+ if (packed < 32 || packed > 253) {
1826
+ throw new InvalidTupleEncodingError(
1827
+ `Field index must be between 32-253, got: ${packed}`,
1828
+ );
1829
+ }
1830
+
1831
+ const tupleValue = packed - 32;
1832
+ const firstIndex = (tupleValue >> 4) & 0xf;
1833
+ const secondIndex = tupleValue & 0xf;
1834
+ return [firstIndex, secondIndex];
1835
+ }
1836
+
1837
+ /**
1838
+ * Determines if a fieldIndex represents a tuple index (value >= 32) or a normal field index.
1839
+ *
1840
+ * @export
1841
+ * @param {number} fieldIndex - The field index to check
1842
+ * @returns {boolean} - True if it's a tuple index, false if it's a normal field index
1843
+ */
1844
+ export function isCriteriaFieldIndexTuple(fieldIndex: number): boolean {
1845
+ return fieldIndex >= 32;
1846
+ }
1847
+
1848
+ /**
1849
+ * Extracts a scalar value from a tuple within event or function arguments.
1850
+ * This is used for incentive criteria when determining reward amounts.
1851
+ *
1852
+ * @export
1853
+ * @param {unknown[]} args - The decoded arguments from an event or function call
1854
+ * @param {number} fieldIndex - The tuple-encoded index
1855
+ * @returns {bigint} The extracted scalar value as a bigint
1856
+ * @throws {DecodedArgsError} If arguments are missing or cannot be converted to bigint
1857
+ */
1858
+ export function getScalarValueFromTuple(
1859
+ args: unknown[],
1860
+ fieldIndex: number,
1861
+ ): bigint {
1862
+ if (!isCriteriaFieldIndexTuple(fieldIndex)) {
1863
+ throw new DecodedArgsError(
1864
+ `Field index ${fieldIndex} is invalid. Expected index >= 32`,
1865
+ );
1866
+ }
1867
+
1868
+ const [index0, index1] = unpackCriteriaFieldIndexes(fieldIndex);
1869
+
1870
+ if (index0 === undefined || index1 === undefined) {
1871
+ throw new DecodedArgsError(
1872
+ `Failed to unpack field indexes from ${fieldIndex}`,
1873
+ );
1874
+ }
1875
+
1876
+ if (!args || args.length <= index0) {
1877
+ throw new DecodedArgsError(`Decoded args missing item at index ${index0}`);
1878
+ }
1879
+
1880
+ const tuple = args[index0];
1881
+ if (!tuple || !Array.isArray(tuple)) {
1882
+ throw new DecodedArgsError(
1883
+ `Expected array at index ${index0}, but got ${typeof tuple}`,
1884
+ );
1885
+ }
1886
+ if (tuple.length <= index1) {
1887
+ throw new DecodedArgsError(
1888
+ `index ${index1} is out of bounds. tuple length is ${tuple.length}`,
1889
+ );
1890
+ }
1891
+
1892
+ const scalarValue = tuple[index1] as unknown;
1893
+ if (typeof scalarValue !== 'bigint') {
1894
+ throw new DecodedArgsError(
1895
+ `Expected bigint at tuple index ${index1}, but got ${typeof scalarValue}`,
1896
+ );
1897
+ }
1898
+
1899
+ return scalarValue;
1900
+ }
package/src/BoostCore.ts CHANGED
@@ -865,7 +865,7 @@ export class BoostCore extends Deployable<
865
865
  }
866
866
 
867
867
  // This function mutates payload, which isn't awesome but it's fine
868
- private async prepareCreateBoostPayload(
868
+ public async prepareCreateBoostPayload(
869
869
  coreAddress: Address,
870
870
  chainId: number,
871
871
  payload: CreateBoostPayload,
@@ -35,7 +35,11 @@ import {
35
35
  zeroHash,
36
36
  } from 'viem';
37
37
  import { ERC20PeggedVariableCriteriaIncentiveV2 as ERC20PeggedVariableCriteriaIncentiveV2Bases } from '../../dist/deployments.json';
38
- import { SignatureType } from '../Actions/EventAction';
38
+ import {
39
+ SignatureType,
40
+ getScalarValueFromTuple,
41
+ isCriteriaFieldIndexTuple,
42
+ } from '../Actions/EventAction';
39
43
  import type {
40
44
  DeployableOptions,
41
45
  GenericDeployableParams,
@@ -257,7 +261,6 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
257
261
 
258
262
  // Decode the event log
259
263
  try {
260
- // Decode function data
261
264
  const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
262
265
  const decodedEvents = parseEventLogs({
263
266
  abi: [eventAbi],
@@ -268,10 +271,18 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
268
271
  `No logs found for event signature ${criteria.signature}`,
269
272
  );
270
273
  }
271
- const scalarValue = (decodedEvents[0]?.args as string[])[
272
- criteria.fieldIndex
273
- ];
274
274
 
275
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
276
+ return getScalarValueFromTuple(
277
+ decodedEvents[0]?.args as unknown[],
278
+ criteria.fieldIndex,
279
+ );
280
+ }
281
+
282
+ const scalarValue =
283
+ decodedEvents[0] && decodedEvents[0].args
284
+ ? (decodedEvents[0].args as string[])[criteria.fieldIndex]
285
+ : undefined;
275
286
  if (scalarValue === undefined) {
276
287
  throw new DecodedArgsError(
277
288
  `Decoded argument at index ${criteria.fieldIndex} is undefined`,
@@ -296,6 +307,14 @@ export class ERC20PeggedVariableCriteriaIncentiveV2 extends DeployableTarget<
296
307
  abi: [func],
297
308
  data: transaction.input,
298
309
  });
310
+
311
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
312
+ return getScalarValueFromTuple(
313
+ decodedFunction.args as unknown[],
314
+ criteria.fieldIndex,
315
+ );
316
+ }
317
+
299
318
  const scalarValue = decodedFunction.args[criteria.fieldIndex] as string;
300
319
  if (scalarValue === undefined || scalarValue === null) {
301
320
  throw new DecodedArgsError(
@@ -19,7 +19,12 @@ import {
19
19
  zeroHash,
20
20
  } from 'viem';
21
21
  import { ERC20VariableCriteriaIncentiveV2 as ERC20VariableCriteriaIncentiveV2Bases } from '../../dist/deployments.json';
22
- import { SignatureType, ValueType } from '../Actions/EventAction';
22
+ import {
23
+ SignatureType,
24
+ ValueType,
25
+ getScalarValueFromTuple,
26
+ isCriteriaFieldIndexTuple,
27
+ } from '../Actions/EventAction';
23
28
  import type {
24
29
  DeployableOptions,
25
30
  GenericDeployableParams,
@@ -268,7 +273,6 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
268
273
 
269
274
  // Decode the event log
270
275
  try {
271
- // Decode function data
272
276
  const eventAbi = knownSignatures[criteria.signature] as AbiEvent;
273
277
  const decodedEvents = parseEventLogs({
274
278
  abi: [eventAbi],
@@ -279,10 +283,18 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
279
283
  `No logs found for event signature ${criteria.signature}`,
280
284
  );
281
285
  }
282
- const scalarValue = (decodedEvents[0]?.args as string[])[
283
- criteria.fieldIndex
284
- ];
285
286
 
287
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
288
+ return getScalarValueFromTuple(
289
+ decodedEvents[0]?.args as unknown[],
290
+ criteria.fieldIndex,
291
+ );
292
+ }
293
+
294
+ const scalarValue =
295
+ decodedEvents[0] && decodedEvents[0].args
296
+ ? (decodedEvents[0].args as string[])[criteria.fieldIndex]
297
+ : undefined;
286
298
  if (scalarValue === undefined) {
287
299
  throw new DecodedArgsError(
288
300
  `Decoded argument at index ${criteria.fieldIndex} is undefined`,
@@ -307,6 +319,14 @@ export class ERC20VariableCriteriaIncentiveV2 extends ERC20VariableIncentive<
307
319
  abi: [func],
308
320
  data: transaction.input,
309
321
  });
322
+
323
+ if (isCriteriaFieldIndexTuple(criteria.fieldIndex)) {
324
+ return getScalarValueFromTuple(
325
+ decodedFunction.args as unknown[],
326
+ criteria.fieldIndex,
327
+ );
328
+ }
329
+
310
330
  const scalarValue = decodedFunction.args[criteria.fieldIndex] as string;
311
331
  if (scalarValue === undefined || scalarValue === null) {
312
332
  throw new DecodedArgsError(