> ## Documentation Index
> Fetch the complete documentation index at: https://seilabs-docs-evm-cookbook.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Pyth Network VRF Integration

> Complete guide to integrating Pyth Network VRF with Sei Network

Pyth Entropy is an on-chain random number generator (RNG) that supplies cryptographically secure, verifiable randomness to blockchain applications. Entropy uses a two-party commit-reveal protocol, which is a well-known way to generate a random number in cryptography. Compared to traditional VRF solutions, Entropy offers lower fees, direct integration with Pyth Network, scalability, and faster response times. Entropy delivers trustless, low-latency, cost-efficient randomness. It does not require registration.

## What you'll be doing in this guide

This tutorial shows you how to:

1. Integrate Pyth Entropy's commit-reveal randomness system into your Sei EVM application
2. Create smart contracts that request and consume verifiable random numbers with the Entropy protocol
3. Implement a complete gaming application with fair, transparent randomness
4. Handle fees, callbacks, and errors for production-ready randomness

By the end of this guide, you will have a working demo that uses Pyth Entropy. It can request cryptographically secure random numbers on the Sei network, with proper verification mechanisms.

## Prerequisites

Before you start this tutorial, make sure that you have:

### Technical requirements

* **Solidity knowledge**: A basic understanding of smart contract development in Solidity
* **JavaScript and Node.js**: For off-chain interaction and frontend integration
* **Development environment**: Remix IDE, Hardhat, Foundry, or a similar Solidity development setup
* **Sei network access**: An RPC endpoint and familiarity with the Sei EVM environment
* **Native tokens**: SEI tokens, which you need to pay Entropy request fees

### Required dependencies

* Pyth Entropy Solidity SDK (`@pythnetwork/entropy-sdk-solidity`)

#### Install

```bash theme={null}
# npm
npm install @pythnetwork/entropy-sdk-solidity

# yarn
yarn add @pythnetwork/entropy-sdk-solidity

# pnpm
pnpm add @pythnetwork/entropy-sdk-solidity
```

### Sei network configuration

Make sure that your development environment is configured for Sei:

* **Mainnet RPC**: `https://evm-rpc.sei-apis.com`
* **Chain ID**: 1329 (Sei Mainnet)
* **Testnet RPC**: `https://evm-rpc-testnet.sei-apis.com`
* **Testnet chain ID**: 1328 (Sei Testnet)

## Pyth Entropy architecture overview

Entropy uses a two-party commit-reveal protocol that has these parts:

1. **Entropy provider**: An off-chain service that commits to a sequence of random numbers with hash chains
2. **User commitment**: Users contribute their own random input to make sure that the result is unpredictable
3. **Commit-reveal protocol**: A two-party system where both parties contribute to the final randomness
4. **On-chain verification**: Smart contracts verify the randomness proofs and execute callbacks
5. **Keeper network**: Decentralized bots that fulfill randomness requests by revealing provider commitments

## Key concepts

Before you implement the integration, make sure that you understand these main aspects of Pyth Entropy:

### Two-phase process

Entropy uses a two-phase approach:

* **Request phase**: Your contract calls `entropy.requestV2()` and receives a `sequenceNumber`
* **Fulfillment phase**: Off-chain keepers call your contract's `entropyCallback()` method to fulfill the request

### Asynchronous nature

Unlike synchronous random number generation, Entropy requests are asynchronous:

* The random number is not available immediately after the request
* Your application must handle the waiting period (typically 1 to 3 blocks)
* Use events and polling to detect when the randomness is fulfilled

### Fee management

Entropy requires payment for each randomness request:

* Before you make a request, always call `getFeeV2()` to get the current fee
* Fees are paid in the native token (SEI) as `msg.value`
* Fees are dynamic and may change based on network conditions

### Callback implementation

Your contract must implement the `entropyCallback` function:

* This method is called automatically when the randomness is fulfilled
* It receives the `sequenceNumber`, `providerAddress`, and `randomNumber`
* Handle all your game logic in this callback

### Sequence number tracking

Each request has a unique `sequenceNumber`:

* Use it to map requests to your application state
* Store game or request data with the sequence number as the key
* Multiple requests can be pending at the same time

### Error handling

Always implement proper error handling:

* Requests can fail or time out
* Network issues may prevent fulfillment
* Have fallback mechanisms for failed requests

### Gas considerations

The callback execution has gas limits:

