Random number generation (RNG) has always been one of the biggest problems when working with smart contracts. A deterministic virtual machine is incapable of generating ‘true’ randomness. Due to this, RNG needs to be provided as an oracle service. To fulfill the need for randomness in smart contracts, decentralized pseudorandom RNG has been a common way. One of the most used methods is Chainlink’s VRF or verifiable random function, which provides cryptographically provable random numbers on-chain. It generates a random number off-chain with cryptographic proof that’s used to verify the result. However, this configuration suffers from the same issues as any other third-party oracle network. Setting up an oracle node that can provide PRNG exposes potential attack vectors like , but also lacks source transparency and decentralization. For example, one needs to trust the governing entity to select the network participants, which means decentralized PRNG is only as secure and decentralized as the governing entity. Sybil attacks Quantum Random Number Generation QRNG generates randomness via quantum phenomena. It uses a ‘true’ source of entropy using unique properties of quantum physics to generate true randomness. There are different methods of implementing QRNG with varying levels of practicality, yet the common point is that the resulting numbers will be truly random because the outcome of a quantum event is theoretically uncertain with well-defined characteristics. Therefore, QRNG is the gold standard for random number generation. Australian National University’s QRNG Airnode As we already discussed, providing RNG through a third-party oracle network opens space for attack vectors. But first-party oracles ( ) that are directly operated by the Providers optimally counter the Sybil attack risk. Airnodes QRNG API is a public utility offered through the Australian National University (ANU). It is powered by an Airnode hosted by ANU Quantum Random Numbers, meaning that it is a first-party service. ’s Quantum Optics Division is one of the worlds leading research institutions in the field. The division also operates a REST API, , to serve QRNG in Web2. API3 QRNG Australian National University Quantum Random Numbers API Read more about how ANU Generates random numbers in real time by measuring the quantum fluctuations of the vacuum It is served as a public good and is free of charge (apart from the gas costs), and it provides ‘true’ quantum randomness via an easy-to-use solution when requiring RNG on-chain. How Airnode and API3 QRNG works To begin, we need to deploy and sponsor the with a matching sponsor wallet. The will be the primary contract that retrieves the random number. QrngRequester QrngRequester The submits a request for a random number to . Airnode gathers the request from the protocol contract, retrieves the random number off-chain, and sends it back to . Once received, it performs a callback to the requester with the random number. QrngRequester AirnodeRrpV0 AirnodeRrpV0 AirnodeRrpV0 You can read more about how API3 QRNG uses the request-response protocol . here Coding QrngRequester.sol Getting started Make sure you have the following installed: Node.js yarn/NPM Also, make sure you’ve already cloned and installed the . If you haven’t, clone the Airnode Monorepo with this command: Airnode Monorepo $ git clone https://github.com/api3dao/airnode.git . To install the dependencies, do the following: $ yarn run bootstrap To build all the packages, use this command: $ yarn run build Compiling the Contract To compile the QrngRequester contract, we are going to use . It’s an online IDE that allows the developing, deploying, and administering of smart contracts for EVM-compatible blockchains. Remix IDE //SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol"; contract RemixQrngExample is RrpRequesterV0 { event RequestedUint256(bytes32 indexed requestId); event ReceivedUint256(bytes32 indexed requestId, uint256 response); address public airnode; bytes32 public endpointIdUint256; address public sponsorWallet; mapping(bytes32 => bool) public waitingFulfillment; // These are for Remix demonstration purposes, their use is not practical. struct LatestRequest { bytes32 requestId; uint256 randomNumber; } LatestRequest public latestRequest; constructor(address _airnodeRrp) RrpRequesterV0(_airnodeRrp) {} // Normally, this function should be protected, as in: // require(msg.sender == owner, "Sender not owner"); function setRequestParameters( address _airnode, bytes32 _endpointIdUint256, address _sponsorWallet ) external { airnode = _airnode; endpointIdUint256 = _endpointIdUint256; sponsorWallet = _sponsorWallet; } function makeRequestUint256() external { bytes32 requestId = airnodeRrp.makeFullRequest( airnode, endpointIdUint256, address(this), sponsorWallet, address(this), this.fulfillUint256.selector, "" ); waitingFulfillment[requestId] = true; latestRequest.requestId = requestId; latestRequest.randomNumber = 0; emit RequestedUint256(requestId); } function fulfillUint256(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp { require( waitingFulfillment[requestId], "Request ID not known" ); waitingFulfillment[requestId] = false; uint256 qrngUint256 = abi.decode(data, (uint256)); // Do what you want with `qrngUint256` here... latestRequest.randomNumber = qrngUint256; emit ReceivedUint256(requestId, qrngUint256); } } The will have three main functions: , , and . QrngRequester setRequestParameters() makeRequestUint256() fulfillUint256() The takes in , , and sets these parameters. setRequestParameters() airnode endpointIdUint256 sponsorWallet The function calls the function of the protocol contract which adds the request to its storage and returns a . makeRequestUint256() airnodeRrp.makeFullRequest() AirnodeRrpV0.sol requestId The targeted off-chain ANU gathers the request and performs a callback to the requester with the random number. Airnode Request Parameters The function expects the following parameters to make a valid request. makeRequestUint256() (address) and specify the endpoint. Get these from . airnode endpointIdUint256 here specifies which wallet will be used to fulfill the request. sponsorWallet Response Parameters The callback to the contains two parameters: QrngRequester : First acquired when making the request and passed here as a reference to identify the request for which the response is intended. requestId : In case of a successful response, this is the requested data that has been encoded and contains a in addition to other response data. Decode it using the function from the object to get your random number. data timestamp decode() abi Head to Remix IDE, make a contract, and paste it in the code. QrngRequester Now, hit compile on the right side of the dashboard and compile the smart contract. Deploying the Contract We are going to deploy our to Goerli. Make sure you have enough testnet ETH in your wallet to deploy the contract and fund the later. You can get some testnet Goerli . QrngRequester sponsorWallet here Head to deploy, run Transactions, and select the “Injected Provider — MetaMask” option under Environment. Connect your MetaMask. Make sure you’re on Goerli. The is the main . The RRP contracts have already been deployed on-chain. You can check for your specific chain . _rrpAddress airnodeRrpAddress here Once the is populated, click on “Deploy.” Confirm the transaction on your MetaMask and wait for it to deploy the Requester contract. _rrpAddress Calling the Contract When your gets deployed, head to Deploy, run transactions, and click on the dropdown for your Requester under Deployed Contracts. QrngRequester Now select the dropdown to set all the parameters. setRequestParameters Add the following to the corresponding fields for the function. : The airnode address of the desired QRNG service provider. See its value from the . _airnode ANU Airnode : The Airnode endpoint ID will return a single random number. See its value from the . _endpointIdUint256 ANU Airnode : A wallet derived from the requester contract address, the Airnode address, and the Airnode xpub. The wallet is used to pay gas costs to acquire a random number. A sponsor wallet must be derived using the command from the Admin CLI. Use the value of the sponsor wallet address that the command outputs. _sponsorWallet derive-sponsor-wallet-address After you’ve set up the Airnode CLI, installed and built all the dependencies and packages, run the following command to derive your : _sponsorWallet Linux npx @api3/airnode-admin derive-sponsor-wallet-address \ --airnode-xpub xpub6CUGRUo... \ --airnode-address 0xe1...dF05s \ --sponsor-address 0xF4...dDyu9 Windows npx @api3/airnode-admin derive-sponsor-wallet-address ^ --airnode-xpub xpub6CUGRUo... ^ --airnode-address 0xe1...dF05s ^ --sponsor-address 0xF4...dDyu9 ANU’s and can be found . airnode-address airnode-xpub here Fund the with some test ETH. Click on transact button and confirm the transaction to set the parameters. sponsorWallet To make the request, click on the button to call the function and make a full request. makeRequestUint256 Now you can head over to and check your for any new transactions. https://goerli.etherscan.io/ sponsorWallet You might need to wait for a while as the Airnode calls the function in that will in turn call back the requester contract at using function to deliver (the random number). fulfill() AirnodeRrpV0.sol fulfillAddress fulfillFunctionId data Here, we can see the latest transaction. Fulfill Now go back to Remix and click on button to check the response. latestRequest If the callback has been successfully completed, the will be present. The value of will be . randomNumber waitingFulfillment false If you want to learn more about it, check out the . QRNG Example Project Read more about . API3 QRNG Also published here.