1
1
import { ethers } from 'ethers' ;
2
+ import { zip } from 'lodash' ;
2
3
3
4
import {
4
- Api3ServerV1__factory as Api3ServerV1Factory ,
5
5
type AirseekerRegistry ,
6
6
AirseekerRegistry__factory as AirseekerRegistryFactory ,
7
+ Api3ServerV1__factory as Api3ServerV1Factory ,
7
8
} from '../typechain-types' ;
8
- import type { DecodedDataFeed } from '../types' ;
9
+ import type { AirnodeAddress , TemplateId } from '../types' ;
9
10
import { decodeDapiName , deriveBeaconId } from '../utils' ;
10
11
11
12
export const getApi3ServerV1 = ( address : string , provider : ethers . JsonRpcProvider ) =>
@@ -29,9 +30,15 @@ export const decodeGetBlockNumberResponse = Number;
29
30
30
31
export const decodeGetChainIdResponse = Number ;
31
32
32
- export const decodeDataFeedDetails = ( dataFeed : string ) : DecodedDataFeed | null => {
33
+ export interface Beacon {
34
+ airnodeAddress : AirnodeAddress ;
35
+ templateId : TemplateId ;
36
+ beaconId : string ;
37
+ }
38
+
39
+ export const decodeDataFeedDetails = ( dataFeed : string ) : Beacon [ ] | null => {
33
40
// The contract returns empty bytes if the data feed is not registered. See:
34
- // https://github.com/api3dao/dapi-management /blob/f3d39e4707c33c075a8f07aa8f8369f8dc07736f /contracts/AirseekerRegistry.sol#L209
41
+ // https://github.com/bbenligiray/api3-contracts /blob/d394581549e4d2f343e9910bc330b21266808851 /contracts/AirseekerRegistry.sol#L346
35
42
if ( dataFeed === '0x' ) return null ;
36
43
37
44
// This is a hex encoded string, the contract works with bytes directly
@@ -41,7 +48,7 @@ export const decodeDataFeedDetails = (dataFeed: string): DecodedDataFeed | null
41
48
42
49
const dataFeedId = deriveBeaconId ( airnodeAddress , templateId ) ! ;
43
50
44
- return { beacons : [ { beaconId : dataFeedId , airnodeAddress, templateId } ] } ;
51
+ return [ { beaconId : dataFeedId , airnodeAddress, templateId } ] ;
45
52
}
46
53
47
54
const [ airnodeAddresses , templateIds ] = ethers . AbiCoder . defaultAbiCoder ( ) . decode (
@@ -56,7 +63,7 @@ export const decodeDataFeedDetails = (dataFeed: string): DecodedDataFeed | null
56
63
return { beaconId, airnodeAddress, templateId } ;
57
64
} ) ;
58
65
59
- return { beacons } ;
66
+ return beacons ;
60
67
} ;
61
68
62
69
export interface DecodedUpdateParameters {
@@ -81,29 +88,53 @@ export const decodeUpdateParameters = (updateParameters: string): DecodedUpdateP
81
88
} ;
82
89
} ;
83
90
91
+ export interface BeaconWithData extends Beacon {
92
+ value : bigint ;
93
+ timestamp : bigint ;
94
+ }
95
+
84
96
export interface DecodedActiveDataFeedResponse {
85
97
dapiName : string | null ;
86
98
dataFeedId : string ;
87
99
decodedDapiName : string | null ;
88
100
decodedUpdateParameters : DecodedUpdateParameters ;
89
101
dataFeedValue : bigint ;
90
102
dataFeedTimestamp : bigint ;
91
- decodedDataFeed : DecodedDataFeed ;
103
+ beaconsWithData : BeaconWithData [ ] ;
92
104
signedApiUrls : string [ ] ;
93
105
}
94
106
107
+ export const createBeaconsWithData = ( beacons : Beacon [ ] , beaconValues : bigint [ ] , beaconTimestamps : bigint [ ] ) => {
108
+ return zip ( beacons , beaconValues , beaconTimestamps ) . map ( ( [ beacon , value , timestamp ] ) => ( {
109
+ ...beacon ! ,
110
+ value : value ! ,
111
+ timestamp : BigInt ( timestamp ! ) ,
112
+ } ) ) ;
113
+ } ;
114
+
95
115
export const decodeActiveDataFeedResponse = (
96
116
airseekerRegistry : AirseekerRegistry ,
97
117
activeDataFeedReturndata : string
98
118
) : DecodedActiveDataFeedResponse | null => {
99
- const { dapiName, dataFeedId, updateParameters, dataFeedValue, dataFeedTimestamp, dataFeedDetails, signedApiUrls } =
100
- airseekerRegistry . interface . decodeFunctionResult ( 'activeDataFeed' , activeDataFeedReturndata ) as unknown as Awaited <
101
- ReturnType < AirseekerRegistry [ 'activeDataFeed' ] [ 'staticCall' ] >
102
- > ;
103
-
104
- // https://github.com/api3dao/dapi-management/blob/f3d39e4707c33c075a8f07aa8f8369f8dc07736f/contracts/AirseekerRegistry.sol#L162
105
- const decodedDataFeed = decodeDataFeedDetails ( dataFeedDetails ) ;
106
- if ( ! decodedDataFeed ) return null ;
119
+ const {
120
+ dataFeedId,
121
+ dapiName,
122
+ updateParameters,
123
+ dataFeedValue,
124
+ dataFeedTimestamp,
125
+ dataFeedDetails,
126
+ signedApiUrls,
127
+ beaconValues,
128
+ beaconTimestamps,
129
+ } = airseekerRegistry . interface . decodeFunctionResult (
130
+ 'activeDataFeed' ,
131
+ activeDataFeedReturndata
132
+ ) as unknown as Awaited < ReturnType < AirseekerRegistry [ 'activeDataFeed' ] [ 'staticCall' ] > > ;
133
+
134
+ // https://github.com/bbenligiray/api3-contracts/blob/d394581549e4d2f343e9910bc330b21266808851/contracts/AirseekerRegistry.sol#L295
135
+ const beacons = decodeDataFeedDetails ( dataFeedDetails ) ;
136
+ if ( ! beacons ) return null ;
137
+ const beaconsWithData = createBeaconsWithData ( beacons , beaconValues , beaconTimestamps ) ;
107
138
108
139
// The dAPI name will be set to zero (in bytes32) in case the data feed is not a dAPI and is identified by a data feed
109
140
// ID.
@@ -116,7 +147,7 @@ export const decodeActiveDataFeedResponse = (
116
147
decodedUpdateParameters : decodeUpdateParameters ( updateParameters ) ,
117
148
dataFeedValue,
118
149
dataFeedTimestamp,
119
- decodedDataFeed ,
150
+ beaconsWithData ,
120
151
signedApiUrls,
121
152
} ;
122
153
} ;
0 commit comments