* Keep callback logic simple to avoid out-of-gas errors
* For complex logic, consider custom gas limits with `requestV2` variants
* Store expensive computations for later execution

## Steps to integrate Pyth Entropy into Sei

### Step 1: Smart contract integration

Create a consumer contract that integrates with Pyth Entropy:

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "@pythnetwork/entropy-sdk-solidity/IEntropyV2.sol";
import "@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol";

contract SeiEntropyDemo is IEntropyConsumer {
    // Entropy configuration
    IEntropyV2 entropy;

    // Game state
    struct DiceGame {
        address player;
        uint256 betAmount;
        uint256 targetNumber;
        bool fulfilled;
        bool won;
        uint256 diceRoll;
        uint256 timestamp;
    }

    mapping(uint64 => DiceGame) public games;
    mapping(address => uint256) public playerBalances;
    uint256 public gameCounter;

    // Events
    event GameRequested(uint64 indexed sequenceNumber, address indexed player, uint256 betAmount, uint256 targetNumber);
    event GameResolved(uint64 indexed sequenceNumber, address indexed player, bool won, uint256 diceRoll);
    event RandomnessRequested(uint64 indexed sequenceNumber);
    event RandomnessFulfilled(uint64 indexed sequenceNumber, bytes32 randomNumber);

    constructor(address _entropy) {
        entropy = IEntropyV2(_entropy);
    }

    // This method is required by the IEntropyConsumer interface
    function getEntropy() internal view override returns (address) {
        return address(entropy);
    }

    /**
     * @notice Start a new dice game with Entropy randomness
     * @param targetNumber The number to roll (1-6) to win
     */
    function playDiceGame(uint256 targetNumber) external payable returns (uint64 sequenceNumber) {
        require(targetNumber >= 1 && targetNumber <= 6, "Target must be 1-6");

        // Get fee for entropy request
        uint128 requestFee = entropy.getFeeV2();
        require(msg.value >= requestFee, "Insufficient fee for randomness");

        // Calculate bet amount (total payment minus entropy fee)
        uint256 betAmount = msg.value - requestFee;
        require(betAmount > 0, "Must send more than just the entropy fee");

        // Store player balance
        playerBalances[msg.sender] += betAmount;

        // Request randomness from Entropy (V2 doesn't require user random number)
        sequenceNumber = entropy.requestV2{value: requestFee}();

        // Store game session
        games[sequenceNumber] = DiceGame({
            player: msg.sender,
            betAmount: betAmount,
            targetNumber: targetNumber,
            fulfilled: false,
            won: false,
            diceRoll: 0,
            timestamp: block.timestamp
        });

        gameCounter++;

        emit GameRequested(sequenceNumber, msg.sender, betAmount, targetNumber);
        emit RandomnessRequested(sequenceNumber);

        return sequenceNumber;
    }

    /**
     * @notice Callback function used by Entropy when randomness is fulfilled
     * @param sequenceNumber The sequence number of the request
     * @param providerAddress The randomness provider address
     * @param randomNumber The generated random number
     */
    function entropyCallback(
        uint64 sequenceNumber,
        address providerAddress,
        bytes32 randomNumber
    ) internal override {
        DiceGame storage game = games[sequenceNumber];
        require(game.player != address(0), "Game not found");
        require(!game.fulfilled, "Game already fulfilled");

        game.fulfilled = true;

        // Convert random number to dice roll (1-6)
        uint256 diceRoll = (uint256(randomNumber) % 6) + 1;
        game.diceRoll = diceRoll;

        // Determine if player won
        bool won = diceRoll == game.targetNumber;
        game.won = won;

        if (won) {
            // Player wins 5x their bet
            uint256 winnings = game.betAmount * 5;
            playerBalances[game.player] += winnings;
        }

        emit RandomnessFulfilled(sequenceNumber, randomNumber);
        emit GameResolved(sequenceNumber, game.player, won, diceRoll);
    }

    /**
     * @notice Get game details by sequence number
     * @param sequenceNumber The Entropy sequence number
     * @return Game session details
     */
    function getGameDetails(uint64 sequenceNumber) external view returns (DiceGame memory) {
        return games[sequenceNumber];
    }

    /**
     * @notice Check if randomness has been fulfilled for a request
     * @param sequenceNumber The Entropy sequence number
     * @return True if randomness has been fulfilled
     */
    function isRequestFulfilled(uint64 sequenceNumber) external view returns (bool) {
        return games[sequenceNumber].fulfilled;
    }

    /**
     * @notice Get player's current balance
     * @param player Player address
     * @return Current balance
     */
    function getPlayerBalance(address player) external view returns (uint256) {
        return playerBalances[player];
    }

    /**
     * @notice Withdraw player balance
     */
    function withdraw() external {
        uint256 balance = playerBalances[msg.sender];
        require(balance > 0, "No balance to withdraw");

        playerBalances[msg.sender] = 0;
        payable(msg.sender).transfer(balance);
    }

    /**
     * @notice Get the current fee for entropy requests
     * @return fee The current fee amount in wei
     */
    function getEntropyFee() external view returns (uint128) {
        return entropy.getFeeV2();
    }

    /**
     * @notice Play multiple dice games in batch
     * @param targetNumbers Array of target numbers
     */
    function playMultipleDiceGames(
        uint256[] calldata targetNumbers
    ) external payable returns (uint64[] memory sequenceNumbers) {
        require(targetNumbers.length > 0 && targetNumbers.length <= 10, "Invalid array length");

        uint128 requestFee = entropy.getFeeV2();
        uint256 totalFee = uint256(requestFee) * targetNumbers.length;
        require(msg.value >= totalFee, "Insufficient fee for batch randomness");

        uint256 betPerGame = (msg.value - totalFee) / targetNumbers.length;
        require(betPerGame > 0, "Insufficient funds for bets");

        sequenceNumbers = new uint64[](targetNumbers.length);

        for (uint i = 0; i < targetNumbers.length; i++) {
            require(targetNumbers[i] >= 1 && targetNumbers[i] <= 6, "Target must be 1-6");

            playerBalances[msg.sender] += betPerGame;

            uint64 sequenceNumber = entropy.requestV2{value: requestFee}();

            games[sequenceNumber] = DiceGame({
                player: msg.sender,
                betAmount: betPerGame,
                targetNumber: targetNumbers[i],
                fulfilled: false,
                won: false,
                diceRoll: 0,
                timestamp: block.timestamp
            });

            sequenceNumbers[i] = sequenceNumber;
            gameCounter++;

            emit GameRequested(sequenceNumber, msg.sender, betPerGame, targetNumbers[i]);
            emit RandomnessRequested(sequenceNumber);
        }

        return sequenceNumbers;
    }

    receive() external payable {}
}
```

Deploy this contract with [Remix](https://remix.ethereum.org/). Use the Entropy contract address for your target network:

| Network | Entropy contract address |
| - | - |
| **Sei Mainnet** | [`0x98046bd286715d3b0bc227dd7a956b83d8978603`](https://docs.pyth.network/entropy/chainlist) |
| **Sei Testnet** | [`0x36825bf3fbdf5a29e2d5148bfe7dcf7b5639e320`](https://docs.pyth.network/entropy/chainlist) |

Entropy V2 uses a default provider system, so you do not need to specify a provider address in the constructor.

### Step 2: JavaScript integration for Entropy management

Create a module that interacts with Entropy and manages randomness requests:

The JavaScript examples below use CommonJS (`require` and `module.exports`). If your project uses `"type": "module"`, rename these files to `.cjs` or convert the snippets to ES Modules.

```javascript theme={null}
const { ethers } = require('ethers');
const dotenv = require('dotenv');

