@boostxyz/sdk 5.3.0 → 5.5.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.
- package/dist/Actions/EventAction.cjs +1 -1
- package/dist/Actions/EventAction.cjs.map +1 -1
- package/dist/Actions/EventAction.d.ts +13 -5
- package/dist/Actions/EventAction.d.ts.map +1 -1
- package/dist/Actions/EventAction.js +1745 -379
- package/dist/Actions/EventAction.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +154 -153
- package/package.json +1 -1
- package/src/Actions/EventAction.test.ts +9 -0
- package/src/Actions/EventAction.ts +117 -70
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
writeEventActionExecute,
|
|
7
7
|
} from '@boostxyz/evm';
|
|
8
8
|
import { bytecode } from '@boostxyz/evm/artifacts/contracts/actions/EventAction.sol/EventAction.json';
|
|
9
|
+
import { abi } from '@boostxyz/signatures/events';
|
|
9
10
|
import { getTransaction, getTransactionReceipt } from '@wagmi/core';
|
|
10
|
-
import type { AbiEventParameter } from 'abitype';
|
|
11
11
|
import { match } from 'ts-pattern';
|
|
12
12
|
import {
|
|
13
13
|
type AbiEvent,
|
|
@@ -26,7 +26,9 @@ import {
|
|
|
26
26
|
fromHex,
|
|
27
27
|
isAddress,
|
|
28
28
|
isAddressEqual,
|
|
29
|
+
pad,
|
|
29
30
|
toEventSelector,
|
|
31
|
+
trim,
|
|
30
32
|
zeroAddress,
|
|
31
33
|
zeroHash,
|
|
32
34
|
} from 'viem';
|
|
@@ -157,7 +159,7 @@ export interface ActionClaimant {
|
|
|
157
159
|
*
|
|
158
160
|
* @type {SignatureType}
|
|
159
161
|
*/
|
|
160
|
-
signatureType
|
|
162
|
+
signatureType?: SignatureType;
|
|
161
163
|
/**
|
|
162
164
|
* The 4 byte signature of the event or function
|
|
163
165
|
*
|
|
@@ -202,7 +204,7 @@ export interface ActionStep {
|
|
|
202
204
|
*
|
|
203
205
|
* @type {SignatureType}
|
|
204
206
|
*/
|
|
205
|
-
signatureType
|
|
207
|
+
signatureType?: SignatureType;
|
|
206
208
|
/**
|
|
207
209
|
* The type of action being performed.
|
|
208
210
|
*
|
|
@@ -585,9 +587,15 @@ export class EventAction extends DeployableTarget<
|
|
|
585
587
|
) {
|
|
586
588
|
return undefined;
|
|
587
589
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
590
|
+
|
|
591
|
+
let decodedLogs: EventLogs;
|
|
592
|
+
if (signature === TRANSFER_SIGNATURE) {
|
|
593
|
+
({ decodedLogs } = await this.decodeTransferLogs(receipt));
|
|
594
|
+
} else {
|
|
595
|
+
decodedLogs = receipt.logs
|
|
596
|
+
.filter((log) => log.topics[0] === toEventSelector(event))
|
|
597
|
+
.map((log) => decodeAndReorderLogArgs(event, log));
|
|
598
|
+
}
|
|
591
599
|
|
|
592
600
|
for (let log of decodedLogs) {
|
|
593
601
|
if (!isAddressEqual(log.address, claimant.targetContract)) continue;
|
|
@@ -728,7 +736,8 @@ export class EventAction extends DeployableTarget<
|
|
|
728
736
|
|
|
729
737
|
// Special handling for Transfer events
|
|
730
738
|
if (actionStep.signature === TRANSFER_SIGNATURE) {
|
|
731
|
-
|
|
739
|
+
const { decodedLogs, event } = await this.decodeTransferLogs(receipt);
|
|
740
|
+
return this.isActionEventValid(actionStep, decodedLogs, event);
|
|
732
741
|
}
|
|
733
742
|
|
|
734
743
|
const decodedLogs = receipt.logs
|
|
@@ -801,7 +810,7 @@ export class EventAction extends DeployableTarget<
|
|
|
801
810
|
}
|
|
802
811
|
|
|
803
812
|
/**
|
|
804
|
-
* Decodes
|
|
813
|
+
* Decodes logs specifically for ERC721 and ERC20 Transfer events.
|
|
805
814
|
*
|
|
806
815
|
* This special handling is required because both ERC20 and ERC721 Transfer events:
|
|
807
816
|
* 1. Share the same event signature (0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef)
|
|
@@ -813,79 +822,51 @@ export class EventAction extends DeployableTarget<
|
|
|
813
822
|
* try decoding both ways to determine which type of Transfer event we're dealing with.
|
|
814
823
|
*
|
|
815
824
|
* @param {GetTransactionReceiptReturnType} receipt - The transaction receipt containing the logs
|
|
816
|
-
* @
|
|
817
|
-
* @returns {Promise<boolean>} - Returns true if the transfer logs are valid for either ERC20 or ERC721
|
|
825
|
+
* @returns {Promise<{ decodedLogs: EventLogs; event: AbiEvent }>} - Returns the decoded logs and the transfer event ABI used for decoding
|
|
818
826
|
* @throws {DecodedArgsError} - Throws if neither ERC20 nor ERC721 decoding succeeds
|
|
819
827
|
*/
|
|
820
828
|
private async decodeTransferLogs(
|
|
821
829
|
receipt: GetTransactionReceiptReturnType,
|
|
822
|
-
|
|
823
|
-
) {
|
|
830
|
+
): Promise<{ decodedLogs: EventLogs; event: AbiEvent }> {
|
|
824
831
|
const filteredLogs = receipt.logs.filter(
|
|
825
832
|
(log) => log.topics[0] === TRANSFER_SIGNATURE,
|
|
826
833
|
);
|
|
834
|
+
const event = structuredClone(
|
|
835
|
+
abi['Transfer(address indexed,address indexed,uint256 indexed)'],
|
|
836
|
+
) as AbiEvent;
|
|
827
837
|
|
|
828
838
|
// ERC721
|
|
829
839
|
try {
|
|
830
840
|
const decodedLogs = filteredLogs.map((log) => {
|
|
831
841
|
const { eventName, args } = decodeEventLog({
|
|
832
|
-
abi: [
|
|
833
|
-
{
|
|
834
|
-
name: 'Transfer',
|
|
835
|
-
type: 'event',
|
|
836
|
-
inputs: [
|
|
837
|
-
{ type: 'address', indexed: true },
|
|
838
|
-
{ type: 'address', indexed: true },
|
|
839
|
-
{ type: 'uint256', indexed: true },
|
|
840
|
-
],
|
|
841
|
-
},
|
|
842
|
-
],
|
|
842
|
+
abi: [event],
|
|
843
843
|
data: log.data,
|
|
844
844
|
topics: log.topics,
|
|
845
845
|
});
|
|
846
846
|
return { ...log, eventName, args };
|
|
847
847
|
});
|
|
848
848
|
|
|
849
|
-
return
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
{ type: 'address', indexed: true },
|
|
854
|
-
{ type: 'address', indexed: true },
|
|
855
|
-
{ type: 'uint256', indexed: true },
|
|
856
|
-
],
|
|
857
|
-
});
|
|
849
|
+
return {
|
|
850
|
+
decodedLogs,
|
|
851
|
+
event,
|
|
852
|
+
};
|
|
858
853
|
} catch {
|
|
859
854
|
// ERC20
|
|
860
855
|
try {
|
|
856
|
+
event.inputs[2]!.indexed = false;
|
|
861
857
|
const decodedLogs = filteredLogs.map((log) => {
|
|
862
858
|
const { eventName, args } = decodeEventLog({
|
|
863
|
-
abi: [
|
|
864
|
-
{
|
|
865
|
-
name: 'Transfer',
|
|
866
|
-
type: 'event',
|
|
867
|
-
inputs: [
|
|
868
|
-
{ type: 'address', indexed: true },
|
|
869
|
-
{ type: 'address', indexed: true },
|
|
870
|
-
{ type: 'uint256' },
|
|
871
|
-
],
|
|
872
|
-
},
|
|
873
|
-
],
|
|
859
|
+
abi: [event],
|
|
874
860
|
data: log.data,
|
|
875
861
|
topics: log.topics,
|
|
876
862
|
});
|
|
877
863
|
return { ...log, eventName, args };
|
|
878
864
|
});
|
|
879
865
|
|
|
880
|
-
return
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
{ type: 'address', indexed: true },
|
|
885
|
-
{ type: 'address', indexed: true },
|
|
886
|
-
{ type: 'uint256' },
|
|
887
|
-
],
|
|
888
|
-
});
|
|
866
|
+
return {
|
|
867
|
+
decodedLogs,
|
|
868
|
+
event,
|
|
869
|
+
};
|
|
889
870
|
} catch {
|
|
890
871
|
throw new DecodedArgsError('Failed to decode transfer logs');
|
|
891
872
|
}
|
|
@@ -1398,6 +1379,72 @@ function _isEventActionPayloadSimple(
|
|
|
1398
1379
|
return Array.isArray((opts as EventActionPayloadSimple).actionSteps);
|
|
1399
1380
|
}
|
|
1400
1381
|
|
|
1382
|
+
/**
|
|
1383
|
+
* Determines whether a signature is an event or function signature based on its format.
|
|
1384
|
+
* - 32-byte signatures (0x + 64 chars) that don't start with 28 zeros are event signatures
|
|
1385
|
+
* - 4-byte signatures (0x + 8 chars) or 32-byte signatures with 28 leading zeros are function signatures
|
|
1386
|
+
*
|
|
1387
|
+
* @param {Hex} signature - The signature to check
|
|
1388
|
+
* @returns {SignatureType} The detected signature type
|
|
1389
|
+
*/
|
|
1390
|
+
export function detectSignatureType(signature: Hex): SignatureType {
|
|
1391
|
+
const hexWithoutPrefix = signature.slice(2);
|
|
1392
|
+
|
|
1393
|
+
// 4-byte function selectors (8 hex chars)
|
|
1394
|
+
if (hexWithoutPrefix.length === 8) {
|
|
1395
|
+
return SignatureType.FUNC;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
// 32-byte selectors (64 hex chars)
|
|
1399
|
+
if (hexWithoutPrefix.length === 64) {
|
|
1400
|
+
// Check if it starts with 28 bytes (56 chars) of zeros
|
|
1401
|
+
const leadingPart = hexWithoutPrefix.slice(0, 56);
|
|
1402
|
+
if (leadingPart === '0'.repeat(56)) {
|
|
1403
|
+
return SignatureType.FUNC;
|
|
1404
|
+
}
|
|
1405
|
+
return SignatureType.EVENT;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
throw new Error('Invalid signature format');
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Normalizes a hex value to ensure proper byte padding.
|
|
1413
|
+
* This prevents viem's automatic padding which can change the value.
|
|
1414
|
+
* For example:
|
|
1415
|
+
* - "0x1" -> "0x01"
|
|
1416
|
+
* - "0xabc" -> "0x0abc"
|
|
1417
|
+
* - "0xabcd" -> "0xabcd"
|
|
1418
|
+
*
|
|
1419
|
+
* @param {Hex} value - The hex value to normalize
|
|
1420
|
+
* @returns {Hex} The normalized hex string
|
|
1421
|
+
*/
|
|
1422
|
+
function normalizeUintValue(value: Hex): Hex {
|
|
1423
|
+
return trim(pad(value));
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
/**
|
|
1427
|
+
* Helper function to prepare an action step for encoding
|
|
1428
|
+
*
|
|
1429
|
+
* @param {ActionStep} step - The action step to prepare
|
|
1430
|
+
* @returns {ActionStep} The prepared action step
|
|
1431
|
+
*/
|
|
1432
|
+
function prepareActionStep(step: ActionStep) {
|
|
1433
|
+
return {
|
|
1434
|
+
..._toRawActionStep(step),
|
|
1435
|
+
signatureType: step.signatureType ?? detectSignatureType(step.signature),
|
|
1436
|
+
signature: pad(step.signature),
|
|
1437
|
+
actionType: step.actionType || 0,
|
|
1438
|
+
actionParameter:
|
|
1439
|
+
step.actionParameter.fieldType === PrimitiveType.UINT
|
|
1440
|
+
? {
|
|
1441
|
+
...step.actionParameter,
|
|
1442
|
+
filterData: normalizeUintValue(step.actionParameter.filterData),
|
|
1443
|
+
}
|
|
1444
|
+
: step.actionParameter,
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1401
1448
|
/**
|
|
1402
1449
|
* Function to properly encode an event action payload.
|
|
1403
1450
|
*
|
|
@@ -1523,23 +1570,17 @@ export function prepareEventActionPayload({
|
|
|
1523
1570
|
],
|
|
1524
1571
|
[
|
|
1525
1572
|
{
|
|
1526
|
-
actionClaimant:
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
..._toRawActionStep(actionStepTwo),
|
|
1533
|
-
actionType: actionStepTwo.actionType || 0,
|
|
1534
|
-
},
|
|
1535
|
-
actionStepThree: {
|
|
1536
|
-
..._toRawActionStep(actionStepThree),
|
|
1537
|
-
actionType: actionStepThree.actionType || 0,
|
|
1538
|
-
},
|
|
1539
|
-
actionStepFour: {
|
|
1540
|
-
..._toRawActionStep(actionStepFour),
|
|
1541
|
-
actionType: actionStepFour.actionType || 0,
|
|
1573
|
+
actionClaimant: {
|
|
1574
|
+
..._toRawActionStep(actionClaimant),
|
|
1575
|
+
signatureType:
|
|
1576
|
+
actionClaimant.signatureType ??
|
|
1577
|
+
detectSignatureType(actionClaimant.signature),
|
|
1578
|
+
signature: pad(actionClaimant.signature),
|
|
1542
1579
|
},
|
|
1580
|
+
actionStepOne: prepareActionStep(actionStepOne),
|
|
1581
|
+
actionStepTwo: prepareActionStep(actionStepTwo),
|
|
1582
|
+
actionStepThree: prepareActionStep(actionStepThree),
|
|
1583
|
+
actionStepFour: prepareActionStep(actionStepFour),
|
|
1543
1584
|
},
|
|
1544
1585
|
],
|
|
1545
1586
|
);
|
|
@@ -1632,6 +1673,9 @@ export function packFieldIndexes(indexes: number[]): number {
|
|
|
1632
1673
|
}
|
|
1633
1674
|
packed |= (index & MAX_FIELD_INDEX) << (i * 6); // Each index occupies 6 bits
|
|
1634
1675
|
});
|
|
1676
|
+
if (indexes.length < 5) {
|
|
1677
|
+
packed |= MAX_FIELD_INDEX << (indexes.length * 6); // Terminator
|
|
1678
|
+
}
|
|
1635
1679
|
|
|
1636
1680
|
return packed;
|
|
1637
1681
|
}
|
|
@@ -1672,7 +1716,10 @@ export function decodeAndReorderLogArgs(event: AbiEvent, log: Log) {
|
|
|
1672
1716
|
: Object.values(decodedLog.args);
|
|
1673
1717
|
|
|
1674
1718
|
if (!event.inputs.some((input) => input.indexed)) {
|
|
1675
|
-
return
|
|
1719
|
+
return {
|
|
1720
|
+
...log,
|
|
1721
|
+
...decodedLog,
|
|
1722
|
+
} as EventLog;
|
|
1676
1723
|
}
|
|
1677
1724
|
|
|
1678
1725
|
const indexedIndices: number[] = [];
|
|
@@ -1685,7 +1732,7 @@ export function decodeAndReorderLogArgs(event: AbiEvent, log: Log) {
|
|
|
1685
1732
|
}
|
|
1686
1733
|
}
|
|
1687
1734
|
|
|
1688
|
-
const reorderedArgs =
|
|
1735
|
+
const reorderedArgs = Array.from({ length: event.inputs.length });
|
|
1689
1736
|
let currentIndex = 0;
|
|
1690
1737
|
|
|
1691
1738
|
// Place the indexed arguments in their original positions
|