Skip to content
On this page
Guides → QRNG
SearchHighlight.vue
FLEX_START_TAG

Using QRNG - Remix Example

This project is a simple and quick introduction to API3's QRNG service. Simply follow the steps to see how a smart contract can access an on-chain quantum random number. You will use the browser-based Remix IDE➚ and MetaMask➚. Some basic knowledge of these two tools is assumed.

Currently, QRNG has three providers, two of which provide quantum random numbers. This guide will use the Nodary provider➚, available only on testnets, which returns a pseudorandom number.

To begin, you need to deploy and sponsor the RemixQrngExample with a matching sponsor wallet. The RemixQrngExample will be the primary contract that retrieves the random number.

The RemixQrngExample submits a request for a random number to AirnodeRrpV0. Airnode gathers the request from the AirnodeRrpV0 protocol contract, retrieves the random number off-chain, and sends it back to AirnodeRrpV0. Once received, it performs a callback to the requester with the random number.

You can read more about how API3 QRNG Airnode uses the Request-Response Protocol here.

1. Coding the RemixQrngExample

Head on to Remix online IDE➚ using a browser that you have added Metamask support to. Not all browsers support MetaMask➚. It should load up the RemixQrngExample contract.

Open in Remix➚

Add Contract

The RemixQrngExample will have five main functions: setRequestParameters(), makeRequestUint256(), fulfillUint256(), makeRequestUint256Array(), and fulfillUint256Array().

  • The setRequestParameters() takes in airnode, endpointIdUint256, _endpointIdUint256Array, sponsorWallet and sets these parameters on-chain.
solidity
function setRequestParameters(
        address _airnode,
        bytes32 _endpointIdUint256,
        bytes32 _endpointIdUint256Array,
        address _sponsorWallet
    ) external {
        airnode = _airnode;
        endpointIdUint256 = _endpointIdUint256;
        endpointIdUint256Array = _endpointIdUint256Array;
        sponsorWallet = _sponsorWallet;
    }
  • The makeRequestUint256() function calls the airnodeRrp.makeFullRequest() function of the AirnodeRrpV0.sol protocol contract which adds the request to its storage and emits a requestId.
solidity
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);
    }
  • The targeted off-chain QRNG Airnode gathers the request and performs a callback to the RemixQrngExample with the random number.
solidity
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);
    }

Similarly, makeRequestUint256Array() takes in _endpointIdUint256Array and can be used to request an array of random numbers.

solidity
function makeRequestUint256Array(uint256 size) external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointIdUint256Array,
            address(this),
            sponsorWallet,
            address(this),
            this.fulfillUint256Array.selector,
            // Using Airnode ABI to encode the parameters
            abi.encode(bytes32("1u"), bytes32("size"), size)
        );
        expectingRequestWithIdToBeFulfilled[requestId] = true;
        emit RequestedUint256Array(requestId, size);
    }

The fulfillUint256Array() will be the callback if an array of random numbers is requested.