dotenv.config();

// Contract ABI (simplified for key functions)
const ENTROPY_DEMO_ABI = ['function playDiceGame(uint256 targetNumber) external payable returns (uint64)', 'function getGameDetails(uint64 sequenceNumber) external view returns (tuple(address player, uint256 betAmount, uint256 targetNumber, bool fulfilled, bool won, uint256 diceRoll, uint256 timestamp))', 'function isRequestFulfilled(uint64 sequenceNumber) external view returns (bool)', 'function getPlayerBalance(address player) external view returns (uint256)', 'function withdraw() external', 'function getEntropyFee() external view returns (uint128)', 'function gameCounter() external view returns (uint256)', 'event GameRequested(uint64 indexed sequenceNumber, address indexed player, uint256 betAmount, uint256 targetNumber)', 'event GameResolved(uint64 indexed sequenceNumber, address indexed player, bool won, uint256 diceRoll)', 'event RandomnessRequested(uint64 indexed sequenceNumber)', 'event RandomnessFulfilled(uint64 indexed sequenceNumber, bytes32 randomNumber)'];

/**
 * Play a dice game using Pyth Entropy randomness
 * @param {string} contractAddress Deployed Entropy demo contract address
 * @param {string} privateKey Player's private key
 * @param {number} targetNumber Target dice number (1-6)
 * @param {string} betAmount Bet amount in SEI
 * @param {string} rpcUrl RPC endpoint URL
 */
