Skip to content

Commit 128b76e

Browse files
committed
fix: correct attestation example flow and documentation
1 parent e06cc91 commit 128b76e

File tree

3 files changed

+253
-151
lines changed

3 files changed

+253
-151
lines changed

examples/attestation/README.md

Lines changed: 80 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -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

2525
1. **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 =====
7378
Data Provider: 0x4710a8d8f0d845da110086812a32de6d90d7ff5c
7479
Stream 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
80119
Waiting for transaction confirmation...
81120
✅ Transaction confirmed!
82121
83122
===== Waiting for Validator Signature =====
84123
The 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
167179
The 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");
176197
const 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
222234
interface 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

Comments
 (0)