solidity
function fulfillUint256Array(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
    {
        require(
            expectingRequestWithIdToBeFulfilled[requestId],
            "Request ID not known"
        );
        expectingRequestWithIdToBeFulfilled[requestId] = false;
        uint256[] memory qrngUint256Array = abi.decode(data, (uint256[]));
        // Do what you want with `qrngUint256Array` here...
        emit ReceivedUint256Array(requestId, qrngUint256Array);
    }

2. Compiling the Contract

Be sure the RemixQrngExample.sol contract is selected in the FILE EXPLORER tab. Switch to the SOLIDITY COMPILER tab. Select the 0.8.9 version of Solidity from the COMPILER pick list. Select the Compile RemixQrngExample.sol button to compile the RemixQrngExample.sol contract.

3. Deploying the Contract

Deploy to a testnet only.

Do not deploy the RemixQrngExample.sol contract to a production network. It lacks adequate security features!

This guide will use the Nodary provider➚ which has the same usage as the production quantum random number generator providers but returns a pseudorandom number.

  • Switch to the DEPLOY & RUN TRANSACTIONS tab. Use MetaMask and switch to the desired account and testnet for your deployment.

  • Select the ENVIRONMENT pick list and switch to Injected Web3. Check that the testnet and account you selected in MetaMask are displayed in Remix as shown below.

  • Be sure QrngReqester - contracts/QrngReqester.sol is selected in the CONTRACT pick list.

  • Add the Airnode _airnodeRrp address parameter value for the constructor into the field next to the Deploy button. See the list of addresses for the testnet you are using.

  • Click on Deploy and approve the transaction with MetaMask.

4. Setting the Parameters

Before making a request, parameters must be set. They determine which Airnode endpoint will be called and define the wallet used to pay the gas costs for the response.

Under Deployed Contracts expand and expose the functions and variables of the contract. Note the address of the contract that is displayed with its name. This is the requester's contract address which will be needed later. Next, expand the setRequestParameters function. Add the following to the corresponding fields for the function.

  • _airnode: The airnode address of the desired QRNG service provider. Use nodary (0x6238772544f029ecaBfDED4300f13A3c4FE84E1D).

  • _endpointIdUint256: The nodary Airnode endpoint ID (0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78) which will return a single random number.

  • _endpointIdUint256Array: The nodary Airnode endpoint ID (0x27cc2713e7f968e4e86ed274a051a5c8aaee9cca66946f23af6f29ecea9704c3) which will return an array of random numbers.

  • _sponsorWallet: A wallet derived from the Airnode address and the Airnode xpub used by nodary, and the smart contract address for RemixQrngExample.sol. The wallet is used to pay gas costs to acquire a random number. A sponsor wallet must be derived using the command derive-sponsor-wallet-address from the Admin CLI. Use the value of the sponsor wallet address that the command outputs.

    sh
    npx @api3/airnode-admin derive-sponsor-wallet-address \
      --airnode-address 0x6238772544f029ecaBfDED4300f13A3c4FE84E1D \
      --airnode-xpub xpub6CuDdF9zdWTRuGybJPuZUGnU4suZowMmgu15bjFZT2o6PUtk4Lo78KGJUGBobz3pPKRaN9sLxzj21CMe6StP3zUsd8tWEJPgZBesYBMY7Wo \
      --sponsor-address <use-the-address-of: RemixQrngExample.sol>
    
      # --airnode-address: Airnode address (nodary provider)
      # --airnode-xpub:    Airnode xpub (nodary provider)
      # --sponsor-address: Use the smart contract address for
      #                    RemixQrngExample.sol as displayed in the Remix IDE.
    
      # The command outputs.
      Sponsor wallet address: 0x6394...5906757
      # Use this address as the value for _sponsorWallet.

    Be sure to fund the public address of the sponsor wallet that the command outputs with enough testnet currency. The funds are used to pay gas costs for the Airnode's response. You can use the table below for the amount of fund as reference.

    Funding table reference
    TestnetAmountUnitChain Id
    Ethereum-Goerli0.1ETH5
    Ethereum-Sepolia0.05SEP11155111
    RSK testnet0.001tRBTC31
    POA Network Sokol testnet0.05POA77
    BNB Chain testnet0.005tBNB97
    Optimism testnet0.05ETH420
    Moonbase Alpha testnet0.1DEV1287
    Fantom testnet0.5FTM4002
    Avalanche Fuji testnet0.3AVAX43113
    Polygon Mumbai testnet0.05MATIC80001
    Milkomeda C1 testnet0.5mTAda200101
    Arbitrum testnet0.01AGOR421613

Select the Transact button in Remix to send the parameters to the smart contract. Approve the transaction with MetaMask. After the transaction completes you can see each parameter's value by clicking the buttons with a parameter name. These parameters will be used each time the smart contract requests a random number.

Designated Sponsor Wallets

Sponsors should not fund a sponsorWallet with more than they can trust the Airnode with, as the Airnode controls the private key to the sponsorWallet. The deployer of such Airnode undertakes no custody obligations, and the risk of loss or misuse of any excess funds sent to the sponsorWallet remains with the sponsor.

5. Make a Request

Be sure you have funded the sponsor wallet created in the last step. Its funds will be used to pay gas costs when Airnode returns a random number to the callback function fulfillUint256().

Each request made will use the parameters set in the last step. You can change the parameters at any time and subsequent requests will use the newer parameter set.

To make a request select the makeRequest button in Remix. Approve the transaction with MetaMask.

As soon as the transaction completes in MetaMask, select the lastRequest button in Remix. You will see the requestId and a randomNumber which equals 0. This is because the random number has yet to be returned to the callback function. Copy and paste the requestId into the field for waitingFulfillment and select the button. You will see the value is true, meaning the callback has not been made.

6. View the Response

The request is gathered by the off-chain Airnode which in turn calls the API provider. Once the API provider returns data, Airnode will callback to the RemixQrngExample.sol contract function fulfillUint256(bytes32 requestId, bytes calldata data).

Select the the lastRequest button in Remix again. If the callback has been successfully completed the randomNumber will be present. The value of waitingFulfillment will be false.

FLEX_END_TAG

Released under the MIT License.