# Welcome Source: https://docs.proofofplay.com/introduction Introduction to Proof of Play Onchain Services Proof of Play Online Services Docs Proof of Play Onchain Services (Proof of Play OS) is a platform for building performance onchain applications and games. We provide a diverse set of services to support the development of your project. Many of our services are independent of each other and can be used on their own. Reach out and we will create an account for you to get started Join our Discord to get help from our team and community ## Explore by Service View the documentation for each of our services. If public documentation is not ready yet for a service, reach out and we can potentially provide early access depending on your use case. Fast, secure, and scalable onchain random number generation. Automatically mirror ownership data of your NFTs to any chain. {/* */} Onchain Entity-Component-System (ECS) database and indexer for fully onchain application development. # Marketplace API Source: https://docs.proofofplay.com/services/marketplace/about Support peer-to-peer trading within a game or app. Works across both onchain and offchain inventory systems. How does the Proof of Play Marketplace work? Overview: * Our APIs allow app developers to build an in-game marketplace and take a fee. * Sellers can list items for sale from their inventory priced in USD. * Buyers can purchase item listings via credit card or crypto. * Purchased items are placed in the buyer’s inventory upon fulfillment. * Sellers are paid out in USD stablecoins in their wallets upon settlement. * Players can withdraw their balances into fiat across many supported payment methods. Diagram: Marketplace Flow Why should you be interested as an app developer? * With just a simple integration, you can quickly stand up a marketplace that works with your existing databases and inventory systems. * Your app doesn’t need any crypto or have plans to use it in the future. It’s only the marketplace payments that settle on a crypto network. * You can generate additional revenue & increase LTVs. * Most importantly, your users get the very best in-game marketplace UX and can participate in real-money, peer-to-peer trading. Reach out to us if you’d like to be part of the closed alpha at: [partnerships@proofofplay.gg](mailto:partnerships@proofofplay.gg). # NoSQL Database Source: https://docs.proofofplay.com/services/nosql-database Onchain Entity-Component-System (ECS) database and indexer for fully onchain application development. Coming soon, reach out to us if you'd like to be part of the closed alpha. # Token Mirroring Source: https://docs.proofofplay.com/services/token-mirroring Mirror ownership data of your NFTs to any chain. Coming soon, reach out to us if you'd like to be part of the closed alpha. How Mirroring Works Mirror Interoperability # Verified Random Number Generator (vRNG) Source: https://docs.proofofplay.com/services/vrng/about Fast, secure, and scalable onchain random number generation. Welcome to Proof of Play's Verified Random Number Generator (vRNG) documentation. We've been running this tool at scale for [Pirate Nation](https://proofofplay.com/piratenation) on Polygon, [Arbitrum Nova](https://proofofplay.com/arbitrum-nova), [Proof of Play Apex](https://explorer.apex.proofofplay.com/), [Proof of Play Boss](https://explorer.boss.proofofplay.com/) with over *100 million random numbers* served. Our vRNG is also deployed to ApeChain, Abstract, Avalanche, BASE, BNB Chain, and HyperEVM. Because speed matters, we're heavily focused on serving random numbers as fast as possible to reduce latency in applications. On chains like Proof of Play Apex and Boss we see average times from requested to delivered in as fast as 900ms. We also deeply care about reliability and scaleabily because at peak, our vRNG was performing 1.5M transactions per day in Pirate Nation without issue. # Registration During early access, all users of the Verified Random Number Generator system must be manually registered. In order to use it your contract address **must be** approved, otherwise any requests will revert. # Supported Networks | **Network** | **Address** | **Api Url** | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | | **Mainnets** | | | | Abstract Mainnet | [0xBDC8B6eb1840215A22fC1134046f595b7D42C2DE](https://abscan.org/address/0xBDC8B6eb1840215A22fC1134046f595b7D42C2DE#readProxyContract) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | Apechain Mainnet | [0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1](https://apescan.io/address/0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1#readProxyContract) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | Avalance C-Chain | [0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1](https://snowscan.xyz/address/0x9ec728fce50c77e0bef7d34f1ab28a46409b7af1#readContract) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | BASE Mainnet | [0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1](https://basescan.org/address/0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1#readProxyContract) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | Binance Smart Chain Mainnet | [0x9ec728fce50c77e0bef7d34f1ab28a46409b7af1](https://bscscan.com/address/0x9ec728fce50c77e0bef7d34f1ab28a46409b7af1#readProxyContract) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | HyperEVM | [0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1](https://www.hyperscan.com/address/0x9eC728Fce50c77e0BeF7d34F1ab28a46409b7aF1) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | Kaia | [0xf628f7843d94064c5072704a53b9ec455bcc4abb](https://kaiascan.io/address/0xf628f7843d94064c5072704a53b9ec455bcc4abb?) | [https://vrf.proofofplay.com/v1](https://vrf.proofofplay.com/v1) | | **Testnets** | | | | Abstract Testnet | [0xC04ae87CDd258994614f7fFB8506e69B7Fd8CF1D](https://sepolia.abscan.org/address/0xC04ae87CDd258994614f7fFB8506e69B7Fd8CF1D#readProxyContract) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Ape Curtis Testnet | [0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD](https://curtis.apescan.io/address/0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD#readProxyContract) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Avalanche Testnet | [0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD](https://testnet.snowtrace.io/address/0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Base Sepolia | [0x8aFDcAA4573A36061aC087F9Ba872A7C7F482CFC](https://sepolia.basescan.org/address/0x8afdcaa4573a36061ac087f9ba872a7c7f482cfc#readProxyContract) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Binance Smart Chain Testnet | [0xb47A3C1d33b3f1DAC376417A788b812787006c4a](https://testnet.bscscan.com/address/0xb47a3c1d33b3f1dac376417a788b812787006c4a#readProxyContract) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Earnm Testnet | [0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD](https://earnm-sepolia.explorer.alchemy.com/address/0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | HyperEVM Testnet | [0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD](https://testnet.purrsec.com/address/0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Kaia Testnet | [0xd14D984603b0b7Ade91bE52f3Fc4A917Dfa77bcD](https://kairos.kaiascan.io/address/0xd14d984603b0b7ade91be52f3fc4a917dfa77bcd) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Ronin Testnet | [0xd14d984603b0b7ade91be52f3fc4a917dfa77bcd](https://saigon-app.roninchain.com/address/0xd14d984603b0b7ade91be52f3fc4a917dfa77bcd?t=contract) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Soneium Minato Testnet | [0x2f0AbA02098f197aD27eB83137847F564D2Dd2cD](https://soneium-minato.blockscout.com/address/0x2f0AbA02098f197aD27eB83137847F564D2Dd2cD) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | | Sophon Testnet | [0x16f0f662cA708f1d19eE18d3F1fB7c37b000370f](https://explorer.testnet.sophon.xyz/address/0x16f0f662cA708f1d19eE18d3F1fB7c37b000370f) | [https://staging.vrf.proofofplay.com/v1](https://staging.vrf.proofofplay.com/v1) | # Usage ## Requesting a Random Number The following interface provides a method for requesting random numbers. Your contract can call the VRFSystem deployed on each chain. You can optionally provide a traceId, which will be annotated to each event (Useful if you have one transaction that does many steps, users can trace their transactions on chain). This is **not required** and can be left as 0. ```solidity theme={null} // SPDX-License-Identifier: MIT LICENSE pragma solidity ^0.8.26; uint256 constant ID = uint256(keccak256('com.proofofplay.vrfsystem.v1')); interface IVRFSystem { /** * Starts a VRF random number request * * @param traceId Optional Id to use when tracing the request * @return requestId for the random number, will be passed to the callback contract */ function requestRandomNumberWithTraceId(uint256 traceId) external returns (uint256); } ``` ## Random Number Callbacks Every random number requested is delivered as soon as the first available number from drand is available to be delievered. This can take as long as 3 seconds. ```solidity theme={null} // SPDX-License-Identifier: MIT LICENSE pragma solidity ^0.8.26; interface IVRFSystemCallback { /** * Callback for when a Random Number is delivered * * @param requestId Id of the request * @param randomNumber Random number that was generated by the Verified Random Number Generator Tool */ function randomNumberCallback(uint256 requestId, uint256 randomNumber) external; } ``` ### What if I want to have different numbers in the same 3 second window? By default, we deliver the same number to all requests inside the same 3 second window that drand provides. This is great to be able to verify, but if you would like to have users all have different numbers over this time period, we recommend you add a source of entropy. Here's a couple of examples of having unique random numbers per transaction. ```solidity theme={null} // Add the requestId (Most Gas Efficient) uint256 newRandomNumber = requestId + randomNumber; // Hash with requestId uint256 newRandomNumber = uint256(keccak256(abi.encodePacked(requestId, randomNumber) // More expensive, but more normalized, hash based on requestId in last 256 block hashes uint256 newRandomNumber = uint256(keccak256(abi.encodePacked(blockhash(block.number - (requestId % 256)), randomNumber) ``` Note: These are not guaranteed to be normalized, but will retain the randomness properties of the above. We recommend adjusting to your liking to achieve more or less normalized (for instance, adding sequenceId to the randomNumber would be very skewed, whereas using a blockhash would be very normalized). If you would like to have different numbers on the same block, recommend re-hashing the same number multiple times in the same transaction ```solidity theme={null} functionThatUsesNumber(randomNumber); randomNumber = uint256(keccak256(randomNumber)); functionThatUsesNumber(randomNumber); ``` ### What if I want to have different numbers in the same transaction? By default, we will give you only one number per transaction. We encourage developers to use this number to dervive other numbers from this to create new numbers. ```solidity theme={null} //Example 1: Keccak dervive uint256 randomNumber = 12398012938091283113928; uint256 randomNumber2 = keccak256(randomNumber); uint256 randomNumber3 = keccak256(randomNumber2); //Example 2: Split the number and use both sides uint256 randomNumber = 234345234523452345; uint256 randomNumber2 = randomNumber >> 128; // Take upper 128 bits uint256 randomNumber3 = randomNumber & ((1 << 128) - 1); // Take lower 128 bits ``` ## Blockchain Events The contract will emit the following events. ```solidity theme={null} /// @notice Emitted when a random number request is initiated /// @param requestId The unique identifier for the random number request /// @param callbackAddress The address the random number is requested to /// @param traceId The trace ID used to track the request across transactions (0 if no trace ID) event RandomNumberRequested(uint256 indexed requestId, address indexed callbackAddress, uint256 indexed traceId); /// @notice Emitted when a random number is successfully delivered /// @param requestId The unique identifier of the fulfilled request /// @param callbackAddress the adddress was random number is requested to /// @param traceId The trace ID associated with the request /// @param number The round number that was used for the random number /// @param randomNumber The random number that was generated event RandomNumberDelivered(uint256 indexed requestId, address indexed callbackAddress, uint256 indexed traceId, uint256 roundNumber, uint256 randomNumber); ``` You can query these events on RPC level to see if they were delivered or use the block explorer to view a stream of events. ### Verifying the round number / random number with drand If you want to verify the random number, you can check directly with drand for this. We use drand's **quicknet** for this. **For instance, to see the roundNumber 11:** GET [https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971/public/11](https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971/public/11) ```json theme={null} { "round": 11, "randomness": "ebdcbfe855d10c56db22455fa5a18963c1f62d85f859c35c310273449b49d284", "signature": "163d14081e191a3f5d81e2f580eab591ea608402fda4f6e44b5a0bde11e368070e77d07ad3240726ea33e410c84d4b09ea0a4a0291f6c3c485d8630e1c0edf0a" } ``` We can see here the random number in hex is `ebdcbfe855d10c56db22455fa5a18963c1f62d85f859c35c310273449b49d284` ## Manual Retries with EIP712 signatures > 🧪 **This feature is in Preview**. Please contact us on slack if you wish to use this. In a very rare instance, you may see random numbers fail to be delivered. In most cases this will be an issue on the contract side. In these situations, you can choose to deliver this number yourself. First you should request the EIP712 signature from our API servers which you can use to deliver the random nummber directly to the contract on the blockchain. **Request:** [Try the API!](/services/vrng/api) ```javascript theme={null} GET https://vrf.proofofplay.com/v1/vrf/{chainId}/{txHash} ``` **Response:** ```javascript theme={null} { "requestId": Number, "roundNumber": Number, "randomNumber": BigInt, "signature": String // bytes data of signature } ``` With the response you can now call the VRFSystem contract ```solidity theme={null} vrf.deliverSignedRandomNumber(requestId, roundNumber, randomNumber, signature); ``` > ⚠️ **Warning**: You will be racing the normal relay flow. If you get a tx revert with InvalidRequestId, this means that a relay has already delivered this random number. Random numbers can only be delivered once. How Proof of Play VRF Works # Get vRNG signed message Source: https://docs.proofofplay.com/services/vrng/api api-reference/openapi.json get /v1/vrf/{chainId}/{txHash} Generate a signature offchain to call `deliverSignedRandomNumber`. This can be useful for users who want to manually retry a random number. [How it works](/services/vrng/about#manual-retries-with-eip712-signatures)