Skip to main content

Complete policy evaluation and transaction submission

For this walkthrough, we’ll use a web application as an example, though most other services require only a subset of these steps.
1

Backend Integration

Fetching Predicate Attestations requires an API key that must be secured. Using a passthrough proxy is best practice!
2

Frontend Integration

Embed the Predicate Attestation into the transaction object, allowing users to self-authorize onchain.

Mental model

  • With specific transaction information, your backend requests the PredicateAPI for an attestation.
  • The PredicateAPI returns a message detailing if the request is compliant and a corresponding attestation.
  • Your frontend includes that message when calling a predicated contract function.
  • EVM
  • SVM

Backend Integration

Store your API key on the server, call the Predicate API, and return the attestation to the client. The examples show representative payloads; adapt the function signature/args for your app.
Example Backend Proxy (EVM)
import express from 'express';
import fetch from 'node-fetch';
import { packFunctionArgs } from '@predicate/core';

const app = express();
app.use(express.json());

app.post('/api/predicate/attestation', async (req, res) => {
  const { from, to, functionArgs, chain = 'sepolia' } = req.body;
  try {
    // Encode the internal function invoked by your predicated function (example shown)
    const data = packFunctionArgs('sendCoin(address,uint256)', functionArgs);

    const resp = await fetch('https://api.predicate.io/v2/attestation', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.PREDICATE_API_KEY as string,
      },
      body: JSON.stringify({ to, from, data, msg_value: '0x0', chain }),
    });

    if (!resp.ok) {
      const err = await resp.text();
      return res.status(resp.status).send(err);
    }

    const result = await resp.json();
    if (!result.is_compliant) {
      return res.status(400).json({ error: 'Transaction not compliant', details: result });
    }

    res.json({ attestation: result.attestation, policy_id: result.policy_id });
  } catch (e) {
    res.status(500).json({ error: 'Failed to evaluate policy' });
  }
});

Frontend Integration

Fetch the attestation from your backend and pass it to your predicated function.
Frontend (EVM)
// 1) Fetch attestation
const resp = await fetch('/api/predicate/attestation', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    from: userAddress,
    to: contractAddress,
    functionArgs: [receiverAddress, amount],
    chain: 'sepolia',
  }),
});
const { attestation } = await resp.json();

// 2) Call predicated function, passing Attestation struct
// function sendCoin(address to, uint256 amount, Attestation calldata attestation) external payable {}
const tx = await contract.sendCoin(
  receiverAddress,
  amount,
  {
    uuid: attestation.uuid,
    expiration: attestation.expiration,
    attester: attestation.attester,
    signature: attestation.signature,
  }
);

Next Steps

Next: Dashboard Setup to configure your organization and test the integration.