-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhooks.ts
129 lines (107 loc) · 5.12 KB
/
hooks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//
// Copyright 2023 Vulcanize, Inc.
//
import assert from 'assert';
import { utils } from 'ethers';
import { ResultEvent } from '@cerc-io/util';
import { Indexer, KIND_PHISHERREGISTRY } from './indexer';
const INVOKE_SIGNATURE = 'invoke(((((address,uint256,bytes),((address,bytes32,(address,bytes)[]),bytes)[])[],(uint256,uint256)),bytes)[])';
const CLAIM_IF_MEMBER_SIGNATURE = 'claimIfMember(string,bool)';
const CLAIM_IF_PHISHER_SIGNATURE = 'claimIfPhisher(string,bool)';
/**
* Hook function to store an initial state.
* @param indexer Indexer instance.
* @param blockHash Hash of the concerned block.
* @param contractAddress Address of the concerned contract.
* @returns Data block to be stored.
*/
export async function createInitialState (indexer: Indexer, contractAddress: string, blockHash: string): Promise<any> {
assert(indexer);
assert(blockHash);
assert(contractAddress);
// Store an empty State.
const stateData: any = {
state: {}
};
// Use updateStateForElementaryType to update initial state with an elementary property.
// Eg. const stateData = updateStateForElementaryType(stateData, '_totalBalance', result.value.toString());
// Use updateStateForMappingType to update initial state with a nested property.
// Eg. const stateData = updateStateForMappingType(stateData, '_allowances', [owner, spender], allowance.value.toString());
// Return initial state data to be saved.
return stateData;
}
/**
* Hook function to create state diff.
* @param indexer Indexer instance that contains methods to fetch the contract varaiable values.
* @param blockHash Block hash of the concerned block.
*/
export async function createStateDiff (indexer: Indexer, blockHash: string): Promise<void> {
assert(indexer);
assert(blockHash);
// Use indexer.createDiff() method to save custom state diff(s).
}
/**
* Hook function to create state checkpoint
* @param indexer Indexer instance.
* @param contractAddress Address of the concerned contract.
* @param blockHash Block hash of the concerned block.
* @returns Whether to disable default checkpoint. If false, the state from this hook is updated with that from default checkpoint.
*/
export async function createStateCheckpoint (indexer: Indexer, contractAddress: string, blockHash: string): Promise<boolean> {
assert(indexer);
assert(blockHash);
assert(contractAddress);
// Use indexer.createStateCheckpoint() method to create a custom checkpoint.
// Return false to update the state created by this hook by auto-generated checkpoint state.
// Return true to disable update of the state created by this hook by auto-generated checkpoint state.
return false;
}
/**
* Event hook function.
* @param indexer Indexer instance that contains methods to fetch and update the contract values in the database.
* @param eventData ResultEvent object containing event information.
*/
export async function handleEvent (indexer: Indexer, eventData: ResultEvent): Promise<void> {
assert(indexer);
assert(eventData);
// Perform indexing for PhisherStatusUpdated and MemberStatusUpdated.
if (['PhisherStatusUpdatedEvent', 'MemberStatusUpdatedEvent'].includes(eventData.event.__typename)) {
const txData = await indexer.getFullTransaction(eventData.tx.hash, eventData.block.number);
const txDescription = getTxDescription(indexer, KIND_PHISHERREGISTRY, txData.input);
let txDescriptions = [txDescription];
if (txDescription.signature === INVOKE_SIGNATURE) {
// Parse transactions from batches if it is an invoke method in Delegatable contract.
txDescriptions = txDescription.args.signedInvocations
.reduce((txs: utils.TransactionDescription[], signedInvocation: any) => {
// Get transactions from signed invocations batch.
const batchTxs = signedInvocation.invocations.batch.map((invocation: any) => {
return getTxDescription(indexer, KIND_PHISHERREGISTRY, invocation.transaction.data);
});
txs.push(...batchTxs);
return txs;
}, []);
}
// Filter transactions for claimIfMember and claimIsPhisher methods.
txDescriptions = txDescriptions.filter((tx: utils.TransactionDescription) => {
return [CLAIM_IF_MEMBER_SIGNATURE, CLAIM_IF_PHISHER_SIGNATURE].includes(tx.signature);
});
for (const txDescription of txDescriptions) {
switch (txDescription.signature) {
case CLAIM_IF_MEMBER_SIGNATURE:
// Update isMember entry for the identifier in database.
await indexer.isMember(eventData.block.hash, eventData.contract, txDescription.args.identifier, true);
break;
case CLAIM_IF_PHISHER_SIGNATURE:
// Update isPhisher entry for the identifier in database.
await indexer.isPhisher(eventData.block.hash, eventData.contract, txDescription.args.identifier, true);
break;
}
}
}
}
// Get transaction details from input data.
const getTxDescription = (indexer: Indexer, contractKind: string, data: string): utils.TransactionDescription => {
const contractInterface = indexer.getContractInterface(contractKind);
assert(contractInterface);
return contractInterface.parseTransaction({ data });
};