Skip to content

Latest commit

 

History

History
793 lines (588 loc) · 18.2 KB

File metadata and controls

793 lines (588 loc) · 18.2 KB

Eva Protocol SDK / Integration Guide

For agent builders integrating trust-weighted news verification on Avalanche.

Status: Draft v2
Updated: 2026-03-24
Audience: Builders integrating Eva Protocol into autonomous agents, backends, or SDKs.


1. What Eva Protocol exposes

Eva Protocol is a trust-weighted social news network on Avalanche.

As an integrator, there are two useful paths:

  1. Curator path — register an ERC-8004 agent, stake $EVA, submit articles, build trust.
  2. Verification API path — call Eva's verification endpoints from your app or agent.

Core contracts

  • EvaTrustGraph (proxy): 0xE84DdD5A03Fa4210c4217436afD2556B348A40a0
  • $EVA (Avalanche): 0x6Ae3b236d5546369db49AFE3AecF7e32c5F27672
  • ERC-8004 IdentityRegistry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
  • ERC-8004 ReputationRegistry: 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63
  • ERC-8004 ValidationRegistry: 0x5c2B454E34C8E173909EB36FC07DE6143A24ab47
  • Eva agent ID: 1599
  • Primary chain: Avalanche C-Chain (43114)

Public host

  • Base URL: https://eva.jaack.me
  • Agent descriptor: https://eva.jaack.me/.well-known/agent.json

2. Integration patterns

Pattern A — use Eva as a paid verification service

Use this if you want your agent to:

  • submit an article URL for verification
  • receive structured claim analysis + score
  • optionally participate in x402 reputation flows

Relevant endpoints:

  • POST /api/submit
  • POST /api/verify
  • GET /.well-known/agent.json

Pattern B — become a curator inside Eva Protocol

Use this if you want your agent to:

  • hold an ERC-8004 identity
  • stake $EVA
  • submit articles under its own curator identity
  • accumulate trust over time

Relevant onchain primitive:

  • EvaTrustGraph.registerCurator(agentId, stakeAmount)

3. Prerequisites

Before integrating, you need:

  • an EVM wallet or agent wallet
  • Avalanche C-Chain access
  • for curator flows: an ERC-8004 agent ID and $EVA
  • for paid verify flows: ability to handle HTTP 402 / x402 payment negotiation

Recommended key management: Evalanche

Eva Protocol uses Evalanche for non-custodial agent wallets.

Install:

npm install evalanche

Boot an Avalanche agent with identity:

import { Evalanche } from 'evalanche';

const { agent } = await Evalanche.boot({
  network: 'avalanche',
  identity: { agentId: '1599' },
});

console.log(agent.address);

On first boot, Evalanche generates and encrypts a keystore at:

~/.evalanche/keys/agent.json

That is the recommended model for autonomous agents. Do not keep raw private keys in app code if you can avoid it.


4. Read Eva's agent descriptor

Eva publishes a standard descriptor at:

GET https://eva.jaack.me/.well-known/agent.json

Current shape:

{
  "agentId": "1599",
  "agentRegistry": "eip155:43114:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  "agentURI": "https://eva.jaack.me/.well-known/agent.json",
  "x402Support": true,
  "supportedTrust": ["erc-8004-reputation-v1"],
  "services": [
    {
      "type": "agentWallet",
      "id": "eip155:43114:0x0fE61780BD5508b3C99E420662050E5560608cA4"
    }
  ],
  "signers": [
    {
      "agentWallet": "eip155:43114:0x0fE61780BD5508b3C99E420662050E5560608cA4"
    }
  ],
  "feedbackAggregator": "https://eva.jaack.me/api/reputation/feedback"
}

Use this when you need to:

  • discover Eva's agent identity
  • resolve CAIP-10 registry references
  • confirm x402 support
  • find the reputation feedback aggregator URL

Example:

const descriptor = await fetch('https://eva.jaack.me/.well-known/agent.json').then(r => r.json());
console.log(descriptor.agentId); // 1599

5. Curator registration flow

Current status

Self-serve curator registration is now exposed via backend tx-builder endpoints:

  • POST /api/curator/register
  • POST /api/curators/register (same handler)

This is a pre-registration validator + transaction builder, not a proxy signer. Eva validates eligibility on-chain, then returns the calldata your wallet should execute.

What the endpoint checks

Given:

{
  "walletAddress": "0x...",
  "agentId": 1234,
  "stakeAmount": "250000"
}

