Data Access Module

First, let's walk through the workflow for adding historical receipt/tx/storage data to your app via the Brevis TypeScript SDK which offers a convenient way for NodeJS to interact with the prover service and Brevis' system.

Install the Dependency

npm install brevis-sdk-typescript

Adding Source Data

Initialize a Proof Request to Your Prover Service

import { ProofRequest, Prover } from 'brevis-sdk-typescript';
// Assuming you started your prover service on port 33247, this is how you 
// initialize a client in your NodeJS program to interact with it.
const prover = new Prover('localhost:33247');

const proofReq = new ProofRequest();

Add the Data to the Proof Request

Depending on your project, you may want to first query an indexer, such as Dune, an Ethereum node, or your own service, to acquire the raw data (such as transactions) according to your business logic. This part is not handled by the Brevis SDK.

So why can't we just use the indexer data directly on chain?

If you directly post the data from an indexer to your contract without any validity proofs, your users would be trusting the entity who posted this data to behave correctly. Brevis's core role is to replace this trust of data validity on one party with a ZK proof so no one can fabricate data and computation results.

After you acquire the raw data, you add the data to the proofReq. The data you add here is closely tied to how you allocate data slots for your circuit and is available in CircuitInput passed in to your Define function. how to write an application circuit

proofReq.addReceipt(
    new ReceiptData({
        block_num: 18064070,
        tx_hash: '0x53b37ec7975d217295f4bdadf8043b261fc49dccc16da9b9fc8b9530845a5794',
        fields: [
            new Field({
                contract: '0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640',
                log_index: 3,
                event_id: '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67',
                is_topic: false,
                field_index: 0,
                value: '724999999',
            }),
            new Field({
                contract: '0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640',
                log_index: 3,
                event_id: '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67',
                is_topic: true,
                field_index: 2,
                value: '0xEf1c6E67703c7BD7107eed8303Fbe6EC2554BF6B',
            }),
            new Field({
                contract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
                log_index: 2,
                event_id: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
                is_topic: true,
                field_index: 1,
                value: '0xaefB31e9EEee2822f4C1cBC13B70948b0B5C0b3c',
            }),
        ],
    }),
);
proofReq.addStorage(
    new StorageData({
        block_num: 18233760,
        address: '0x5427FEFA711Eff984124bFBB1AB6fbf5E3DA1820',
        slot: '0x0000000000000000000000000000000000000000000000000000000000000000',
        value: '0xf380166f8490f24af32bf47d1aa217fba62b6575',
    }),
);
proofReq.addTransaction(
    new TransactionData({
        hash: '0x6dc75e61220cc775aafa17796c20e49ac08030020fce710e3e546aa4e003454c',
        chain_id: 1,
        block_num: 19073244,
        nonce: 0,
        gas_tip_cap_or_gas_price: '90000000000',
        gas_fee_cap: '90000000000',
        gas_limit: 21000,
        from: '0x6c2843bA78Feb261798be1AAC579d1A4aE2C64b4',
        to: '0x2F19E5C3C66C44E6405D4c200fE064ECe9bC253a',
        value: '22329290000000000',
    }),
);

Add Custom Inputs

If you define custom inputs for your circuit, you need to fully assign them here in ProofRequest.

// circuit custom input definition
type AppCircuit struct{
    // example custom field `MerkleProof`
    MerkleProof [8]sdk.Bytes32
}
// assigning custom input in typescript
proofReq.setCustomInput({
    // key names match what we defined in AppCircuit
    MerkleProof: [
        // type of the field should also match what we define in AppCircuit
        asBytes32('0x1111111111111111111111111111111111111111111111111111111111111111'),
        asBytes32('0x2222222222222222222222222222222222222222222222222222222222222222'),
        // ...
    ],
});

The keys of the custom input object you add in typescript matches what you define in your app circuit. The first letter can also be lower cased, e.g. merkleProof in the above example

Custom Input Types

The types of the custom input you assign in ProofRequest must match what you define in your app circuit. All primitive circuit data types are allowed here through the following functions.

For example, if your AppCircuit is defined as

type AppCircuit struct {
    MyUint248Input1 sdk.Uint248
    MyUint248Input2 sdk.Uint248
    MyUint521Input1 sdk.Uint521
    MyUint521Input2 sdk.Uint521
    MyInt248Input sdk.Int248
    MyBytes32Input sdk.bytes32
}

In your Typescript program you would need to assign the custom input as

proofReq.setCustomInput({
    MyUint248Input1: asUint248('123'),
    // 0x prefixed hex input is also allowed
    MyUint248Input2: asUint248('0xabcdef'),
    MyUint521Input1: asUint521('123'),
    // 0x prefixed hex input is also allowed
    MyUint521Input2: asUint521('0xabcdef'),
    MyInt248Input: asInt248('-123'),
    MyBytes32Input: asBytes32('0x3333333333333333333333333333333333333333333333333333333333333333'),
});

The data you add here will be available for use in your Application Circuit.

Read more about Source Data Types.

For advanced developers, there is also a way to access the receipt/tx/storage data via the Go SDK. See Go Workflow for details.

Last updated