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
Copy
struct DecryptionAttestation {
bytes32 handle;
bytes32 value;
}
Attested Decrypt
Off-chain (JS SDK):- example.ts
- client.ts
- abi.ts
Copy
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,
]);
Copy
import { createWalletClient, http } from "viem";
import { baseSepolia } from "viem/chains";
import { Lightning, supportedChains } from "@inco/js";
export const walletClient = createWalletClient({
chain: baseSepolia,
transport: http(),
});
export const zap = await Lightning.latest(
"testnet",
supportedChains.baseSepolia
);
Copy
export const gatedAccessAbi = [
{
inputs: [
{
components: [
{
internalType: "bytes32",
name: "handle",
type: "bytes32",
},
{
internalType: "bytes32",
name: "value",
type: "bytes32",
},
],
internalType: "struct DecryptionAttestation",
name: "decryption",
type: "tuple",
},
{
internalType: "bytes[]",
name: "signatures",
type: "bytes[]",
},
],
name: "gatedAction",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
] as const;
Copy
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):- example.ts
- client.ts
- abi.ts
Copy
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,
]);
Copy
import { createWalletClient, http } from "viem";
import { baseSepolia } from "viem/chains";
import { Lightning, supportedChains } from "@inco/js";
export const walletClient = createWalletClient({
chain: baseSepolia,
transport: http(),
});
export const zap = await Lightning.latest(
"testnet",
supportedChains.baseSepolia
);
Copy
export const revealAbi = [
{
inputs: [
{
components: [
{
internalType: "bytes32",
name: "handle",
type: "bytes32",
},
{
internalType: "bytes32",
name: "value",
type: "bytes32",
},
],
internalType: "struct DecryptionAttestation",
name: "decryption",
type: "tuple",
},
{
internalType: "bytes[]",
name: "signatures",
type: "bytes[]",
},
],
name: "submitRevealedValue",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
] as const;
Copy
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 examplehandleB = handleA.ge(700)), and then returns a decryption attestation
for that result handle. On-chain you verify that:
- the attestation is valid,
- the
decryption.handlematches the expected computed handle (e.g.handleB), - and the decrypted value of
handleBsatisfies your predicate.
- example.ts
- client.ts
- abi.ts
Copy
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,
]);
Copy
import { createWalletClient, http } from "viem";
import { baseSepolia } from "viem/chains";
import { Lightning, supportedChains } from "@inco/js";
export const walletClient = createWalletClient({
chain: baseSepolia,
transport: http(),
});
export const zap = await Lightning.latest(
"testnet",
supportedChains.baseSepolia
);
Copy
export const creditCheckAbi = [
{
inputs: [
{
components: [
{
internalType: "bytes32",
name: "handle",
type: "bytes32",
},
{
internalType: "bytes32",
name: "value",
type: "bytes32",
},
],
internalType: "struct DecryptionAttestation",
name: "decryption",
type: "tuple",
},
{
internalType: "bytes[]",
name: "signatures",
type: "bytes[]",
},
],
name: "submitCreditCheck",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
] as const;
Copy
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
}
}