async function playEntropyDiceGame(contractAddress, privateKey, targetNumber, betAmount, rpcUrl = 'https://evm-rpc.sei-apis.com') {
  try {
    console.log('🎲 Starting Pyth Entropy Dice Game...');

    // Setup provider and wallet
    const provider = new ethers.JsonRpcProvider(rpcUrl);
    const wallet = new ethers.Wallet(privateKey, provider);

    // Create contract instance
    const contract = new ethers.Contract(contractAddress, ENTROPY_DEMO_ABI, wallet);

    const balance = await provider.getBalance(wallet.address);
    console.log(`💼 Player Wallet: ${wallet.address} | Balance: ${ethers.formatEther(balance)} SEI`);

    console.log(`🎯 Player: ${wallet.address}`);
    console.log(`💰 Bet Amount: ${betAmount} SEI`);
    console.log(`🎲 Target Number: ${targetNumber}`);

    // Get current entropy fee
    const entropyFee = await contract.getEntropyFee();
    console.log(`⚡ Entropy Fee: ${ethers.formatEther(entropyFee)} SEI`);

    // Check current balance
    const currentBalance = await contract.getPlayerBalance(wallet.address);
    console.log(`💳 Current Contract Balance: ${ethers.formatEther(currentBalance)} SEI`);

    // Calculate total payment (bet + entropy fee)
    const betInWei = ethers.parseEther(betAmount);
    const totalPayment = betInWei + entropyFee;

    console.log('\n🔄 Submitting game transaction...');

    const tx = await contract.playDiceGame(targetNumber, {
      value: totalPayment,
      gasLimit: 300000
    });

    console.log(`📝 Transaction Hash: ${tx.hash}`);

    // Wait for confirmation and get receipt
    const receipt = await tx.wait();
    console.log(`✅ Transaction confirmed in block: ${receipt.blockNumber}`);

    // Extract sequence number from events
    const gameRequestedEvent = receipt.logs.find((log) => {
      try {
        const decoded = contract.interface.parseLog({
          topics: log.topics,
          data: log.data
        });
        return decoded.name === 'GameRequested';
      } catch {
        return false;
      }
    });

    if (!gameRequestedEvent) {
      throw new Error('GameRequested event not found');
    }

    const decodedEvent = contract.interface.parseLog({
      topics: gameRequestedEvent.topics,
      data: gameRequestedEvent.data
    });

    const sequenceNumber = decodedEvent.args[0];
    console.log(`🎟️ Sequence Number: ${sequenceNumber.toString()}`);

    // Wait for Entropy fulfillment
    console.log('\n⏳ Waiting for Entropy fulfillment...');
    await waitForEntropyFulfillment(contract, sequenceNumber);

    // Get final game results
    const gameDetails = await contract.getGameDetails(sequenceNumber);

    console.log('\n🎯 GAME RESULTS:');
    console.log(`🎲 Dice Roll: ${gameDetails.diceRoll}`);
    console.log(`🎯 Target: ${gameDetails.targetNumber}`);
    console.log(`${gameDetails.won ? '🎉 WINNER!' : '💔 Better luck next time!'}`);
    console.log(`💰 Bet Amount: ${ethers.formatEther(gameDetails.betAmount)} SEI`);

    if (gameDetails.won) {
      const winAmount = gameDetails.betAmount * BigInt(5);
      console.log(`💸 Winnings: ${ethers.formatEther(winAmount)} SEI`);
    }

    // Check updated balance
    const newBalance = await contract.getPlayerBalance(wallet.address);
    console.log(`💳 New Balance: ${ethers.formatEther(newBalance)} SEI`);

    return {
      sequenceNumber: sequenceNumber.toString(),
      diceRoll: Number(gameDetails.diceRoll),
      targetNumber: Number(gameDetails.targetNumber),
      won: gameDetails.won,
      txHash: receipt.transactionHash,
      blockNumber: receipt.blockNumber
    };
  } catch (error) {
    console.error('❌ Error playing Entropy dice game:', error.message);
    throw error;
  }
}

