airnode_events/
lib.rs

1mod addresses;
2pub(crate) mod logreader;
3mod requests;
4
5use crate::logreader::{EventParseError, LogReader};
6use airnode_abi::{DecodingError, ABI};
7use ethereum_types::{H160, H256, U256};
8use hex_literal::hex;
9use phf::phf_map;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(tag = "type")]
14pub enum AirnodeEvent {
15    ClientEndorsementStatusUpdatedA {
16        requester_index: U256,
17        client_address: H160,
18        endorsement_status: bool,
19    },
20    ClientFullRequestCreatedA {
21        provider_id: U256,
22        request_id: U256,
23        no_requests: u64,
24        client_address: H160,
25        endpoint_id: U256,
26        requester_index: U256,
27        designated_wallet: H160,
28        fulfill_address: H160,
29        fulfill_function_id: u64,
30        #[serde(skip_serializing_if = "Option::is_none")]
31        parameters: Option<ABI>,
32        #[serde(skip_serializing_if = "Option::is_none")]
33        error: Option<DecodingError>,
34        #[serde(skip_serializing_if = "Option::is_none")]
35        data: Option<Vec<U256>>,
36    },
37    ClientRequestCreatedA {
38        provider_id: U256,
39        request_id: U256,
40        no_requests: u64,
41        client_address: H160,
42        template_id: U256,
43        requester_index: U256,
44        designated_wallet: H160,
45        fulfill_address: H160,
46        fulfill_function_id: u64,
47        #[serde(skip_serializing_if = "Option::is_none")]
48        parameters: Option<ABI>,
49        #[serde(skip_serializing_if = "Option::is_none")]
50        error: Option<DecodingError>,
51        #[serde(skip_serializing_if = "Option::is_none")]
52        data: Option<Vec<U256>>,
53    },
54    ClientRequestFailedA {
55        provider_id: U256,
56        request_id: U256,
57    },
58    ClientRequestFulfilledA {
59        provider_id: U256,
60        request_id: U256,
61        status_code: u64,
62        #[serde(skip_serializing_if = "Option::is_none")]
63        parameters: Option<ABI>,
64        #[serde(skip_serializing_if = "Option::is_none")]
65        error: Option<DecodingError>,
66        #[serde(skip_serializing_if = "Option::is_none")]
67        data: Option<Vec<U256>>,
68    },
69    ClientRequestFulfilledWithBytesA {
70        provider_id: U256,
71        request_id: U256,
72        status_code: u64,
73        #[serde(skip_serializing_if = "Option::is_none")]
74        parameters: Option<ABI>,
75        #[serde(skip_serializing_if = "Option::is_none")]
76        error: Option<DecodingError>,
77        #[serde(skip_serializing_if = "Option::is_none")]
78        data: Option<Vec<U256>>,
79    },
80    ClientShortRequestCreatedA {
81        provider_id: U256,
82        request_id: U256,
83        no_requests: u64,
84        client_address: H160,
85        template_id: U256,
86        #[serde(skip_serializing_if = "Option::is_none")]
87        parameters: Option<ABI>,
88        #[serde(skip_serializing_if = "Option::is_none")]
89        error: Option<DecodingError>,
90        #[serde(skip_serializing_if = "Option::is_none")]
91        data: Option<Vec<U256>>,
92    },
93    EndpointUpdatedA {
94        provider_id: U256,
95        endpoint_id: U256,
96        authorizers: Vec<H160>,
97    },
98    MinBalanceUpdatedA {
99        provider_id: U256,
100        min_balance: U256,
101    },
102    ProviderCreatedA {
103        provider_id: U256,
104        admin: H160,
105        xpub: String,
106    },
107    ProviderUpdatedA {
108        provider_id: U256,
109        admin: H160,
110    },
111    RequesterCreatedA {
112        requester_index: U256,
113        admin: H160,
114    },
115    RequesterUpdatedA {
116        requester_index: U256,
117        admin: H160,
118    },
119    RequestFulfilledA {
120        request_id: U256,
121        status_code: u64,
122        data: U256,
123    },
124    RequestFulfilledWithBytesA {
125        request_id: U256,
126        status_code: u64,
127        #[serde(skip_serializing_if = "Option::is_none")]
128        parameters: Option<ABI>,
129        #[serde(skip_serializing_if = "Option::is_none")]
130        error: Option<DecodingError>,
131        #[serde(skip_serializing_if = "Option::is_none")]
132        data: Option<Vec<U256>>,
133    },
134    TemplateCreatedA {
135        template_id: U256,
136        provider_id: U256,
137        endpoint_id: U256,
138        requester_index: U256,
139        designated_wallet: H160,
140        fulfill_address: H160,
141        fulfill_function_id: u64,
142        #[serde(skip_serializing_if = "Option::is_none")]
143        parameters: Option<ABI>,
144        #[serde(skip_serializing_if = "Option::is_none")]
145        error: Option<DecodingError>,
146        #[serde(skip_serializing_if = "Option::is_none")]
147        data: Option<Vec<U256>>,
148    },
149    WithdrawalFulfilledA {
150        provider_id: U256,
151        requester_index: U256,
152        withdrawal_request_id: U256,
153        designated_wallet: H160,
154        destination: H160,
155        amount: U256,
156    },
157    WithdrawalRequestedA {
158        provider_id: U256,
159        requester_index: U256,
160        withdrawal_request_id: U256,
161        designated_wallet: H160,
162        destination: H160,
163    },
164
165    CreatedTemplate {
166        template_id: U256,
167        airnode: H160,
168        endpoint_id: U256,
169        #[serde(skip_serializing_if = "Option::is_none")]
170        parameters: Option<ABI>,
171        #[serde(skip_serializing_if = "Option::is_none")]
172        error: Option<DecodingError>,
173        #[serde(skip_serializing_if = "Option::is_none")]
174        data: Option<Vec<U256>>,
175    },
176    DecreasedSelfRank {
177        admin: H160,
178        new_rank: U256,
179    },
180    DecreasedSelfRankAdminned {
181        adminned: H160,
182        admin: H160,
183        new_rank: U256,
184    },
185    ErroredBeaconUpdate {
186        template_id: U256,
187        request_id: U256,
188        status_code: u64,
189    },
190    ExtendedWhitelistExpiration {
191        airnode: H160,
192        endpoint_id: U256,
193        user: H160,
194        admin: H160,
195        expiration: u64,
196    },
197    ExtendedWhitelistExpirationTpl {
198        template_id: U256,
199        user: H160,
200        admin: H160,
201        expiration: u64,
202    },
203    FailedRequest {
204        airnode: H160,
205        request_id: U256,
206        error_message: String,
207    },
208    FulfilledRequest {
209        airnode: H160,
210        request_id: U256,
211        #[serde(skip_serializing_if = "Option::is_none")]
212        parameters: Option<ABI>,
213        #[serde(skip_serializing_if = "Option::is_none")]
214        error: Option<DecodingError>,
215        #[serde(skip_serializing_if = "Option::is_none")]
216        data: Option<Vec<U256>>,
217    },
218    FulfilledRequestWithStatus {
219        airnode: H160,
220        request_id: U256,
221        status_code: u64,
222        #[serde(skip_serializing_if = "Option::is_none")]
223        parameters: Option<ABI>,
224        #[serde(skip_serializing_if = "Option::is_none")]
225        error: Option<DecodingError>,
226        #[serde(skip_serializing_if = "Option::is_none")]
227        data: Option<Vec<U256>>,
228    },
229    FulfilledWithdrawal {
230        airnode: H160,
231        sponsor: H160,
232        withdrawal_request_id: U256,
233        sponsor_wallet: H160,
234        amount: U256,
235    },
236    MadeFullRequest {
237        airnode: H160,
238        request_id: U256,
239        requester_request_count: u64,
240        chain_id: u64,
241        requester: H160,
242        endpoint_id: U256,
243        sponsor: H160,
244        sponsor_wallet: H160,
245        fulfill_address: H160,
246        fulfill_function_id: u64,
247        #[serde(skip_serializing_if = "Option::is_none")]
248        parameters: Option<ABI>,
249        #[serde(skip_serializing_if = "Option::is_none")]
250        error: Option<DecodingError>,
251        #[serde(skip_serializing_if = "Option::is_none")]
252        data: Option<Vec<U256>>,
253    },
254    MadeTemplateRequest {
255        airnode: H160,
256        request_id: U256,
257        requester_request_count: u64,
258        chain_id: u64,
259        requester: H160,
260        template_id: U256,
261        sponsor: H160,
262        sponsor_wallet: H160,
263        fulfill_address: H160,
264        fulfill_function_id: u64,
265        #[serde(skip_serializing_if = "Option::is_none")]
266        parameters: Option<ABI>,
267        #[serde(skip_serializing_if = "Option::is_none")]
268        error: Option<DecodingError>,
269        #[serde(skip_serializing_if = "Option::is_none")]
270        data: Option<Vec<U256>>,
271    },
272    RequestedBeaconUpdate {
273        template_id: U256,
274        sponsor: H160,
275        requester: H160,
276        request_id: U256,
277        sponsor_wallet: H160,
278    },
279    RequestedWithdrawal {
280        airnode: H160,
281        sponsor: H160,
282        withdrawal_request_id: U256,
283        sponsor_wallet: H160,
284    },
285    SetAirnodeXpub {
286        airnode: H160,
287        xpub: String,
288    },
289    SetRankAdminned {
290        adminned: H160,
291        caller_admin: H160,
292        target_admin: H160,
293        new_rank: U256,
294    },
295    SetRank {
296        caller_admin: H160,
297        target_admin: H160,
298        new_rank: U256,
299    },
300    SetSponsorshipStatus {
301        sponsor: H160,
302        requester: H160,
303        sponsorship_status: bool,
304    },
305    SetUpdatePermissionStatus {
306        sponsor: H160,
307        update_requester: H160,
308        status: bool,
309    },
310    SetWhitelistExpiration {
311        airnode: H160,
312        endpoint_id: U256,
313        user: H160,
314        admin: H160,
315        expiration: u64,
316    },
317    SetWhitelistExpirationTpl {
318        template_id: U256,
319        user: H160,
320        admin: H160,
321        expiration: u64,
322    },
323    SetWhitelistStatusPastExpiration {
324        airnode: H160,
325        endpoint_id: U256,
326        user: H160,
327        admin: H160,
328        status: bool,
329    },
330    SetWhitelistStatusPastExpirationTpl {
331        template_id: U256,
332        user: H160,
333        admin: H160,
334        status: bool,
335    },
336    TransferredMetaAdminStatus {
337        meta_admin: H160,
338    },
339    UpdatedBeacon {
340        template_id: U256,
341        request_id: U256,
342        value: U256,
343        timestamp: u64,
344    },
345
346    // unknown, but ignored, do not fail on this type
347    Unclassified {
348        topic: H256,
349    },
350    // unknown and fail on that
351    Unknown {
352        topic: H256,
353    },
354}
355
356static KNOWN_EVENTS: phf::Map<&'static str, &'static str> = phf_map! {
357    // Pre-Alpha version
358    "8acbd28af1fec329994543393007c74ebc717caab62689ba09fbf938f015d3fc" => "ClientEndorsementStatusUpdated(uint256,address,bool)",
359    "775e78a8e7375d14ad03d31edd0a27b29a055f732bca987abfe8082c16ed7e44" => "ClientFullRequestCreated(bytes32,bytes32,uint256,address,bytes32,uint256,address,address,bytes4,bytes)",
360    "aff6f5e5548953a11cbb1cfdd76562512f969b0eba0a2163f2420630d4dda97b" => "ClientRequestCreated(bytes32,bytes32,uint256,address,bytes32,uint256,address,address,bytes4,bytes)",
361    "1cfdd5ace64f15111ef8ed9df04364d0e9a9165cccf8386109347e54661ba3ad" => "ClientRequestFailed(bytes32,bytes32)",
362    "1bdbe9e5d42a025a741fc3582eb3cad4ef61ac742d83cc87e545fbd481b926b5" => "ClientRequestFulfilled(bytes32,bytes32,uint256,bytes32)",
363    "0ebeb9b9b5c4baf915e7541c7e0919dd1a58eb06ee596035a50d08d20b9219de" => "ClientRequestFulfilledWithBytes(bytes32,bytes32,uint256,bytes)",
364    "fcbcd5adb2d26ecd4ad50e6267e977fd479fcd0a6c82bde8eea85290ab3b46e6" => "ClientShortRequestCreated(bytes32,bytes32,uint256,address,bytes32,bytes)",
365    "e5687475d94be4622dec0d6fa4db8686e003947facd485b0f4685954b8e93aa8" => "EndpointUpdated(bytes32,bytes32,address[])",
366    "40857340078796a2b6bca551f97b62fffe6ae69e2131195d461862224ee871b6" => "MinBalanceUpdated(bytes32,uint256)",
367    "36ef18ad81b13124b66c80d27059d75bfadf09474c46aee8bb4ae998a921196d" => "ProviderCreated(bytes32,address,string)",
368    "b7de80d002230ae37dd9e25804e78c41517296ad969a962ef5457be94cb8ac6e" => "ProviderUpdated(bytes32,address)",
369    "59e98f4c18a6c92efe8c23bcbd74f0d71e271eebf9a95f9edefdbee17c01f270" => "RequesterCreated(uint256,address)",
370    "de26d3d8fc98a8dab0df21ef2146d313da1a060d635f3ce9b42adab32fa992aa" => "RequesterUpdated(uint256,address)",
371    "2cb6f3105333165ac08235b122e2651dae9c2e70787572aa65bde31fe838d90d" => "RequestFulfilled(bytes32,uint256,bytes32)",
372    "13873a3c5277d69c913bb408d87512468d41afb41113dd46eee917ec4eceb04b" => "RequestFulfilledWithBytes(bytes32,uint256,bytes)",
373    "fa33b8597a1a83305d334562a90f8b4ce657e1b33c081423b6a44792d1cf41a4" => "TemplateCreated(bytes32,bytes32,bytes32,uint256,address,address,bytes4,bytes)",
374    "9e7b58b29aa3b972bb0f457499d0dfd00bf23905b0c3358fb864e7120402aefa" => "WithdrawalFulfilled(bytes32,uint256,bytes32,address,address,uint256)",
375    "3d0ebccb4fc9730699221da0180970852f595ed5c78781346149123cbbe9f1d3" => "WithdrawalRequested(bytes32,uint256,bytes32,address,address)",
376
377    // Beta protocol version
378    "ba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a" => "CreatedTemplate(bytes32,address,bytes32,bytes)",
379    "b4a13e8a5b83b6572fd11170aa28965f4b16ce6ed228501322a428b48e34230c" => "DecreasedSelfRank(address,uint256)",
380    "907b7436750d9bb04b635c837b151be449230b1975dac4ba31b01343b41eb75c" => "DecreasedSelfRank(address,address,uint256)",
381    "df7c6cf6c7d32bf473537bcf24259094d6e7cb863700e071f65a4d8a05b6ce5e" => "ErroredBeaconUpdate(bytes32,bytes32,uint256)",
382    "f9b174be67f83278d4516865d1b9ba4576b73e523ea0c2f124ea29152bb1b676" => "ExtendedWhitelistExpiration(address,bytes32,address,address,uint256)",
383    "a9e0c89b898eb7a904617915dc5b5510d539c899810042e9248569b54b9cc2ed" => "ExtendedWhitelistExpiration(bytes32,address,address,uint256)",
384    "8c087e42b178608800a2ea8b3d009bdbbf75e0d23426510c2edd447d4f8b8ebd" => "FailedRequest(address,bytes32)",
385    "c7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc" => "FailedRequest(address,bytes32,string)",
386    "d1cc11d12363af4b6022e66d14b18ba1779ecd85a5b41891349d530fb6eee066" => "FulfilledRequest(address,bytes32,uint256,bytes)",
387    "c0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a" => "FulfilledRequest(index_topic_1 address airnode, index_topic_2 bytes32 requestId, bytes data)",
388    "adb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e" => "FulfilledWithdrawal(address,address,bytes32,address,uint256)",
389    "3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae" => "MadeFullRequest(address,bytes32,uint256,uint256,address,bytes32,address,address,address,bytes4,bytes)",
390    "eb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c3203" => "MadeTemplateRequest(address,bytes32,uint256,uint256,address,bytes32,address,address,address,bytes4,bytes)",
391    "db6e5ad2f932677d9abcb868239c24d484d5512caf71029b8b7c2309aeee760a" => "RequestedBeaconUpdate(bytes32,address,address,bytes32,address)",
392    "d48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7" => "RequestedWithdrawal(address,address,bytes32,address)",
393    "ebace4380f1ba3ccf701db78879a937b0ad2a9370e98baaba922228f632383e0" => "SetAirnodeXpub(address,string)",
394    "584a7e3e68feb90397faadcb0af28a855e0268ddedf9fce510b4cf57770b9410" => "SetRank(address,address,address,uint256)",
395    "07048cabcdd89c62fecf542621231579eae613db4aeb83794e9c3abf428840ca" => "SetRank(address,address,uint256)",
396    "c2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56" => "SetSponsorshipStatus(address,address,bool)",
397    "5a3b1968640fbb8b12349ea1a58be5c61eaec6e38c11c38652f1d250207103ab" => "SetUpdatePermissionStatus(address,address,bool)",
398    "375ee45428e158031095010484fd6451af89c501c79d75e390da4e91eb480ce1" => "SetWhitelistExpiration(address,bytes32,address,address,uint256)",
399    "d19e89b7d547ccf349211588a9a1d29461e2ce984b1b1cdbe7150976528b86f1" => "SetWhitelistExpiration(bytes32,address,address,uint256)",
400    "0e8af304f7f920661493a5051df03a3947d58b4f655581e51ab0c014d768d8eb" => "SetWhitelistStatusPastExpiration(address,bytes32,address,address,bool)",
401    "527f03e7cb13db04fc83c2332106b6087c66d253bca13289f5d91d8e73796d11" => "SetWhitelistStatusPastExpiration(bytes32,address,address,bool)",
402    "c3dafe3cca75d9d099b1941e05b199870f55b853dd49784a96359ac26f01bf6d" => "TransferredMetaAdminStatus(address)",
403    "cb9c65e5f99c20826a331174f56e8c536161ecb0b5d598267e79c83567d477f1" => "UpdatedBeacon(bytes32,bytes32,int224,uint32)",
404
405    // Topics from other versions/branches (probably abandoned or deprecated):
406    // "cee45ff00381d88710040af9bd1c13ee3176f83efd36b33f2330cca74e53000b" => "AirnodeParametersSet(bytes32,address,string,address[])",
407    // "450d1b4c87d285de4ba1f262cca585d6bb3184ca909e14263ac31a044682d429" => "CheckAuthorizationStatus(bytes32,bytes32,bytes32,uint256,address,address)",
408    // "c39b3f29cca3bbf148a7d996d34223a627c7df660f04f3d28e915ae11eea446c" => "CheckAuthorizationStatuses(bytes32,bytes32[],bytes32[],uint256[],address[],address[])",
409    // "d859fb74ec5a83da09d56bb4211667f87fc36cdec8ccdd9ddc7115c99923e75e" => "ClientEndorsementStatusSet(uint256,address,bool)",
410    // "e8ae99161b1547fd1c6ff3cb9660293fa4cd770fd52f72ff0362d64d8bccc08e" => "ClientFullRequestCreated(bytes32,bytes32,uint256,uint256,address,bytes32,uint256,address,address,bytes4,bytes)",
411    // "8339fddbb81e588a9ed04dec82ee9ae6c7a185f44835adaaa2ace50ce3a14aaf" => "ClientRequestCreated(bytes32,bytes32,uint256,uint256,address,bytes32,uint256,address,address,bytes4,bytes)",
412    // "cde46e28d8d3e348e5f5b4fcc511fe3b1f9b0f549cd8332f0da31802a6f2bf61" => "ClientRequestFulfilled(bytes32,bytes32,uint256,bytes)",
413    // "14c9c5c9712ca2ec34c62aaeb946d2762f472ad43612ad1a7fb549e274715e39" => "CreateRequester(address)",
414    // "57fd46b3414df2b35458ac6ab35236164c21fab7f784d250882d66a197e8cdaf" => "CreateTemplate(bytes32,bytes32,bytes)",
415    // "ddac55da39d52cd1fe3f9a6832cb6fa4c1fb45d755c47f984cc5a1c48aa774cf" => "DecreasedSelfRank(bytes32,address,uint256)",
416    // "98f45a41d9f64ecabfb00dc5bc4f6aea7e50c2afb9eebee8936be5dbcad03dc2" => "ExtendedWhitelistExpiration(bytes32,address,uint256,address)",
417    // "3338d71fe7787f614d15e7da994eaa07eb176c0e5193ba05cc0b71cc10017665" => "Fail(bytes32,bytes32,address,bytes4)",
418    // "a3ecafb4214d6c3c8dbf95d5fe8e92051c9ac156e0584a00b2a7e16b2df48c0a" => "Fulfill(bytes32,bytes32,uint256,bytes,address,bytes4)",
419    // "8ff67212697f6648c4c6355eb59d2e859c8b0de2e42e5c226e43626ec8c38355" => "FulfillWithdrawal(bytes32,bytes32,uint256,address)",
420    // "cf16e219d0e9946ba140541a449711b0d9e7e3600c4fd63f3c5c1e6f7e78f789" => "MakeFullRequest(bytes32,bytes32,uint256,address,address,bytes4,bytes)",
421    // "bc7e6375ca8aaa60eba7a35af9f5692d6de892654b6d794613be986377467d90" => "MakeRequest(bytes32,uint256,address,address,bytes4,bytes)",
422    // "19233d41da09723f3b102e7a0e192a478c3cd72aa3269f529824b8cc632043a3" => "RequestWithdrawal(bytes32,uint256,address,address)",
423    // "430ace8db43187f56ab9e66a2421b7044fa806a347e0a402a646dc9d0edb0cb1" => "SetApi3Admin(address)",
424    // "aeae98ebd6f5c18f7e64fdd4102cb25feb3552afa6f81285fb4f942e2e41fc3f" => "SetAirnodeParameters(address,string,address[])",
425    // "5a0aa1abecb91b072383fcd5858f29ed6135a87dd2f2ab02e8f77def11f19bc2" => "SetAirnodeParametersAndForwardFunds(address,string,address[])",
426    // "5a570f3df76e0cf7e768a1227f789390627bb125bd73a160596a2559aafdc2da" => "SetClientEndorsementStatus(uint256,address,bool)",
427    // "19b9e44e700d40233866bbf1eaa4d9465d357e53969945a144ef247f39a0836a" => "SetRank(bytes32,address,uint256,address)",
428    // "c980cf6eca9a252c38dc7738fb47cd57dfbf37bda6664adfbab67a09df1af859" => "SetRequesterAdmin(uint256,address)",
429    // "0c4d21ef7140ba56cb38499615ee0b0d3258917f74c778590e597a47ad529ac1" => "SetWhitelistExpiration(bytes32,address,uint256,address)",
430    // "12abbeaa6fd4b14c4a9208f65d65c03b44c354145ba54d20b11474254438408f" => "SetWhitelistStatusPastExpiration(bytes32,address,bool,address)",
431    // "a3c44778bf2c4729d112c7eeee01a2a79be70e58e3fe0b2a25d6c3562f73ab83" => "TemplateCreated(bytes32,bytes32,bytes32,bytes)",
432};
433
434#[derive(Debug, Clone, Serialize, Deserialize)]
435pub struct AirnodeState {
436    address: H160,
437    network: String,
438    events: Vec<AirnodeEvent>,
439}
440
441impl AirnodeEvent {
442    pub fn get_error(&self) -> Option<String> {
443        match self {
444            Self::ClientFullRequestCreatedA { error, .. } => error.clone().map(|x| x.to_string()),
445            Self::ClientRequestCreatedA { error, .. } => error.clone().map(|x| x.to_string()),
446            Self::ClientShortRequestCreatedA { error, .. } => error.clone().map(|x| x.to_string()),
447            Self::CreatedTemplate { error, .. } => error.clone().map(|x| x.to_string()),
448            Self::FailedRequest { error_message, .. } => {
449                if error_message.len() > 0 {
450                    Some(error_message.clone())
451                } else {
452                    None
453                }
454            }
455            Self::MadeFullRequest { error, .. } => error.clone().map(|x| x.to_string()),
456            Self::MadeTemplateRequest { error, .. } => error.clone().map(|x| x.to_string()),
457            Self::TemplateCreatedA { error, .. } => error.clone().map(|x| x.to_string()),
458            _ => None,
459        }
460    }
461
462    pub fn get_addresses(&self) -> Vec<H160> {
463        addresses::get_addresses(self)
464    }
465
466    pub fn get_request_id(&self) -> Option<U256> {
467        requests::get_request_id(self)
468    }
469
470    // requester_index: only for pre-alpha
471    pub fn get_requester_index(&self) -> Option<U256> {
472        requests::get_requester_index(self)
473    }
474
475    pub fn get_endpoint_id(&self) -> Option<U256> {
476        requests::get_endpoint_id(self)
477    }
478
479    // airnode: only for beta-protocol
480    pub fn get_airnode(&self) -> Option<H160> {
481        requests::get_airnode(self)
482    }
483
484    // provider_id: only for pre-alpha
485    pub fn get_provider_id(&self) -> Option<U256> {
486        requests::get_provider_id(self)
487    }
488
489    pub fn get_template_id(&self) -> Option<U256> {
490        requests::get_template_id(self)
491    }
492    pub fn get_fulfill_function_id(&self) -> Option<u64> {
493        requests::get_fulfill_function_id(self)
494    }
495
496    pub fn from_log(log: &web3::types::Log) -> Result<Self, EventParseError> {
497        let t0 = log.topics[0];
498
499        if t0 == hex!("8acbd28af1fec329994543393007c74ebc717caab62689ba09fbf938f015d3fc").into() {
500            let mut r = LogReader::new(&log, 2, Some(1)).unwrap();
501            return Ok(Self::ClientEndorsementStatusUpdatedA {
502                requester_index: r.value(),
503                client_address: r.address(),
504                endorsement_status: r.bool(),
505            });
506        } else if t0
507            == hex!("775e78a8e7375d14ad03d31edd0a27b29a055f732bca987abfe8082c16ed7e44").into()
508        {
509            let mut r = LogReader::new(&log, 2, None).unwrap();
510            let provider_id = r.value();
511            let request_id = r.value();
512            let no_requests = r.value().as_u64();
513            let client_address = r.address();
514            let endpoint_id = r.value();
515            let requester_index = r.value();
516            let designated_wallet = r.address();
517            let fulfill_address = r.address();
518            let fulfill_function_id = U256::from(r.value().as_ref()[3] / 0x100000000).as_u64();
519            let (parameters, error, data) = r.decoded();
520            return Ok(Self::ClientFullRequestCreatedA {
521                provider_id,
522                request_id,
523                no_requests,
524                client_address,
525                endpoint_id,
526                requester_index,
527                designated_wallet,
528                fulfill_address,
529                fulfill_function_id, //.as_u64(),
530                parameters,
531                error,
532                data,
533            });
534        } else if t0
535            == hex!("aff6f5e5548953a11cbb1cfdd76562512f969b0eba0a2163f2420630d4dda97b").into()
536        {
537            let mut r = LogReader::new(&log, 2, None).unwrap();
538            let provider_id = r.value();
539            let request_id = r.value();
540            let no_requests = r.value().as_u64();
541            let client_address = r.address();
542            let template_id = r.value();
543            let requester_index = r.value();
544            let designated_wallet = r.address();
545            let fulfill_address = r.address();
546            let fulfill_function_id = U256::from(r.value().as_ref()[3] / 0x100000000).as_u64();
547            let (parameters, error, data) = r.decoded();
548            return Ok(Self::ClientRequestCreatedA {
549                provider_id,
550                request_id,
551                no_requests,
552                client_address,
553                template_id,
554                requester_index,
555                designated_wallet,
556                fulfill_address,
557                fulfill_function_id, //.as_u64(),
558                parameters,
559                error,
560                data,
561            });
562        } else if t0
563            == hex!("1cfdd5ace64f15111ef8ed9df04364d0e9a9165cccf8386109347e54661ba3ad").into()
564        {
565            let mut r = LogReader::new(&log, 2, Some(0)).unwrap();
566            return Ok(Self::ClientRequestFailedA {
567                provider_id: r.value(),
568                request_id: r.value(),
569            });
570        } else if t0
571            == hex!("1bdbe9e5d42a025a741fc3582eb3cad4ef61ac742d83cc87e545fbd481b926b5").into()
572        {
573            let mut r = LogReader::new(&log, 2, Some(2)).unwrap();
574            let provider_id = r.value();
575            let request_id = r.value();
576            let status_code = r.value().as_u64();
577            let (parameters, error, data) = r.decoded();
578            return Ok(Self::ClientRequestFulfilledA {
579                provider_id,
580                request_id,
581                status_code,
582                parameters,
583                error,
584                data,
585            });
586        } else if t0
587            == hex!("0ebeb9b9b5c4baf915e7541c7e0919dd1a58eb06ee596035a50d08d20b9219de").into()
588        {
589            let mut r = LogReader::new(&log, 2, None).unwrap();
590            let provider_id = r.value();
591            let request_id = r.value();
592            let status_code = r.value().as_u64();
593            let (parameters, error, data) = r.decoded();
594            return Ok(Self::ClientRequestFulfilledWithBytesA {
595                provider_id,
596                request_id,
597                status_code,
598                parameters,
599                error,
600                data,
601            });
602        } else if t0
603            == hex!("fcbcd5adb2d26ecd4ad50e6267e977fd479fcd0a6c82bde8eea85290ab3b46e6").into()
604        {
605            let mut r = LogReader::new(&log, 2, None).unwrap();
606            let provider_id = r.value();
607            let request_id = r.value();
608            let no_requests = r.value().as_u64();
609            let client_address = r.address();
610            let template_id = r.value();
611            let (parameters, error, data) = r.decoded();
612            return Ok(Self::ClientShortRequestCreatedA {
613                provider_id,
614                request_id,
615                no_requests,
616                client_address,
617                template_id,
618                parameters,
619                error,
620                data,
621            });
622        } else if t0
623            == hex!("e5687475d94be4622dec0d6fa4db8686e003947facd485b0f4685954b8e93aa8").into()
624        {
625            let mut r = LogReader::new(&log, 2, None).unwrap();
626            return Ok(Self::EndpointUpdatedA {
627                provider_id: r.value(),
628                endpoint_id: r.value(),
629                authorizers: r.addresses(),
630            });
631        } else if t0
632            == hex!("40857340078796a2b6bca551f97b62fffe6ae69e2131195d461862224ee871b6").into()
633        {
634            let mut r = LogReader::new(&log, 1, Some(1)).unwrap();
635            return Ok(Self::MinBalanceUpdatedA {
636                provider_id: r.value(),
637                min_balance: r.value(),
638            });
639        } else if t0
640            == hex!("36ef18ad81b13124b66c80d27059d75bfadf09474c46aee8bb4ae998a921196d").into()
641        {
642            let mut r = LogReader::new(&log, 1, None).unwrap();
643            return Ok(Self::ProviderCreatedA {
644                provider_id: r.value(),
645                admin: r.address(),
646                xpub: r.text(),
647            });
648        } else if t0
649            == hex!("b7de80d002230ae37dd9e25804e78c41517296ad969a962ef5457be94cb8ac6e").into()
650        {
651            let mut r = LogReader::new(&log, 1, None).unwrap();
652            return Ok(Self::ProviderUpdatedA {
653                provider_id: r.value(),
654                admin: r.address(),
655            });
656        } else if t0
657            == hex!("59e98f4c18a6c92efe8c23bcbd74f0d71e271eebf9a95f9edefdbee17c01f270").into()
658        {
659            let mut r = LogReader::new(&log, 1, Some(1)).unwrap();
660            return Ok(Self::RequesterCreatedA {
661                requester_index: r.value(),
662                admin: r.address(),
663            });
664        } else if t0
665            == hex!("de26d3d8fc98a8dab0df21ef2146d313da1a060d635f3ce9b42adab32fa992aa").into()
666        {
667            let mut r = LogReader::new(&log, 1, Some(1)).unwrap();
668            return Ok(Self::RequesterUpdatedA {
669                requester_index: r.value(),
670                admin: r.address(),
671            });
672        } else if t0
673            == hex!("2cb6f3105333165ac08235b122e2651dae9c2e70787572aa65bde31fe838d90d").into()
674        {
675            let mut r = LogReader::new(&log, 0, Some(3)).unwrap();
676            return Ok(Self::RequestFulfilledA {
677                request_id: r.value(),
678                status_code: r.value().as_u64(),
679                data: r.value(),
680            });
681        } else if t0
682            == hex!("13873a3c5277d69c913bb408d87512468d41afb41113dd46eee917ec4eceb04b").into()
683        {
684            let mut r = LogReader::new(&log, 0, None).unwrap();
685            let request_id = r.value();
686            let status_code = r.value().as_u64();
687            let (parameters, error, data) = r.decoded();
688            return Ok(Self::RequestFulfilledWithBytesA {
689                request_id,
690                status_code,
691                parameters,
692                error,
693                data,
694            });
695        } else if t0
696            == hex!("fa33b8597a1a83305d334562a90f8b4ce657e1b33c081423b6a44792d1cf41a4").into()
697        {
698            let mut r = LogReader::new(&log, 1, None).unwrap();
699            let template_id = r.value();
700            let provider_id = r.value();
701            let endpoint_id = r.value();
702            let requester_index: U256 = r.value();
703            let designated_wallet = r.address();
704            let fulfill_address = r.address();
705            let fulfill_function_id = U256::from(r.value().as_ref()[3] / 0x100000000).as_u64();
706            let (parameters, error, data) = r.decoded();
707            return Ok(Self::TemplateCreatedA {
708                template_id,
709                provider_id,
710                endpoint_id,
711                requester_index,
712                designated_wallet,
713                fulfill_address,
714                fulfill_function_id,
715                parameters,
716                error,
717                data,
718            });
719        } else if t0
720            == hex!("9e7b58b29aa3b972bb0f457499d0dfd00bf23905b0c3358fb864e7120402aefa").into()
721        {
722            let mut r = LogReader::new(&log, 3, Some(3)).unwrap();
723            return Ok(Self::WithdrawalFulfilledA {
724                provider_id: r.value(),
725                requester_index: r.value(),
726                withdrawal_request_id: r.value(),
727                designated_wallet: r.address(),
728                destination: r.address(),
729                amount: r.value(),
730            });
731        } else if t0
732            == hex!("3d0ebccb4fc9730699221da0180970852f595ed5c78781346149123cbbe9f1d3").into()
733        {
734            let mut r = LogReader::new(&log, 3, Some(2)).unwrap();
735            return Ok(Self::WithdrawalFulfilledA {
736                provider_id: r.value(),
737                requester_index: r.value(),
738                withdrawal_request_id: r.value(),
739                designated_wallet: r.address(),
740                destination: r.address(),
741                amount: r.value(),
742            });
743        } else if t0
744            == hex!("ba204bad31c4ec4b9b54164af94ae10c4e7312f22c0f9c065d6319c928ec9e7a").into()
745        {
746            let mut r = LogReader::new(&log, 1, None).unwrap();
747            let template_id = r.value();
748            let airnode = r.address();
749            let endpoint_id = r.value();
750            let (parameters, error, data) = r.decoded();
751            return Ok(Self::CreatedTemplate {
752                template_id,
753                airnode,
754                endpoint_id,
755                parameters,
756                data,
757                error,
758            });
759        } else if t0
760            == hex!("b4a13e8a5b83b6572fd11170aa28965f4b16ce6ed228501322a428b48e34230c").into()
761        {
762            let mut r = LogReader::new(&log, 1, Some(1)).unwrap();
763            return Ok(Self::DecreasedSelfRank {
764                admin: r.address(),
765                new_rank: r.value(),
766            });
767        } else if t0
768            == hex!("907b7436750d9bb04b635c837b151be449230b1975dac4ba31b01343b41eb75c").into()
769        {
770            let mut r = LogReader::new(&log, 2, Some(1)).unwrap();
771            return Ok(Self::DecreasedSelfRankAdminned {
772                adminned: r.address(),
773                admin: r.address(),
774                new_rank: r.value(),
775            });
776        } else if t0
777            == hex!("df7c6cf6c7d32bf473537bcf24259094d6e7cb863700e071f65a4d8a05b6ce5e").into()
778        {
779            let mut r = LogReader::new(&log, 1, Some(2)).unwrap();
780            return Ok(Self::ErroredBeaconUpdate {
781                template_id: r.value(),
782                request_id: r.value(),
783                status_code: r.value().as_u64(),
784            });
785        } else if t0
786            == hex!("f9b174be67f83278d4516865d1b9ba4576b73e523ea0c2f124ea29152bb1b676").into()
787        {
788            let mut r = LogReader::new(&log, 1, Some(1)).unwrap();
789            return Ok(Self::ExtendedWhitelistExpiration {
790                airnode: r.address(),
791                endpoint_id: r.value(),
792                user: r.address(),
793                admin: r.address(),
794                expiration: r.value().as_u64(),
795            });
796        } else if t0
797            == hex!("a9e0c89b898eb7a904617915dc5b5510d539c899810042e9248569b54b9cc2ed").into()
798        {
799            let mut r = LogReader::new(&log, 3, Some(1)).unwrap();
800            return Ok(Self::ExtendedWhitelistExpirationTpl {
801                template_id: r.value(),
802                user: r.address(),
803                admin: r.address(),
804                expiration: r.value().as_u64(),
805            });
806        } else if t0
807            == hex!("8c087e42b178608800a2ea8b3d009bdbbf75e0d23426510c2edd447d4f8b8ebd").into()
808        {
809            let mut r = LogReader::new(&log, 2, None).unwrap();
810            return Ok(Self::FailedRequest {
811                airnode: r.address(),
812                request_id: r.value(),
813                error_message: r.text(),
814            });
815        } else if t0
816            == hex!("c7143b2270cddda57e0087ca5e2a4325657dcab10d10f6b1f9d5ce6b41cb97fc").into()
817        {
818            let mut r = LogReader::new(&log, 2, None).unwrap();
819            return Ok(Self::FailedRequest {
820                airnode: r.address(),
821                request_id: r.value(),
822                error_message: r.text(),
823            });
824        } else if t0
825            == hex!("c0977dab79883641ece94bb6a932ca83049f561ffff8d8daaeafdbc1acce9e0a").into()
826        {
827            let mut r = LogReader::new(&log, 2, None).unwrap();
828            let airnode = r.address();
829            let request_id = r.value();
830            let (parameters, error, data) = r.decoded();
831            return Ok(Self::FulfilledRequest {
832                airnode,
833                request_id,
834                parameters,
835                error,
836                data,
837            });
838        } else if t0
839            == hex!("d1cc11d12363af4b6022e66d14b18ba1779ecd85a5b41891349d530fb6eee066").into()
840        {
841            let mut r = LogReader::new(&log, 2, None).unwrap();
842            let airnode = r.address();
843            let request_id = r.value();
844            let status_code = r.value().as_u64();
845            let (parameters, error, data) = r.decoded();
846            return Ok(Self::FulfilledRequestWithStatus {
847                airnode,
848                request_id,
849                status_code,
850                parameters,
851                error,
852                data,
853            });
854        } else if t0
855            == hex!("adb4840bbd5f924665ae7e0e0c83de5c0fb40a98c9b57dba53a6c978127a622e").into()
856        {
857            let mut r = LogReader::new(&log, 3, Some(2)).unwrap();
858            return Ok(Self::FulfilledWithdrawal {
859                airnode: r.address(),
860                sponsor: r.address(),
861                withdrawal_request_id: r.value(),
862                sponsor_wallet: r.address(),
863                amount: r.value(),
864            });
865        } else if t0
866            == hex!("3a52c462346de2e9436a3868970892956828a11b9c43da1ed43740b12e1125ae").into()
867        {
868            let mut r = LogReader::new(&log, 2, None).unwrap();
869            let airnode = r.address();
870            let request_id = r.value();
871            let requester_request_count = r.value().as_u64();
872            let chain_id = r.value().as_u64();
873            let requester = r.address();
874            let endpoint_id = r.value();
875            let sponsor = r.address();
876            let sponsor_wallet = r.address();
877            let fulfill_address = r.address();
878            let fulfill_function_id = U256::from(r.value().as_ref()[3] / 0x100000000).as_u64();
879            let (parameters, error, data) = r.decoded();
880            return Ok(Self::MadeFullRequest {
881                airnode,
882                request_id,
883                requester_request_count,
884                chain_id,
885                requester,
886                endpoint_id,
887                sponsor,
888                sponsor_wallet,
889                fulfill_address,
890                fulfill_function_id,
891                parameters,
892                error,
893                data,
894            });
895        } else if t0
896            == hex!("eb39930cdcbb560e6422558a2468b93a215af60063622e63cbb165eba14c3203").into()
897        {
898            let mut r = LogReader::new(&log, 2, None).unwrap();
899            let airnode = r.address();
900            let request_id = r.value();
901            let requester_request_count = r.value().as_u64();
902            let chain_id = r.value().as_u64();
903            let requester = r.address();
904            let template_id = r.value();
905            let sponsor = r.address();
906            let sponsor_wallet = r.address();
907            let fulfill_address = r.address();
908            let fulfill_function_id = U256::from(r.value().as_ref()[3] / 0x100000000).as_u64();
909            let (parameters, error, data) = r.decoded();
910            return Ok(Self::MadeTemplateRequest {
911                airnode,
912                request_id,
913                requester_request_count,
914                chain_id,
915                requester,
916                template_id,
917                sponsor,
918                sponsor_wallet,
919                fulfill_address,
920                fulfill_function_id,
921                parameters,
922                error,
923                data,
924            });
925        } else if t0
926            == hex!("db6e5ad2f932677d9abcb868239c24d484d5512caf71029b8b7c2309aeee760a").into()
927        {
928            let mut r = LogReader::new(&log, 3, Some(2)).unwrap();
929            return Ok(Self::RequestedBeaconUpdate {
930                template_id: r.value(),
931                sponsor: r.address(),
932                requester: r.address(),
933                request_id: r.value(),
934                sponsor_wallet: r.address(),
935            });
936        } else if t0
937            == hex!("d48d52c7c6d0c940f3f8d07591e1800ef3a70daf79929a97ccd80b4494769fc7").into()
938        {
939            let mut r = LogReader::new(&log, 3, Some(1)).unwrap();
940            return Ok(Self::RequestedWithdrawal {
941                airnode: r.address(),
942                sponsor: r.address(),
943                withdrawal_request_id: r.value(),
944                sponsor_wallet: r.address(),
945            });
946        } else if t0
947            == hex!("ebace4380f1ba3ccf701db78879a937b0ad2a9370e98baaba922228f632383e0").into()
948        {
949            let mut r = LogReader::new(&log, 1, None).unwrap();
950            return Ok(Self::SetAirnodeXpub {
951                airnode: r.address(),
952                xpub: r.text(),
953            });
954        } else if t0
955            == hex!("584a7e3e68feb90397faadcb0af28a855e0268ddedf9fce510b4cf57770b9410").into()
956        {
957            let mut r = LogReader::new(&log, 3, Some(1)).unwrap();
958            return Ok(Self::SetRankAdminned {
959                adminned: r.address(),
960                caller_admin: r.address(),
961                target_admin: r.address(),
962                new_rank: r.value(),
963            });
964        } else if t0
965            == hex!("07048cabcdd89c62fecf542621231579eae613db4aeb83794e9c3abf428840ca").into()
966        {
967            let mut r = LogReader::new(&log, 2, Some(1)).unwrap();
968            return Ok(Self::SetRank {
969                caller_admin: r.address(),
970                target_admin: r.address(),
971                new_rank: r.value(),
972            });
973        } else if t0
974            == hex!("c2e532a12bbcce2bfa2ef9e4bee80180e4e1b1f78618f0d20bc49a648b577c56").into()
975        {
976            let mut r = LogReader::new(&log, 2, Some(1)).unwrap();
977            return Ok(Self::SetSponsorshipStatus {
978                sponsor: r.address(),
979                requester: r.address(),
980                sponsorship_status: r.bool(),
981            });
982        } else if t0
983            == hex!("5a3b1968640fbb8b12349ea1a58be5c61eaec6e38c11c38652f1d250207103ab").into()
984        {
985            let mut r = LogReader::new(&log, 2, Some(1)).unwrap();
986            return Ok(Self::SetUpdatePermissionStatus {
987                sponsor: r.address(),
988                update_requester: r.address(),
989                status: r.bool(),
990            });
991        } else if t0
992            == hex!("375ee45428e158031095010484fd6451af89c501c79d75e390da4e91eb480ce1").into()
993        {
994            let mut r = LogReader::new(&log, 3, Some(1)).unwrap();
995            return Ok(Self::SetWhitelistExpiration {
996                airnode: r.address(),
997                endpoint_id: r.value(),
998                user: r.address(),
999                admin: r.address(),
1000                expiration: r.value().as_u64(),
1001            });
1002        } else if t0
1003            == hex!("d19e89b7d547ccf349211588a9a1d29461e2ce984b1b1cdbe7150976528b86f1").into()
1004        {
1005            let mut r = LogReader::new(&log, 3, Some(1)).unwrap();
1006            return Ok(Self::SetWhitelistExpirationTpl {
1007                template_id: r.value(),
1008                user: r.address(),
1009                admin: r.address(),
1010                expiration: r.value().as_u64(),
1011            });
1012        } else if t0
1013            == hex!("0e8af304f7f920661493a5051df03a3947d58b4f655581e51ab0c014d768d8eb").into()
1014        {
1015            let mut r = LogReader::new(&log, 4, Some(1)).unwrap();
1016            return Ok(Self::SetWhitelistStatusPastExpiration {
1017                airnode: r.address(),
1018                endpoint_id: r.value(),
1019                user: r.address(),
1020                admin: r.address(),
1021                status: r.bool(),
1022            });
1023        } else if t0
1024            == hex!("527f03e7cb13db04fc83c2332106b6087c66d253bca13289f5d91d8e73796d11").into()
1025        {
1026            let mut r = LogReader::new(&log, 3, Some(1)).unwrap();
1027            return Ok(Self::SetWhitelistStatusPastExpirationTpl {
1028                template_id: r.value(),
1029                user: r.address(),
1030                admin: r.address(),
1031                status: r.bool(),
1032            });
1033        } else if t0
1034            == hex!("c3dafe3cca75d9d099b1941e05b199870f55b853dd49784a96359ac26f01bf6d").into()
1035        {
1036            let mut r = LogReader::new(&log, 1, Some(0)).unwrap();
1037            return Ok(Self::TransferredMetaAdminStatus {
1038                meta_admin: r.address(),
1039            });
1040        } else if t0
1041            == hex!("cb9c65e5f99c20826a331174f56e8c536161ecb0b5d598267e79c83567d477f1").into()
1042        {
1043            let mut r = LogReader::new(&log, 1, Some(2)).unwrap();
1044            let template_id = r.value();
1045            let request_id = r.value();
1046            let (value, timestamp) = r.value224_32();
1047            return Ok(Self::UpdatedBeacon {
1048                template_id,
1049                request_id,
1050                value,
1051                timestamp,
1052            });
1053        }
1054
1055        let topic_str = format!("{:?}", t0).chars().skip(2).collect::<String>();
1056        match KNOWN_EVENTS.get(&topic_str) {
1057            Some(_title) => {
1058                // println!("{} topic={:?}", title, t0);
1059                Ok(Self::Unclassified { topic: t0 })
1060            }
1061            None => Ok(Self::Unknown { topic: t0 }),
1062        }
1063    }
1064}