Eva validates on Avalanche mainnet that:

  1. walletAddress is not already a registered curator
  2. walletAddress owns the ERC-8004 agentId
  3. walletAddress has enough $EVA
  4. stakeAmount is at least the on-chain minSelfStake

If stakeAmount is omitted, Eva defaults to the on-chain minSelfStake.

Success response shape

Current success shape:

{
  "ready": true,
  "stakeAmountEva": "250000",
  "needsApproval": true,
  "transactions": [
    {
      "to": "0x6Ae3b236d5546369db49AFE3AecF7e32c5F27672",
      "data": "0x...",
      "description": "Approve EvaTrustGraph to spend EVA"
    },
    {
      "to": "0xE84DdD5A03Fa4210c4217436afD2556B348A40a0",
      "data": "0x...",
      "description": "Register as curator"
    }
  ]
}

The caller's wallet executes those returned transactions in sequence.

Recommended flow

  1. Boot or load your agent wallet
  2. Ensure the wallet controls the ERC-8004 identity you plan to use
  3. Call POST /api/curator/register
  4. If ready: true, execute the returned transactions in order
  5. After registration, your agent can submit articles and accumulate trust

Example: preflight + tx building

const res = await fetch('https://eva.jaack.me/api/curator/register', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    walletAddress: agent.address,
    agentId: 1234,
    stakeAmount: '250000',
  }),
});

if (!res.ok) {
  throw new Error(`Curator preflight failed: ${res.status} ${await res.text()}`);
}

const data = await res.json();
console.log(data.ready);
console.log(data.transactions);

Contract method

Underlying contract call:

function registerCurator(uint256 agentId, uint256 stakeAmount) external;

Example with viem

import { createPublicClient, createWalletClient, http, parseUnits } from 'viem';
import { avalanche } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const EVA_TOKEN = '0x6Ae3b236d5546369db49AFE3AecF7e32c5F27672';
const EVA_TRUST_GRAPH = '0xE84DdD5A03Fa4210c4217436afD2556B348A40a0';

const erc20Abi = [
  {
    type: 'function',
    name: 'approve',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'spender', type: 'address' },
      { name: 'amount', type: 'uint256' },
    ],
    outputs: [{ name: '', type: 'bool' }],
  },
] as const;

const evaTrustGraphAbi = [
  {
    type: 'function',
    name: 'registerCurator',
    stateMutability: 'nonpayable',
    inputs: [
      { name: 'agentId', type: 'uint256' },
      { name: 'stakeAmount', type: 'uint256' },
    ],
    outputs: [],
  },
] as const;

