1414
1515import { NodeTNClient } from "../../src" ;
1616import { Wallet , sha256 , recoverAddress } from "ethers" ;
17+ import { parseAttestationPayload } from "../../src/util/AttestationEncoding" ;
1718
1819async function main ( ) {
1920 // ===== 1. Setup Client =====
@@ -48,13 +49,14 @@ async function main() {
4849 const dataProvider = "0x4710a8d8f0d845da110086812a32de6d90d7ff5c" ; // AI Index data provider
4950 const streamId = "stai0000000000000000000000000000" ; // AI Index stream
5051
51- // Query last 7 days of data
52- const now = Math . floor ( Date . now ( ) / 1000 ) ;
53- const weekAgo = now - 7 * 24 * 60 * 60 ;
52+ // Query data from January 2024 (when the stream has data)
53+ const startTime = 1704067200 ; // Jan 1, 2024 00:00:00 UTC
54+ const endTime = startTime + ( 30 * 24 * 60 * 60 ) ; // 30 days later
5455
5556 console . log ( `Data Provider: ${ dataProvider } ` ) ;
5657 console . log ( `Stream ID: ${ streamId } ` ) ;
57- console . log ( `Time Range: ${ new Date ( weekAgo * 1000 ) . toISOString ( ) } to ${ new Date ( now * 1000 ) . toISOString ( ) } \n` ) ;
58+ console . log ( `Time Range: ${ new Date ( startTime * 1000 ) . toISOString ( ) } to ${ new Date ( endTime * 1000 ) . toISOString ( ) } ` ) ;
59+ console . log ( ` (Using historical data from January 2024)\n` ) ;
5860
5961 // ===== 3. List My Recent Attestations =====
6062 console . log ( "===== Listing Recent Attestations =====\n" ) ;
@@ -129,7 +131,30 @@ async function main() {
129131 console . log ( `✅ Validator Address: ${ validatorAddress } ` ) ;
130132 console . log ( ` This is the address you should use in your EVM smart contract's verify() function\n` ) ;
131133
132- console . log ( ` 💡 How to use this payload:` ) ;
134+ // ===== Parse Attestation Payload =====
135+ console . log ( `===== Parsing Attestation Payload =====` ) ;
136+
137+ const parsed = parseAttestationPayload ( canonicalPayload ) ;
138+
139+ console . log ( `📋 Attestation Details:` ) ;
140+ console . log ( ` Version: ${ parsed . version } ` ) ;
141+ console . log ( ` Algorithm: ${ parsed . algorithm } (0 = secp256k1)` ) ;
142+ console . log ( ` Block Height: ${ parsed . blockHeight } ` ) ;
143+ console . log ( ` Data Provider: ${ parsed . dataProvider } ` ) ;
144+ console . log ( ` Stream ID: ${ parsed . streamId } ` ) ;
145+ console . log ( ` Action ID: ${ parsed . actionId } \n` ) ;
146+
147+ console . log ( `📊 Attested Query Result (from get_record):` ) ;
148+ if ( parsed . result . length === 0 ) {
149+ console . log ( ` No records found` ) ;
150+ } else {
151+ console . log ( ` Found ${ parsed . result . length } row(s):\n` ) ;
152+ parsed . result . forEach ( ( row , idx ) => {
153+ console . log ( ` Row ${ idx + 1 } : ${ JSON . stringify ( row . values ) } ` ) ;
154+ } ) ;
155+ }
156+
157+ console . log ( `\n 💡 How to use this payload:` ) ;
133158 console . log ( ` 1. Send this hex payload to your EVM smart contract` ) ;
134159 console . log ( ` 2. The contract can verify the signature using ecrecover` ) ;
135160 console . log ( ` 3. Parse the payload to extract the attested query results` ) ;
@@ -154,8 +179,8 @@ async function main() {
154179 args : [
155180 dataProvider ,
156181 streamId ,
157- weekAgo ,
158- now ,
182+ startTime ,
183+ endTime ,
159184 null , // frozen_at (not used)
160185 false , // use_cache (will be forced to false for determinism)
161186 ] ,
@@ -215,6 +240,48 @@ async function main() {
215240 console . log ( `First 64 bytes (hex): ${ Buffer . from ( signedAttestation . payload . slice ( 0 , 64 ) ) . toString ( "hex" ) } ` ) ;
216241 console . log ( `Last 65 bytes (signature): ${ Buffer . from ( signedAttestation . payload . slice ( - 65 ) ) . toString ( "hex" ) } ` ) ;
217242 console . log ( `Full payload (hex): ${ Buffer . from ( signedAttestation . payload ) . toString ( "hex" ) } \n` ) ;
243+
244+ // ===== Parse and Display the Attestation =====
245+ try {
246+ console . log ( `===== Parsing Attestation Payload =====` ) ;
247+
248+ const signatureOffset = signedAttestation . payload . length - 65 ;
249+ const canonicalPayload = signedAttestation . payload . slice ( 0 , signatureOffset ) ;
250+ const signature = signedAttestation . payload . slice ( signatureOffset ) ;
251+
252+ // Verify signature
253+ const digest = sha256 ( canonicalPayload ) ;
254+ const r = "0x" + Buffer . from ( signature . slice ( 0 , 32 ) ) . toString ( "hex" ) ;
255+ const s = "0x" + Buffer . from ( signature . slice ( 32 , 64 ) ) . toString ( "hex" ) ;
256+ const v = signature [ 64 ] ;
257+ const validatorAddress = recoverAddress ( digest , { r, s, v } ) ;
258+
259+ console . log ( `✅ Validator Address: ${ validatorAddress } \n` ) ;
260+
261+ // Parse payload
262+ const parsed = parseAttestationPayload ( canonicalPayload ) ;
263+
264+ console . log ( `📋 Attestation Details:` ) ;
265+ console . log ( ` Version: ${ parsed . version } ` ) ;
266+ console . log ( ` Algorithm: ${ parsed . algorithm } (0 = secp256k1)` ) ;
267+ console . log ( ` Block Height: ${ parsed . blockHeight } ` ) ;
268+ console . log ( ` Data Provider: ${ parsed . dataProvider } ` ) ;
269+ console . log ( ` Stream ID: ${ parsed . streamId } ` ) ;
270+ console . log ( ` Action ID: ${ parsed . actionId } \n` ) ;
271+
272+ console . log ( `📊 Attested Query Result (from get_record):` ) ;
273+ if ( parsed . result . length === 0 ) {
274+ console . log ( ` No records found` ) ;
275+ } else {
276+ console . log ( ` Found ${ parsed . result . length } row(s):\n` ) ;
277+ parsed . result . forEach ( ( row , idx ) => {
278+ console . log ( ` Row ${ idx + 1 } : ${ JSON . stringify ( row . values ) } ` ) ;
279+ } ) ;
280+ }
281+ console . log ( "" ) ;
282+ } catch ( parseErr : any ) {
283+ console . log ( `⚠️ Could not parse payload: ${ parseErr . message } \n` ) ;
284+ }
218285 }
219286 } catch ( err : any ) {
220287 // Check if it's an insufficient balance error
0 commit comments