Skip to main content
Attested flows (attestedDecrypt, attestedCompute, attestedReveal) allow wallets to convert an encrypted handle into plaintext or a computed result. This page shows how to plug those responses into Solidity, verify the covalidator signatures, and bind attestations to the expected handles.

DecryptionAttestation Structure

struct DecryptionAttestation {
    bytes32 handle;
    bytes32 value;
}

Attested Decrypt

Off-chain (JS SDK):
import { getContract } from "viem";
import { gatedAccessAbi } from "./abi";
import { walletClient } from "./client";

// 1. Create contract instance
const contract = getContract({
  address: "0x...", // Replace with your deployed contract address
  abi: gatedAccessAbi,
  client: walletClient,
});

// 2. Use attested decrypt and call contract
const results = await zap.attestedDecrypt(walletClient, [handleHex]);
const { handle, plaintext, covalidatorSignatures } = results[0];
const { value } = plaintext;

await contract.write.gatedAction([
  {
    handle,
    value,
  },
  covalidatorSignatures,
]);
On-chain (Solidity):
import {DecryptionAttestation} from "@inco/lightning/src/lightning-parts/DecryptionAttester.types.sol";
import {inco, ebool} from "@inco/lightning/src/Lib.sol";
import {asBool} from "@inco/lightning/src/shared/TypeUtils.sol";

contract GatedAccess {
    mapping(address => ebool) internal userAllowed;

    function gatedAction(
        DecryptionAttestation memory decryption,
        bytes[] memory signatures
    ) external {
        require(
            inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures),
            "Invalid signature"
        );
        require(ebool.unwrap(userAllowed[msg.sender]) == decryption.handle, "Handle mismatch");
        require(asBool(decryption.value) == true, "Not allowed");

        // proceed
    }
}

Attested Reveal

Off-chain (JS SDK):
import { getContract } from "viem";
import { revealAbi } from "./abi";
import { walletClient } from "./client";

// 1. Create contract instance
const contract = getContract({
  address: "0x...", // Replace with your deployed contract address
  abi: revealAbi,
  client: walletClient,
});

// 2. Use attested reveal and call contract
const results = await zap.attestedReveal([handleHex]);
const { handle, plaintext, covalidatorSignatures } = results[0];
const { value } = plaintext;

await contract.write.submitRevealedValue([
  {
    handle,
    value,
  },
  covalidatorSignatures,
]);
On-chain (Solidity):
import {DecryptionAttestation} from "@inco/lightning/src/lightning-parts/DecryptionAttester.types.sol";
import {inco, e, ebool, euint256} from "@inco/lightning/src/Lib.sol";
import {asBool} from "@inco/lightning/src/shared/TypeUtils.sol";

contract GatedAccess {
    using e for *;

    euint256 someHandle;
    function submitRevealedValue(
        DecryptionAttestation memory decryption,
        bytes[] memory signatures
    ) external {
        require(
            inco.incoVerifier().isValidDecryptionAttestation(
                decryption,
                signatures
            ),
            "Invalid signature"
        );
        require(
            euint256.unwrap(someHandle) == decryption.handle,
            "Handle mismatch"
        );

        uint256 revealedValue = uint256(decryption.value);
        // use revealedValue
    }
}

Attested Compute

Attested compute first produces a computed handle (for example handleB = handleA.ge(700)), and then returns a decryption attestation for that result handle. On-chain you verify that:
  • the attestation is valid,
  • the decryption.handle matches the expected computed handle (e.g. handleB),
  • and the decrypted value of handleB satisfies your predicate.
Off-chain (JS SDK):
import { getContract } from "viem";
import { creditCheckAbi } from "./abi";
import { walletClient } from "./client";

// 1. Create contract instance
const contract = getContract({
  address: "0x...", // Replace with your deployed contract address
  abi: creditCheckAbi,
  client: walletClient,
});

// 2. Read encrypted credit score handle
const creditScoreHandle = await contract.read.userCreditScore([
  walletClient.account.address,
]);

// 3. Off-chain check: is credit score >= 700?
const { handle, plaintext, covalidatorSignatures } = await zap.attestedCompute(
  walletClient,
  creditScoreHandle,
  AttestedComputeSupportedOps.Ge,
  700n
);

const { value } = plaintext; // always boolean
await contract.write.submitCreditCheck([
  {
    handle,
    value,
  },
  covalidatorSignatures,
]);
On-chain (Solidity):
import {DecryptionAttestation} from "@inco/lightning/src/lightning-parts/DecryptionAttester.types.sol";
import {inco, e, ebool, euint256} from "@inco/lightning/src/Lib.sol";
import {asBool} from "@inco/lightning/src/shared/TypeUtils.sol";

contract GatedAccess {
    using e for *;

    // Encrypted credit score handle stored on-chain for each user
    mapping(address => euint256) internal userCreditScore;

    function submitCreditCheck(
        DecryptionAttestation memory decryption,
        bytes[] memory signatures
    ) external {
        // 1. Verify covalidator signatures over the attested result
        require(
            inco.incoVerifier().isValidDecryptionAttestation(
                decryption,
                signatures
            ),
            "Invalid signature"
        );

        // 2. Recompute the expected "creditScore >= 700" handle on-chain
        euint256 creditScore = userCreditScore[msg.sender];
        require(
            ebool.unwrap(creditScore.ge(700)) == decryption.handle,
            "Computed handle mismatch"
        );

        // 3. Check that the decrypted boolean is true
        require(asBool(decryption.value) == true, "Credit check failed");

        // proceed with approval
    }
}