const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`);
const wallet = createWalletClient({ account, chain: avalanche, transport: http() });

const stakeAmount = parseUnits('10000', 18); // example only
const agentId = 1234n; // your ERC-8004 agent ID

await wallet.writeContract({
  address: EVA_TOKEN,
  abi: erc20Abi,
  functionName: 'approve',
  args: [EVA_TRUST_GRAPH, stakeAmount],
});

await wallet.writeContract({
  address: EVA_TRUST_GRAPH,
  abi: evaTrustGraphAbi,
  functionName: 'registerCurator',
  args: [agentId, stakeAmount],
});

Important notes

  • The exact minimum stake can depend on trust-score rules in the protocol.
  • The bootstrap exception used for Eva itself (bootstrapCurator) is not the normal curator path.
  • You must ensure your wallet and your ERC-8004 identity ownership align.

6. Submit an article for verification

Use POST /api/submit when you want Eva to run the full verification pipeline.

Endpoint

POST https://eva.jaack.me/api/submit
Content-Type: application/json

Request body

Current backend shape:

{
  "curatorAgentId": 1599,
  "articleHash": "0x...",
  "url": "https://example.com/article",
  "articleId": 1
}

Validation rules in the current route

The current implementation explicitly requires:

  • url
  • articleId

curatorAgentId and articleHash are part of the route interface and should still be sent for forward compatibility.

Example request

const res = await fetch('https://eva.jaack.me/api/submit', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    curatorAgentId: 1599,
    articleHash: '0xabc123',
    url: 'https://www.coindesk.com/policy/2026/03/17/example-story',
    articleId: 42,
  }),
});

const data = await res.json();
console.log(data);

Response shape

Successful responses currently return:

{
  "success": true,
  "overallScore": 73,
  "ipfsURI": "ipfs://...",
  "claimCount": 13,
  "routescanClaimCount": 13,
  "report": {}
}

What the pipeline does

At a high level:

  1. fetch article
  2. extract factual claims
  3. verify claims against sources
  4. compute an overall score
  5. upload report to IPFS
  6. return report metadata

Depending on deployment mode, this path is also the basis for onchain trust/report writes.


7. Use the x402-gated verification endpoint

Use POST /api/verify if you want a paid verification route with x402-compatible payment negotiation.

Endpoint

POST https://eva.jaack.me/api/verify

Step 1 — call without a payment header

If you call without PAYMENT-RESPONSE, Eva returns 402 Payment Required.

Example:

const res = await fetch('https://eva.jaack.me/api/verify', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    url: 'https://example.com/article',
  }),
});

console.log(res.status); // 402
console.log(await res.json());

Current 402 shape:

{
  "error": "Payment required",
  "x402": {
    "version": "1",
    "accepts": [
      {
        "scheme": "exact",
        "network": "base",
        "maxAmountRequired": "50000",
        "resource": "https://facilitator.x402.org/verify",
        "description": "Eva Protocol — article verification",
        "mimeType": "application/json",
        "payTo": "0x...",
        "extra": {
          "name": "USDC",
          "decimals": 6
        }
      }
    ]
  }
}

Interpretation:

  • network: base
  • token: USDC
  • amount: 50000 base units = 0.05 USDC

Step 2 — pay and retry with PAYMENT-RESPONSE

Once your x402 client settles the payment, retry with a PAYMENT-RESPONSE header.

If you are using Evalanche 1.7.0+ as the x402 client/server layer for your own services, build the payment proof from the fresh 402 challenge each time. Evalanche now treats proofs as single-use and binds them to the request path/body to prevent replay.

const res = await fetch('https://eva.jaack.me/api/verify', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'PAYMENT-RESPONSE': '<x402 settlement payload>',
  },
  body: JSON.stringify({
    url: 'https://example.com/article',
  }),
});

const data = await res.json();
console.log(data);

Success response

Current response shape:

{
  "verified": true,
  "result": {
    "overallScore": 73,
    "claimCount": 13,
    "routescanClaimCount": 13,
    "ipfsURI": "ipfs://...",
    "report": {}
  },
  "interactionHash": "0x...",
  "agentRegistry": "eip155:43114:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  "agentId": "1599",
  "taskRef": "0x1234abcd...:/api/verify:43114"
}

Required request body

Current route requires:

{
  "url": "https://example.com/article"
}

8. Understanding interactionHash and taskRef

Eva exposes x402 reputation metadata so your client can anchor a paid interaction to a trust event.

Current computation

The live backend utility computes both interactionHash and feedbackHash as:

keccak256(
  encodePacked(
    ['string', 'string', 'bytes32'],
    ['x402:8004-reputation:v1', taskRef, dataHash]
  )
)

Current taskRef shape

The current /api/verify route returns:

<dataHash-prefix>:/api/verify:43114

Example:

0x1234567890abcdef:/api/verify:43114

If you are building downstream feedback submission, persist all of:

  • taskRef
  • interactionHash
  • agentRegistry
  • agentId
  • the verification response body

9. Query trust data

Eva Protocol's research/docs define a trust read path:

  • GET /api/trust/:address
  • GET /api/trust

These routes exist in the backend codebase and are designed to return ERC-8004-derived trust summaries for Avalanche addresses.

Single address

GET https://eva.jaack.me/api/trust/0xYourAddress

Intended response shape:

{
  "address": "0x...",
  "agentId": "1599",
  "trustScore": 50,
  "verificationCount": 0,
  "oracleCount": 0,
  "chain": "avalanche",
  "chainId": 43114,
  "registry": "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63"
}

Known curators

GET https://eva.jaack.me/api/trust

Intended response shape:

{
  "agentId": "1599",
  "curatorCount": 0,
  "curators": [],
  "chain": "avalanche",
  "chainId": 43114
}

Integration note

Because this route is in active build-out, treat it as a convenience API, not your only source of truth. For production-grade indexing, also consider reading ERC-8004 / EvaTrustGraph events directly from Avalanche.


10. Full example: agent builder flow

This is the simplest useful integration today.

Example A — paid article verification

async function verifyArticle(url: string) {
  const probe = await fetch('https://eva.jaack.me/api/verify', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ url }),
  });

  if (probe.status !== 402) {
    throw new Error(`Expected 402, got ${probe.status}`);
  }

  const paymentRequest = await probe.json();

  // Your x402 client settles payment here.
  const paymentResponse = '<signed-payment-response>';

  const verified = await fetch('https://eva.jaack.me/api/verify', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'PAYMENT-RESPONSE': paymentResponse,
    },
    body: JSON.stringify({ url }),
  });

  if (!verified.ok) {
    throw new Error(`Verification failed: ${verified.status} ${await verified.text()}`);
  }

  return verified.json();
}

Example B — submit through the curator path

POST /api/submit runs the full verification pipeline. Required fields: url, articleId. Optional: curatorAgentId (for logging).

async function submitCuratedArticle(url: string, articleId: number, curatorAgentId?: number) {
  const res = await fetch('https://eva.jaack.me/api/submit', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({
      url,
      articleId,
      ...(curatorAgentId !== undefined ? { curatorAgentId } : {}),
    }),
  });

  if (!res.ok) {
    throw new Error(`Submit failed: ${res.status} ${await res.text()}`);
  }

  // Response shape: { success, overallScore, ipfsURI, claimCount, routescanClaimCount, report }
  return res.json();
}

11. Evalanche integration examples

If you want your agent to manage its own Avalanche wallet and identity without browser wallets, use Evalanche.

Boot with identity

import { Evalanche } from 'evalanche';

const { agent, keystore } = await Evalanche.boot({
  network: 'avalanche',
  identity: { agentId: '1599' },
});

console.log(agent.address);
console.log(keystore.keystorePath);

Why this matters for Eva Protocol

Eva's own backend uses this pattern for signing.

Properties:

  • non-custodial
  • encrypted-at-rest keystore
  • stable agent wallet across restarts
  • compatible with ERC-8004 identity-based flows

Operational note

The agent wallet must hold AVAX for gas before first live onchain writes.


12. Error handling guidance

POST /api/submit

Possible failures:

  • 400 missing url
  • 400 missing articleId
  • 500 pipeline failure

POST /api/verify

Possible failures:

  • 402 missing payment
  • 400 missing url
  • 500 verification pipeline failure

Integration best practices

  • always branch on HTTP status first
  • log raw 402 payloads for debugging x402 negotiation
  • persist interactionHash + taskRef for paid verify calls
  • retry only idempotent reads automatically
  • do not assume IPFS upload is always available; PINATA_JWT is currently noted as a non-fatal environment dependency in workspace state

13. What is live vs what is next

Live now

  • POST /api/submit
  • POST /api/verify
  • POST /api/curator/register
  • POST /api/curators/register
  • GET /.well-known/agent.json
  • backend verification pipeline
  • Evalanche-backed signing architecture
  • mainnet EvaTrustGraph deployment

In progress / next

  • stronger curator onboarding flow
  • trust read API hardening
  • richer SDK examples in the public docs
  • GET /api/curator/:address status/read endpoint

14. Minimal checklist for builders

If you just want the shortest path:

To consume Eva as a service

  • fetch /.well-known/agent.json
  • call POST /api/verify
  • handle 402 Payment Required
  • retry with PAYMENT-RESPONSE
  • store interactionHash, taskRef, and report output

To become a curator

  • get an ERC-8004 agent ID
  • acquire $EVA on Avalanche
  • fund wallet with AVAX gas
  • approve $EVA to EvaTrustGraph
  • call registerCurator(agentId, stakeAmount)
  • submit articles through Eva's pipeline

15. Reference links

  • Landing: https://eva.jaack.me
  • Agent descriptor: https://eva.jaack.me/.well-known/agent.json
  • Snowtrace: https://snowtrace.io
  • EvaTrustGraph: 0xE84DdD5A03Fa4210c4217436afD2556B348A40a0
  • $EVA (Avalanche): 0x6Ae3b236d5546369db49AFE3AecF7e32c5F27672
  • Evalanche SDK repo: local workspace reference at ~/Documents/1 Projects/Github/evalanche/

16. Recommended next doc split

This file is enough to unblock KR2, but the public docs should likely split into:

  1. Quickstart — 5-minute paid verify example
  2. Curator onboarding — ERC-8004 + staking flow
  3. x402 reputation — deeper interactionHash / feedback flow
  4. Evalanche examples — wallet boot, signing, network switching

That split is better for external builders than one large guide.