How it works?

vlayer introduces new super powers to Solidity smart contracts:

  • Time Travel: Execute a smart contract on historical data.
  • Teleport: Execute a smart contract across different blockchain networks.
  • Web proof: Access verified web content, including APIs and websites.
  • Email proof: Access verified email content.

Prover and Verifier

To implement the above features, vlayer introduces two new contract types: Prover and Verifier.

The Prover code runs on the vlayer zkEVM infrastructure. Proof data structure is the result of this operation.

The Verifier verifies generated proof and runs your code on EVM-compatible chains.

Both types of contracts are developed using the Solidity programming language.

vlayer contract execution

A typical vlayer execution flow has three steps:

  1. The application initiates a call to the Prover contract that is executed off-chain in the zkEVM. All the input for this call is private by default and is not published on-chain.
  2. The result of the computation is passed along with a proof to be executed in the on-chain contract. All the output returned from Prover contract is public and is published on-chain as parameters to the Verifier contract.
  3. The Verifier contract verifies the data sent by the proving party (using the submitted proof by client) and then executes the Verifier code.

See the diagram below.

Off-chain execution simplified diagram The flow of vlayer contract execution

Prover

vlayer Prover contracts have a few distinct properties:

  • verifiability - can be executed off-chain and results can't be forged.
  • privacy - inputs are private by default and are not published on-chain.
  • no gas fees - no usual transaction size limits apply.

All arguments passed to the Prover contract functions are private by default. To make an argument public, simply add it to the list of returned values.

See the example Prover contract code below. It generates proof of ownership of the BYAC (Bored Ape Yacht Club) NFT.

contract BoredApeOwnership is Prover  {
    function main(address _owner, uint256 _apeId) public returns (Proof, address) {  
      // jumps to block 12292922 at ETH mainnet (chainId=1), when BYAC where minted
      setChainId(1, 12292922); 

      require(IERC721(BYAC_NFT_ADDR).ownerOf(_apeId) == _owner, "Given address not owning that BYAC");

      return (proof(), _owner); 
    }
}

In order to access Prover specific features, your contract needs to derive from the vlayer Prover contract. Then setChainId() teleport context to a historic block at Ethereum Mainnet (chainId=1) in which the first mint of BYAC NFT occurred. require makes sure that the given address (_owner) was the owner of the specific _apeId at that point of time. The owner address, which makes it public input for the Verifier contract.

Verifier

The Verifier smart contract validates the correctness of a computation generated by Prover, without revealing the underlying information. Such contracts can be used to facilitate more complex workflows, such as privacy-preserving decentralized finance (DeFi) applications or confidential voting systems.

Verification logic is immutable once deployed on the blockchain, ensuring consistent and permissionless access.

See the example Verifer contract below. It transfers tokens to proven owner of certain NFT:

contract Airdrop is Verifier {
  function claim(Proof calldata _p, address owner) 
    public 
    onlyVerified(PROVER_VLAYER_CONTRACT_ADDR, NftOwnership.main.selector) 
  {
    IERC20(TOKEN_ADDR).transfer(owner, 1000);
  }
}

Note that the above contract inherits from the Verfier vlayer contract. It is necessary for veryfing the computation done by the Prover contract from the previous step.

claim() function takes proof returned by the vlayer SDK as the first argument. Other arguments are public inputs returned from Prover main() function (in the same order).

onlyVerified(address, bytes4) modifier ensures that proof is valid and takes two arguments:

  • Address of the Prover contract
  • Function selector of the Prover main function

Proof doesn't have to be passed to onlyVerified as an argument. However, it has to be passed as an argument to function that is being decorated with onlyVerified, along with the public outputs.


To learn more about how the Prover and Verifier work under the hood, please refer to our Advanced section.