/**
 * Wait for Entropy fulfillment with timeout
 * @param {Contract} contract Contract instance
 * @param {BigInt} sequenceNumber Entropy sequence number
 * @param {number} timeoutMs Timeout in milliseconds
 */
async function waitForEntropyFulfillment(contract, sequenceNumber, timeoutMs = 120000) {
  const startTime = Date.now();

  while (Date.now() - startTime < timeoutMs) {
    try {
      const fulfilled = await contract.isRequestFulfilled(sequenceNumber);
      if (fulfilled) {
        console.log('✅ Entropy request fulfilled!');
        return;
      }

      process.stdout.write('.');
      await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait 3 seconds
    } catch (error) {
      console.error('Error checking fulfillment:', error.message);
      await new Promise((resolve) => setTimeout(resolve, 3000));
    }
  }

  throw new Error('Entropy fulfillment timed out');
}

/**
 * Monitor Entropy events in real-time
 * @param {string} contractAddress Contract address
 * @param {string} rpcUrl RPC URL
 */
async function monitorEntropyEvents(contractAddress, rpcUrl = 'https://evm-rpc.sei-apis.com') {
  try {
    console.log('👂 Starting Entropy event monitoring...');

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    const contract = new ethers.Contract(contractAddress, ENTROPY_DEMO_ABI, provider);

    // Listen for game events
    contract.on('GameRequested', (sequenceNumber, player, betAmount, targetNumber) => {
      console.log(`🎮 Game Requested - Sequence: ${sequenceNumber}, Player: ${player}, Target: ${targetNumber}, Bet: ${ethers.formatEther(betAmount)} SEI`);
    });

    contract.on('RandomnessRequested', (sequenceNumber) => {
      console.log(`🔄 Entropy Randomness Requested - Sequence: ${sequenceNumber}`);
    });

    contract.on('RandomnessFulfilled', (sequenceNumber, randomNumber) => {
      console.log(`✅ Entropy Randomness Fulfilled - Sequence: ${sequenceNumber}, Random: ${randomNumber}`);
    });

    contract.on('GameResolved', (sequenceNumber, player, won, diceRoll) => {
      console.log(`🎯 Game Resolved - Sequence: ${sequenceNumber}, Player: ${player}, Won: ${won}, Roll: ${diceRoll}`);
    });

    console.log('✅ Event monitoring active. Press Ctrl+C to stop.');
  } catch (error) {
    console.error('Error monitoring events:', error.message);
    throw error;
  }
}

/**
 * Simple Pyth Entropy demonstration
 */
async function demonstratePythEntropyIntegration() {
  const contractAddress = process.env.CONTRACT_ADDRESS;
  const privateKey = process.env.PRIVATE_KEY;
  const rpcUrl = 'https://evm-rpc.sei-apis.com';

  console.log('🚀 Starting Sei Pyth Entropy Integration Demo...');
  console.log(`📍 Contract Address: ${contractAddress}`);
  console.log(`🌐 RPC URL: ${rpcUrl}\n`);

  try {
    // Play a single dice game
    const result = await playEntropyDiceGame(contractAddress, privateKey, 3, '0.1', rpcUrl);

    console.log('\n🎉 Pyth Entropy Demo completed successfully!');
    console.log(`📋 Game Summary:`);
    console.log(`   - Sequence: ${result.sequenceNumber}`);
    console.log(`   - Target: ${result.targetNumber}, Roll: ${result.diceRoll}`);
    console.log(`   - Result: ${result.won ? 'WON' : 'LOST'}`);
    console.log(`   - Transaction: ${result.txHash}`);
    console.log(`   - Block: ${result.blockNumber}`);
  } catch (error) {
    console.error('❌ Demo failed:', error.message);
  }
}

// Export functions for use in other modules
module.exports = {
  playEntropyDiceGame,
  waitForEntropyFulfillment,
  monitorEntropyEvents,
  demonstratePythEntropyIntegration
};

// Run demo if this file is executed directly
// Usage: node SeiPythEntropyIntegration.js
if (require.main === module) {
  demonstratePythEntropyIntegration();
}
```

### Step 3: Complete integration example

This simple example combines all the parts:

First, create a `.env` file in your project root (never commit this file):

```bash theme={null}
# .env - NEVER commit this file to version control!
PRIVATE_KEY=your_private_key_here
CONTRACT_ADDRESS=your_deployed_entropy_contract_address
```

Then create the demo script:

```javascript theme={null}
// demo.js - Complete Pyth Entropy demonstration
const { demonstratePythEntropyIntegration, monitorEntropyEvents } = require('./SeiPythEntropyIntegration.js');
const dotenv = require('dotenv');

