@@ -17,14 +17,14 @@ Attestations enable validators to cryptographically sign query results, providin
1717## Prerequisites
1818
1919- Node.js >= 18
20- - A wallet with TRUF tokens for transaction fees
21- - Private key with access to TRUF.NETWORK
20+ - (Optional) A wallet with TRUF tokens if you want to request new attestations
21+ - (Optional) Private key - defaults to test key if not provided
2222
2323## Setup
2424
25251 . ** Install Dependencies** :
2626 ``` bash
27- cd /home/micbun/trufnetwork/ sdk-js
27+ # From the sdk-js root directory
2828 npm install
2929 ```
3030
@@ -42,25 +42,30 @@ Attestations enable validators to cryptographically sign query results, providin
4242### Quick Start (No Configuration)
4343
4444``` bash
45- # Run with default test key
46- npm run example:attestation
47- ```
45+ # From the sdk-js root directory, navigate to the example
46+ cd examples/attestation
4847
49- Or directly:
50- ``` bash
51- npx tsx examples/attestation/index.ts
48+ # Run with default test key
49+ npm start
5250```
5351
5452### With Your Own Wallet
5553
54+ If you want to use your own private key instead of the test key:
55+
5656``` bash
57- # Set your private key
58- export PRIVATE_KEY=" 0x..."
57+ # From the sdk-js root directory, navigate to the example
58+ cd examples/attestation
59+
60+ # Set your private key (replace with your actual private key)
61+ export PRIVATE_KEY=" 0x1234567890abcdef..."
5962
6063# Run the example
61- npm run example:attestation
64+ npm start
6265```
6366
67+ ** Note** : Replace ` 0x1234567890abcdef... ` with your actual 64-character hexadecimal private key.
68+
6469## Expected Output
6570
6671```
@@ -72,54 +77,61 @@ Wallet address: 0x...
7277===== Requesting Attestation =====
7378Data Provider: 0x4710a8d8f0d845da110086812a32de6d90d7ff5c
7479Stream ID: stai0000000000000000000000000000
75- Time Range: 2025-10-14T... to 2025-10-21T...
80+ Time Range: ...
81+
82+ ===== Listing Recent Attestations =====
83+
84+ Found ... attestations for 0x...:
85+
86+ [1] Request TX: ...
87+ Created at block: ...
88+ Signed at block: ...
89+ Attestation hash: ...
90+ Encrypted: No
91+
92+ ...
93+
94+ ===== Retrieving Signed Attestation Payload =====
95+ Found ... signed attestation(s), retrieving the first one...
96+
97+ ✅ Retrieved signed attestation for TX: ...
98+ Payload size: ... bytes
99+ First 64 bytes (hex): ...
100+ Last 65 bytes (signature): ...
101+ Full payload (hex): ...
102+
103+ ===== Extracting Validator Information =====
104+ ✅ Validator Address: 0x...
105+ This is the address you should use in your EVM smart contract's verify() function
106+
107+ 💡 How to use this payload:
108+ 1. Send this hex payload to your EVM smart contract
109+ 2. The contract can verify the signature using ecrecover
110+ 3. Parse the payload to extract the attested query results
111+ 4. Use the verified data in your on-chain logic
112+
113+ ===== Attempting to Request New Attestation =====
114+ ⚠️ NOTE: This requires at least 40 TRUF balance for attestation fee
76115
77116✅ Attestation requested!
78- Request TX ID: 0x ...
117+ Request TX ID: ...
79118
80119Waiting for transaction confirmation...
81120✅ Transaction confirmed!
82121
83122===== Waiting for Validator Signature =====
84123The leader validator will sign the attestation asynchronously (typically 1-2 blocks)...
85124
86- ✅ Signed attestation received after 3 attempts!
87-
88- Payload size: 450 bytes
89- First 64 bytes (hex): 010000...
90- Last 65 bytes (signature): a7b3c2...
91-
92- ===== Listing Recent Attestations =====
93-
94- Found 5 attestations for 0x...:
125+ ✅ Signed attestation received after ... attempts!
95126
96- [1] Request TX: 0x...
97- Created at block: 12345
98- Signed at block: 12347
99- Attestation hash: abc123...
100- Encrypted: No
101-
102- ...
127+ Payload size: ... bytes
128+ First 64 bytes (hex): ...
129+ Last 65 bytes (signature): ...
130+ Full payload (hex): ...
103131
104132===== Summary =====
105133✅ Successfully requested and retrieved a signed attestation!
106134
107- Next steps:
108- - Use the payload in EVM smart contracts for verification
109- - Implement signature verification using ecrecover
110- - Parse the canonical payload to extract query results
111-
112- The signed attestation payload contains:
113- 1. Version (1 byte)
114- 2. Algorithm (1 byte, 0 = secp256k1)
115- 3. Block height (8 bytes)
116- 4. Data provider (20 bytes, length-prefixed)
117- 5. Stream ID (32 bytes, length-prefixed)
118- 6. Action ID (2 bytes)
119- 7. Arguments (variable, length-prefixed)
120- 8. Result (variable, length-prefixed)
121- 9. Signature (65 bytes, secp256k1)
122-
123135✨ Example completed successfully!
124136```
125137
@@ -167,26 +179,26 @@ function verifyAttestation(bytes memory payload, address expectedValidator) publ
167179The signature can be verified using ` ecrecover ` :
168180
169181``` typescript
170- import { ethers } from " ethers" ;
182+ import { sha256 , recoverAddress } from " ethers" ;
171183
172184// Extract signature from payload (last 65 bytes)
173- const signature = payload .slice (- 65 );
174- const r = signature .slice (0 , 32 );
175- const s = signature .slice (32 , 64 );
185+ const payload = signedPayload .payload ;
186+ const signatureOffset = payload .length - 65 ;
187+ const canonicalPayload = payload .slice (0 , signatureOffset );
188+ const signature = payload .slice (signatureOffset );
189+
190+ // Hash the canonical payload with SHA256
191+ const digest = sha256 (canonicalPayload );
192+
193+ // Recover validator address from signature
194+ // The signature format is [R || S || V] where V is {27,28}
195+ const r = " 0x" + Buffer .from (signature .slice (0 , 32 )).toString (" hex" );
196+ const s = " 0x" + Buffer .from (signature .slice (32 , 64 )).toString (" hex" );
176197const v = signature [64 ];
177198
178- // Reconstruct message hash (SHA256 of canonical payload without signature)
179- const canonical = payload .slice (0 , - 65 );
180- const messageHash = ethers .utils .sha256 (canonical );
181-
182- // Recover signer
183- const recoveredAddress = ethers .utils .recoverAddress (messageHash , {
184- r: ethers .utils .hexlify (r ),
185- s: ethers .utils .hexlify (s ),
186- v: v
187- });
199+ const validatorAddress = recoverAddress (digest , { r , s , v });
188200
189- console .log (` Signer : ${recoveredAddress }` );
201+ console .log (` Validator Address : ${validatorAddress }` );
190202```
191203
192204## Troubleshooting
@@ -220,12 +232,12 @@ Ensure your private key is correctly formatted:
220232
221233``` typescript
222234interface RequestAttestationInput {
223- dataProvider: string ; // 0x-prefixed address (42 chars)
224- streamId: string ; // 32 characters
225- actionName: string ; // Action to attest
226- args: any []; // Action arguments
227- encryptSig: boolean ; // Must be false (MVP)
228- maxFee: number ; // Maximum fee willing to pay
235+ dataProvider: string ; // 0x-prefixed address (42 chars)
236+ streamId: string ; // 32 characters
237+ actionName: string ; // Action to attest
238+ args: any []; // Action arguments
239+ encryptSig: boolean ; // Must be false (MVP)
240+ maxFee: number | string | bigint ; // Maximum fee willing to pay (in wei)
229241}
230242```
231243
@@ -251,8 +263,8 @@ interface ListAttestationsInput {
251263## Related Documentation
252264
253265- [ SDK-JS Documentation] ( ../../README.md )
254- - [ Attestation Implementation Plan] ( ../../../DataAttestation/SDK_JS_Attestation_Implementation_Plan.md )
255266- [ TRUF.NETWORK Documentation] ( https://docs.truf.network )
267+ - [ EVM Attestation Contracts] ( https://github.com/trufnetwork/evm-contracts/tree/main/contracts/attestation )
256268
257269## Support
258270
0 commit comments