On EVM Networks

Tutorial for using Randomness on EVM

Randomness

There's a Solidity-SDK that you can use to interact with the oracle contract on-chain and leverage customized oracle data within your smart contracts. For querying oracle randomness off-chain for on-chain submission, you can use the Switchboard On-Demand Typescript-SDK.

Prerequisites

To use Switchboard On-Demand, you will need to have a basic understanding of Ethereum and smart contracts. For more on Switchboard's Architecture, see the docs.

Installation

You can install the Switchboard On-Demand Solidity SDK by running:

npm install @switchboard-xyz/on-demand-solidity

And you can install the cross-chain Typescript SDK by running:

npm install @switchboard-xyz/on-demand

Forge (Optional)

If you're using Forge, add following to your remappings.txt file:

@switchboard-xyz/on-demand-solidity/=node_modules/@switchboard-xyz/on-demand-solidity

Step 1: Roll Randomness

The first step to using Switchboard randomness on EVM is to create the contract that will actually call into Switchboard. This requires an active Switchboard deployment. Switchboard is currently supported on the following networks:

Deployments

Making the Contract

  1. Import the Switchboard interface:

import {Structs} from "@switchboard-xyz/on-demand-solidity/structs/Structs.sol";
import {ISwitchboard} from "@switchboard-xyz/on-demand-solidity/ISwitchboard.sol";
  1. Call requestRandomness with the right parameters. Here, randomnessId just has to be a unique bytes32 of your choice. Pick the queue based on whether the network you're on is a mainnet network or not (Note: Morph Holesky uses mainnet queue).

// get the switchboard reference
ISwitchboard switchboard = ISwitchboard(_switchboard);

// [DEVNET] Switchoard Devnet Oracle Queue
bytes32 switchboardDevnetQueue =
    0xd9cd6a04191d6cd559a5276e69a79cc6f95555deeae498c3a2f8b3ee670287d1;

// [MAINNET] Switchoard Oracle Queue
bytes32 switchboardQueue =
    0x86807068432f186a147cf0b13a30067d386204ea9d6c8b04743ac2ef010b0752;

// Random Number to receive Switchboard Randomness
uint256 randomNumber;

// Record randomness id
bytes32 randomnessId;

/**
 * Create Request for Switchboard Randomness 
 */
function roll() public {
    // get some randomness id, this can be from anything
    randomnessId = keccak256(abi.encodePacked(msg.sender, block.timestamp));
    switchboard.requestRandomness(
        randomnessId, // randomnessId - unique ID identifying the randomness
        address(this), // authority - this contract will own it
        switchboardQueue, // queueId - pick the queue based on your network (mainnet networks use the switchboardQueue)
        30 // min settlement delay - the number of seconds until randomness can be settled
    ); 
    
    // ... do something with randomness request ...
}

So let's break this down:

  • Get the Switchboard interface, switchboard

  • Create randomNumber to receive the random number

  • Get the correct queueId, switchboardDevnetQueue for devnet/testnets and switchboardQueue for mainnets (and Morph Holesky)

  • Create function roll to request Switchboard randomness.

  • Get some randomnessId - this can be generated any way you want. There just can't be duplicates.

  • Call requestRandomness with the id, authority address (which has the authority to re-roll randomness), queueId, and min settlement delay.

  • minSettlementDelay is set to 30 seconds, meaning the randomness can't be resolved by an oracle for 30 seconds from when this tx settles.

  1. Make function for resolving randomness. This is done by passing encoded Switchboard updates (requested off-chain from oracles), and calling updateFeeds, which routes the encoded random number into the user's randomness request.

Let's also add a function for resolving randomness:

/**
 * Resolve a random number through Switchboard
 */
function resolve(bytes[] calldata encoded) public {
    
    // Update randomness - encoded data gets routed to resolve randomness
    switchboard.updateFeeds(encoded);
    
    // Fetch the resolved randomness 
    Structs.RandomnessResult memory randomness = switchboard.getRandomness(randomnessId).result;
    
    // Check that it was settled 
    require(randomness.settledAt != 0, "Randomness failed to Settle");
    
    // Set the random number
    randomNumber = randomness.value;
    
    // ... do something with random number ...
}

Here we're just calling updateFeeds which is routing the encoded updates into the randomness feed update.

Step 2: Resolve Randomness Off-Chain

The next step is to get the encoded randomness resolution from Switchboard. Here's an example using Crossbar and its Typescript SDK.

import {
  CrossbarClient,
} from "@switchboard-xyz/on-demand";

// for initial testing and development, you can use the rate-limited 
// https://crossbar.switchboard.xyz instance of crossbar
const crossbar = new CrossbarClient("https://crossbar.switchboard.xyz");

// fetch simulated results
const { encoded } = await crossbar.resolveEVMRandomness({
  chainId: 1115, // chainId (Core Testnet is 1115)
  randomnessId: "0x...",
});

Once you have the randomness resolved, you can put this into a function call for randomness resolution.

Here's what a call using ethers could look like:

// Target contract address
const exampleAddress = process.env.CONTRACT_ADDRESS as string;

// The Human Readable contract ABI
const abi = ["function resolve(bytes[] calldata updates) public payable"];

// ... Setup ethers provider ...

// The Contract object
const exampleContract = new ethers.Contract(exampleAddress, abi, provider);

// Update feeds
await exampleContract.resolve(encoded);

Last updated