dotenv.config();

// Validate required environment variables
if (!process.env.PRIVATE_KEY || !process.env.CONTRACT_ADDRESS) {
  console.error('❌ Missing required environment variables!');
  console.error('Please create a .env file with PRIVATE_KEY and CONTRACT_ADDRESS');
  process.exit(1);
}

// Option 1: Run the complete demo
demonstratePythEntropyIntegration()
  .then(() => {
    console.log('🎯 Pyth Entropy integration demo completed successfully!');
  })
  .catch((error) => {
    console.error('❌ Demo failed:', error);
  });

// Option 2: Monitor events in real-time
// monitorEntropyEvents(process.env.CONTRACT_ADDRESS);
```

### Expected output

To run the complete demo, execute the `demo.js` script:

```bash theme={null}
node demo.js
```

When you run the Pyth Entropy integration, you should see output similar to this:

```
🚀 Starting Sei Pyth Entropy Integration Demo...
📍 Contract Address: 0xb879CEabC035CF1ACb95A2A9D679Be633BAa6BD0
🌐 RPC URL: https://evm-rpc.sei-apis.com

🎲 Starting Pyth Entropy Dice Game...
💼 Player Wallet: 0x232d055936450052c3df9B8064b2B56B01c49DEc | Balance: 0.931653993763751675 SEI
🎯 Player: 0x232d055936450052c3df9B8064b2B56B01c49DEc
💰 Bet Amount: 0.1 SEI
🎲 Target Number: 3
⚡ Entropy Fee: 0.050000000000000001 SEI
💳 Current Contract Balance: 1.532691867344799999 SEI

🔄 Submitting game transaction...
📝 Transaction Hash: 0x248d1b2b9fd5df95bc0ac6e67179e7e1c50e0a557c6acb9be790f7e2dacecab4
✅ Transaction confirmed in block: 184783333
🎟️ Sequence Number: 7547

⏳ Waiting for Entropy fulfillment...
.✅ Entropy request fulfilled!

🎯 GAME RESULTS:
🎲 Dice Roll: 4
🎯 Target: 3
💔 Better luck next time!
💰 Bet Amount: 0.1 SEI
💳 New Balance: 1.632691867344799999 SEI

🎉 Pyth Entropy Demo completed successfully!
📋 Game Summary:
   - Sequence: 7547
   - Target: 3, Roll: 4
   - Result: LOST
   - Transaction: 0x248d1b2b9fd5df95bc0ac6e67179e7e1c50e0a557c6acb9be790f7e2dacecab4
   - Block: 184783333
```

### Data structure details

Pyth Entropy V2 responses include these fields:

* **sequenceNumber**: The unique identifier of the randomness request (uint64)
* **randomNumber**: The cryptographically secure random bytes32 value
* **providerAddress**: The address of the Entropy provider that fulfilled the request
* **blockNumber**: The block number when the request was fulfilled

### Fee structure

* **Dynamic fees**: Always use the on-chain method `entropy.getFeeV2()` to get the current fee
* **Native token payment**: Fees are paid in the native blockchain token (SEI)
* **Per-request basis**: Each randomness request has its own fee
* **No user commitment required**: Entropy V2 does not need user random numbers. This makes the process simpler.

## Best practices

1. **Fee management**: Before you submit a request, always check the current fee with `getFeeV2()`
2. **Callback gas limits**: For complex callback logic, set appropriate gas limits with the custom gas limit features of Entropy V2
3. **Error handling**: Implement proper timeout and error handling for unfulfilled requests
4. **Sequential processing**: Handle multiple requests appropriately, because they may be fulfilled out of order
5. **Storage optimization**: The contract does not store fulfilled randomness. If you need it for multiple uses, save it.

## Resources

* [Pyth Entropy documentation](https://docs.pyth.network/entropy)
* [Entropy contract addresses](https://docs.pyth.network/entropy/chainlist)
* [Example applications](https://github.com/pyth-network/pyth-examples/tree/main/entropy)
* [Entropy Explorer](https://entropy-explorer.pyth.network/)
* [Protocol design](https://docs.pyth.network/entropy/protocol-design)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.