Entropy
in EVM contracts

How to Generate Random Numbers in EVM Contracts Using Pyth Entropy

This guide explains how to integrate Pyth Entropy into EVM Contracts to generate on-chain random numbers. The intended audience for this guide is developers of any application that needs on-chain randomness, such as NFT mints or games.

Install the SDK

Pyth Entropy has a Solidity SDK (opens in a new tab) that lets your contract interact with the Entropy contract. Install the SDK using your package manager:

npm install @pythnetwork/entropy-sdk-solidity

Setup

The Solidity SDK exports two interfaces:

  • IEntropyConsumer (opens in a new tab) - The interface that your contract should implement. It makes sure that your contract is compliant with the Entropy contract.
  • IEntropy (opens in a new tab) - The interface to interact with the Entropy contract. You will need the address of an Entropy contract on your blockchain. Consult the current Entropy contract addresses to find the address on your chain. Once you have a contract address, instantiate an IEntropy contract in your solidity contract:
import { IEntropyConsumer } from "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
import { IEntropy } from "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
 
// @param entropyAddress The address of the entropy contract.
contract YourContract is IEntropyConsumer {
  IEntropy public entropy;
 
  constructor(address entropyAddress) {
    entropy = IEntropy(entropyAddress);
  }
}
 

Entropy also requires selecting a randomness provider. The randomness provider is a third-party who participates in the generation process. Each provider is identified by an address and hosts a keeper service for fullfilling requests.

The simplest way to choose a provider is to use the default provider. The default provider for each contract and their corresponding URI is also listed in the Entropy contract addresses.

You can also get the default provider's address by calling the getDefaultProvider (opens in a new tab) method:

address provider = entropy.getDefaultProvider();

Usage

To generate a random number, follow these steps.

1. Generate a random number

Generate a 32-byte random number on the client side.

const userRandomNumber = web3.utils.randomHex(32);

2. Request a number from Entropy

Invoke the requestWithCallback (opens in a new tab) method of the IEntropy contract. The requestWithCallback method requires paying a fee in native gas tokens which is configured per-provider.

The fees differs for every chain and can be found at the Current Fees page.
You can use the onchain method getFee (opens in a new tab) to calculate the fee for the default provider and send it as the value of the requestWithCallback call:

function requestRandomNumber(bytes32 userRandomNumber) external payable {
  uint256 fee = entropy.getFee(entropyProvider);
 
  uint64 sequenceNumber = entropy.requestWithCallback{ value: fee }(
    entropyProvider,
    userRandomNumber
  );
}
 

This method returns a sequence number and emits a RequestedWithCallback (opens in a new tab) event. You can store this sequence number to identify the request in next step.

3. Implement callback for Entropy

pragma solidity ^0.8.0;
 
import { IEntropyConsumer } from "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";
import { IEntropy } from "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
 
contract YourContract is IEntropyConsumer {
  IEntropy entropy;
 
  // @param entropyAddress The address of the entropy contract.
  constructor(address entropyAddress) {
    entropy = IEntropy(entropyAddress);
  }
 
  // @param userRandomNumber The random number generated by the user.
  function requestRandomNumber(bytes32 userRandomNumber) external payable {
    // Get the default provider and the fee for the request
    address entropyProvider = entropy.getDefaultProvider();
    uint256 fee = entropy.getFee(entropyProvider);
 
    // Request the random number with the callback
    uint64 sequenceNumber = entropy.requestWithCallback{ value: fee }(
      entropyProvider,
      userRandomNumber
    );
    // Store the sequence number to identify the callback request
  }
 
  // @param sequenceNumber The sequence number of the request.
  // @param provider The address of the provider that generated the random number. If your app uses multiple providers, you can use this argument to distinguish which one is calling the app back.
  // @param randomNumber The generated random number.
  // This method is called by the entropy contract when a random number is generated.
  function entropyCallback(
    uint64 sequenceNumber,
    address provider,
    bytes32 randomNumber
  ) internal override {
    // Implement your callback logic here.
  }
 
  // This method is required by the IEntropyConsumer interface.
  // It returns the address of the entropy contract which will call the callback.
  function getEntropy() internal view override returns (address) {
    return address(entropy);
  }
}
 

When the final random number is ready to use, the entropyCallback function will be called by the Entropy contract. This will happen in a separate transaction submitted by the requested provider.

The entropyCallback function should be implemented in the same contract that is requesting the random number.

Additional Resources

You may find these additional resources helpful while integrating Pyth Entropy into your EVM contract.

Debug Callback Failures

Check how to Debug Callback Failures if you are having trouble getting the callback to run.

Pyth Entropy Contract Addresses

Consult the Entropy contract addresses to find the Entropy contract address on your chain.

Current Fees

Check the Current Fees to find the current fee for each provider on your chain.

Best Practices

Check out the Best Practices guide for tips to limit gas usage, or generate multiple random numbers in a single transaction.

Last updated on