Contract Integration

Write the custom app contract that integrates with Brevis SDK.

The final step is to write a smart contract that handles the ZK-attested results. To streamline this process, you can use the contract SDK and implement the handleProofResult function to process the circuit outputs.

npm install brevis-contracts

Here is an example of a typical app contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@brevis-network/contract-sdk/lib/BrevisApp.sol";

contract MyAppContract is BrevisApp, Ownable {
    bytes32 public vkHash;

    constructor(address brevisRequest) 
        BrevisApp(brevisRequest) 
        Ownable(msg.sender) {}

    // BrevisQuery contract will call our callback once Brevis backend submits 
    // the proof.
    function handleProofResult(
        bytes32 _vkHash,
        bytes calldata _circuitOutput
    ) internal override {
        // We need to check if the verifying key that Brevis used to verify the 
        // proof generated by our circuit is indeed the verifying key generated
        // from compiling our app circuit. This ensures that the _circuitOutput 
        // is authentic.
        require(vkHash == _vkHash, "invalid vk");

        (address minBlockNum, uint64 sum) = decodeOutput(_circuitOutput);
        
        // other logic that uses the proven data...
    }

    // Suppose in the app circuit you have:
    // api.OutputUint(64, minBlockNum)
    // api.OutputUint(248, sum)
    // Then, we can decode the output the following way
    function decodeOutput(
        bytes calldata output
    ) internal pure returns (uint64, uint248) {
        uint64 minBlockNum = uint64(bytes8(output[0:8])); 
        uint248 sum = uint248(bytes31(output[8:8+31])); 
        return (minBlockNum, sum);
    }

    function setVkHash(bytes32 _vkHash) external onlyOwner {
        vkHash = _vkHash;
    }
}

Handling Circuit Outputs in Contract

Your app contract needs to inherit the BrevisApp contract and call its constructor with the address of the BrevisProof contract (Deployment Addresses). It also needs to override the abstract method handleProofResult.

function handleProofResult(
    bytes32 _requestId, 
    bytes32 _vkHash, 
    bytes calldata _appCircuitOutput
) internal virtual {}

Checking the Verifying Key

The vk hash you get from the Compiling & Setup step uniquely identifies of your circuit. You should save the vk hash in your contract. When handling callbacks from the BrevisRequest contract, you must check that the vkHash matches your expected one.

Reading the Circuit Output

The output calls in your circuit definition are packed in the form of abi.encodePacked(...). The order of the variables is the same as the order you call the output APIs in the circuit.

Pay Request Fee

If an application is partnered with the Brevis system to serve requests with a customized fee plan, it can skip this step and send off-chain requests directly to the Brevis gateway.

Otherwise, for most applications, the user needs to send the request with fee in native tokens on-chain to the BrevisRequest contract.

Paying the Fee

You need to call BrevisRequest.sendRequest with the requestId and the feeValue (as transaction value) you acquire from in the previous step when you call app.PrepareRequest in Go. The parameter _callback is where you specify your app contract address.

BrevisRequest contract
function sendRequest(
    bytes32 _proofId,
    uint64 _nonce,
    address _refundee,
    Callback calldata _callback,
    uint8 _option // bitmap 0: zk, 1: op bvn, 2: op avs, 3: op bvn and avs
) external payable;

struct Callback {
    address target;
    uint64 gas;
}

Or, you can send a raw transaction using the calldata you acquire from app.PrepareRequest as the transaction call data and the feeValue as the transaction value.

Refunding a Fee after Timeout

requestTimeout a state variable in BrevisRequest. If there is no proof submitted within the requestTimeout, you can call BrevisRequest.refund to refund the fee back to the _refundee you initially specified when calling sendRequest

Last updated