@verify-network/contracts
v0.2.0
Published
The Verify Network router a consumer builds against: viem-ready ABIs, the creation bytecode a local deploy of the router diamond takes, diamond cut helpers, and the Solidity consumer interfaces.
Readme
@verify-network/contracts
What a consumer of the Verify Network router builds against. It holds the Solidity interfaces a consumer imports, the viem-ready ABIs of the router's facets, and the creation bytecode and diamond cut helpers for deploying the router yourself.
Install
npm install @verify-network/contracts viemviem (^2.56.3) is a peer dependency. Node 22 or later.
Solidity interfaces
| Import | Contents |
| -------------------------------------------------------------- | ------------------------------------------------------------------- |
| @verify-network/contracts/contracts/IVerifyNetworkRouter.sol | The router functions a consumer calls: the requests and the balance |
| @verify-network/contracts/contracts/IVrfReceiver.sol | The callback a consumer implements to receive randomness |
| @verify-network/contracts/contracts/IDirectVrfReceiver.sol | The callback a consumer implements to receive direct requests |
Hardhat 3 resolves these paths from node_modules as they are. Foundry needs one remapping:
@verify-network/contracts/=node_modules/@verify-network/contracts/A minimal consumer:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import {IVerifyNetworkRouter} from "@verify-network/contracts/contracts/IVerifyNetworkRouter.sol";
import {IVrfReceiver} from "@verify-network/contracts/contracts/IVrfReceiver.sol";
contract Lottery is IVrfReceiver {
IVerifyNetworkRouter public immutable router;
address public immutable owner;
error OnlyRouter(address caller);
constructor(IVerifyNetworkRouter router_) {
router = router_;
owner = msg.sender;
}
/// Requests from this contract's balance on the router. The round travels as callback data.
function draw(uint256 round) external returns (bytes32 requestId) {
requestId = router.requestRandomness(abi.encode(round), 200_000);
}
/// The router calls this with exactly the callback gas limit of the request.
function onRandomnessFulfilled(bytes32, bytes32 randomness, bytes calldata callbackData) external {
if (msg.sender != address(router)) revert OnlyRouter(msg.sender);
uint256 round = abi.decode(callbackData, (uint256));
// settle `round` with `randomness`
}
/// Refunds of stale requests land on this contract's balance on the router.
function withdrawBalance(address recipient, uint256 amount) external {
require(msg.sender == owner);
router.withdraw(recipient, amount);
}
}Fund it once with router.deposit(address(lottery)). It pays for each request from that balance. Two rules apply to every consumer:
- Only the router may call the callback. Nothing else authenticates the randomness.
- Give the consumer a way to withdraw. A stale request's refund goes to the consumer's balance on the router, even when the request was paid with
msg.value.
The router stores only the request id. Your callback data is hashed into it and returned to your callback verbatim, so a consumer may keep its whole pending state there, up to 16 KiB.
ABIs
Each ABI is the default export of @verify-network/contracts/abi/<Contract>, typed as const for viem:
| ABI | Use |
| ---------------------- | -------------------------------------------------------------------------- |
| VrfFacet | Requests, fulfillments, stale reports, challenges, and the router's events |
| BalancesFacet | deposit, withdraw, balanceOf |
| ConfigFacet | pricing(), the stake, and the admin's settings |
| NodesFacet | The active set, node keys (publicKeyOf), and endpoints (endpointOf) |
| IVerifyNetworkRouter | The consumer's subset of the router |
| IVrfReceiver | The on-chain request callback |
| IDirectVrfReceiver | The direct request callback |
The router is an EIP-2535 diamond, so every facet lives at the router's address.
import BalancesFacet from "@verify-network/contracts/abi/BalancesFacet";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";
const publicClient = createPublicClient({ chain: base, transport: http() });
const balance = await publicClient.readContract({
address: "0x…", // the router
abi: BalancesFacet,
functionName: "balanceOf",
args: ["0x…"], // the consumer
});
console.log(balance);Deploy the router yourself
@verify-network/contracts/artifacts holds the ABI and creation bytecode of every contract a router deployment needs: Router, RouterInit, ECVRFVerifier, TrustedNodeEnclaveKeyVerifier, the facets in FACETS, and the Nitro stack a chain preset deploys beside the router (SP1VerifierGroth16, NitroEnclaveVerifier, NitroAttestationVerifier). Each one is in the shape viem's deployContract takes.
@verify-network/contracts/diamond holds the EIP-2535 helpers. DIAMOND_ACTIONS and facetSelectors build the first diamondCut. planFacetCut and facetCuts plan an in-place upgrade of one facet from the diamond loupe. They refuse a selector that another facet already serves.
To test a consumer against a local router, use @verify-network/local. It deploys these artifacts and runs a node that fulfills requests.
License
MIT
